chore: publish `Oco` separately as `oco_ref` crate so that it can be used elsewhere (#2536)
This commit is contained in:
parent
158b0bd294
commit
0d20f6aca8
|
@ -1,6 +1,9 @@
|
||||||
[workspace]
|
[workspace]
|
||||||
resolver = "2"
|
resolver = "2"
|
||||||
members = [
|
members = [
|
||||||
|
# utilities
|
||||||
|
"oco",
|
||||||
|
|
||||||
# core
|
# core
|
||||||
"leptos",
|
"leptos",
|
||||||
"leptos_dom",
|
"leptos_dom",
|
||||||
|
@ -29,6 +32,7 @@ version = "0.6.11"
|
||||||
rust-version = "1.75"
|
rust-version = "1.75"
|
||||||
|
|
||||||
[workspace.dependencies]
|
[workspace.dependencies]
|
||||||
|
oco_ref = { path = "./oco", version = "0.1.0" }
|
||||||
leptos = { path = "./leptos", version = "0.6.11" }
|
leptos = { path = "./leptos", version = "0.6.11" }
|
||||||
leptos_dom = { path = "./leptos_dom", version = "0.6.11" }
|
leptos_dom = { path = "./leptos_dom", version = "0.6.11" }
|
||||||
leptos_hot_reload = { path = "./leptos_hot_reload", version = "0.6.11" }
|
leptos_hot_reload = { path = "./leptos_hot_reload", version = "0.6.11" }
|
||||||
|
|
|
@ -9,6 +9,7 @@ description = "Reactive system for the Leptos web framework."
|
||||||
rust-version.workspace = true
|
rust-version.workspace = true
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
oco_ref = { workspace = true }
|
||||||
slotmap = { version = "1", features = ["serde"] }
|
slotmap = { version = "1", features = ["serde"] }
|
||||||
serde = { version = "1", features = ["derive"] }
|
serde = { version = "1", features = ["derive"] }
|
||||||
serde-lite = { version = "0.5", optional = true }
|
serde-lite = { version = "0.5", optional = true }
|
||||||
|
|
|
@ -95,7 +95,6 @@ mod hydration;
|
||||||
pub mod macros;
|
pub mod macros;
|
||||||
mod memo;
|
mod memo;
|
||||||
mod node;
|
mod node;
|
||||||
pub mod oco;
|
|
||||||
mod resource;
|
mod resource;
|
||||||
mod runtime;
|
mod runtime;
|
||||||
mod selector;
|
mod selector;
|
||||||
|
@ -120,6 +119,7 @@ pub use hydration::{FragmentData, SharedContext};
|
||||||
pub use memo::*;
|
pub use memo::*;
|
||||||
pub use node::Disposer;
|
pub use node::Disposer;
|
||||||
pub use oco::*;
|
pub use oco::*;
|
||||||
|
pub use oco_ref as oco;
|
||||||
pub use resource::*;
|
pub use resource::*;
|
||||||
use runtime::*;
|
use runtime::*;
|
||||||
pub use runtime::{
|
pub use runtime::{
|
||||||
|
|
|
@ -3,7 +3,7 @@ use crate::{
|
||||||
Oco, ReadSignal, RwSignal, SignalDispose, SignalGet, SignalGetUntracked,
|
Oco, ReadSignal, RwSignal, SignalDispose, SignalGet, SignalGetUntracked,
|
||||||
SignalStream, SignalWith, SignalWithUntracked, StoredValue,
|
SignalStream, SignalWith, SignalWithUntracked, StoredValue,
|
||||||
};
|
};
|
||||||
use std::{fmt::Debug, rc::Rc};
|
use std::{borrow::Cow, fmt::Debug, rc::Rc};
|
||||||
|
|
||||||
/// Helper trait for converting `Fn() -> T` closures into
|
/// Helper trait for converting `Fn() -> T` closures into
|
||||||
/// [`Signal<T>`].
|
/// [`Signal<T>`].
|
||||||
|
@ -1345,12 +1345,33 @@ impl From<Oco<'static, str>> for TextProp {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> From<T> for MaybeProp<TextProp>
|
impl From<String> for MaybeProp<TextProp> {
|
||||||
where
|
fn from(s: String) -> Self {
|
||||||
T: Into<Oco<'static, str>>,
|
Self(Some(MaybeSignal::from(Some(Oco::from(s).into()))))
|
||||||
{
|
}
|
||||||
fn from(s: T) -> Self {
|
}
|
||||||
Self(Some(MaybeSignal::from(Some(s.into().into()))))
|
|
||||||
|
impl From<Rc<str>> for MaybeProp<TextProp> {
|
||||||
|
fn from(s: Rc<str>) -> Self {
|
||||||
|
Self(Some(MaybeSignal::from(Some(Oco::from(s).into()))))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<&'static str> for MaybeProp<TextProp> {
|
||||||
|
fn from(s: &'static str) -> Self {
|
||||||
|
Self(Some(MaybeSignal::from(Some(Oco::from(s).into()))))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Box<str>> for MaybeProp<TextProp> {
|
||||||
|
fn from(s: Box<str>) -> Self {
|
||||||
|
Self(Some(MaybeSignal::from(Some(Oco::from(s).into()))))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Cow<'static, str>> for MaybeProp<TextProp> {
|
||||||
|
fn from(s: Cow<'static, str>) -> Self {
|
||||||
|
Self(Some(MaybeSignal::from(Some(Oco::from(s).into()))))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,16 @@
|
||||||
|
[package]
|
||||||
|
name = "oco_ref"
|
||||||
|
edition = "2021"
|
||||||
|
version = "0.1.1"
|
||||||
|
authors = ["Danik Vitek", "Greg Johnston"]
|
||||||
|
license = "MIT"
|
||||||
|
repository = "https://github.com/leptos-rs/leptos"
|
||||||
|
description = "A smart pointer for storing immutable values with relatively-cheap cloning. (Like a `Cow` meets an `Rc`!)"
|
||||||
|
rust-version.workspace = true
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
serde = "1"
|
||||||
|
thiserror = "1"
|
||||||
|
|
||||||
|
[dev-dependencies]
|
||||||
|
serde_json = "1"
|
|
@ -0,0 +1,31 @@
|
||||||
|
This module contains the `Oco` (Owned Clones Once) smart pointer,
|
||||||
|
which is used to store immutable references to values.
|
||||||
|
This is useful for storing, for example, strings.
|
||||||
|
|
||||||
|
Imagine this as an alternative to [`Cow`] with an additional, reference-counted
|
||||||
|
branch.
|
||||||
|
|
||||||
|
```rust
|
||||||
|
use oco_ref::Oco;
|
||||||
|
use std::rc::Rc;
|
||||||
|
|
||||||
|
let static_str = "foo";
|
||||||
|
let rc_str: Rc<str> = "bar".into();
|
||||||
|
let owned_str: String = "baz".into();
|
||||||
|
|
||||||
|
fn uses_oco(value: impl Into<Oco<'static, str>>) {
|
||||||
|
let mut value = value.into();
|
||||||
|
|
||||||
|
// ensures that the value is either a reference, or reference-counted
|
||||||
|
// O(n) at worst
|
||||||
|
let clone1 = value.clone_inplace();
|
||||||
|
|
||||||
|
// these subsequent clones are O(1)
|
||||||
|
let clone2 = value.clone();
|
||||||
|
let clone3 = value.clone();
|
||||||
|
}
|
||||||
|
|
||||||
|
uses_oco(static_str);
|
||||||
|
uses_oco(rc_str);
|
||||||
|
uses_oco(owned_str);
|
||||||
|
```
|
|
@ -1,6 +1,37 @@
|
||||||
//! This module contains the `Oco` (Owned Clones Once) smart pointer,
|
//! This module contains the `Oco` (Owned Clones Once) smart pointer,
|
||||||
//! which is used to store immutable references to values.
|
//! which is used to store immutable references to values.
|
||||||
//! This is useful for storing, for example, strings.
|
//! This is useful for storing, for example, strings.
|
||||||
|
//!
|
||||||
|
//! Imagine this as an alternative to [`Cow`] with an additional, reference-counted
|
||||||
|
//! branch.
|
||||||
|
//!
|
||||||
|
//! ```rust
|
||||||
|
//! use oco_ref::Oco;
|
||||||
|
//! use std::rc::Rc;
|
||||||
|
//!
|
||||||
|
//! let static_str = "foo";
|
||||||
|
//! let rc_str: Rc<str> = "bar".into();
|
||||||
|
//! let owned_str: String = "baz".into();
|
||||||
|
//!
|
||||||
|
//! fn uses_oco(value: impl Into<Oco<'static, str>>) {
|
||||||
|
//! let mut value = value.into();
|
||||||
|
//!
|
||||||
|
//! // ensures that the value is either a reference, or reference-counted
|
||||||
|
//! // O(n) at worst
|
||||||
|
//! let clone1 = value.clone_inplace();
|
||||||
|
//!
|
||||||
|
//! // these subsequent clones are O(1)
|
||||||
|
//! let clone2 = value.clone();
|
||||||
|
//! let clone3 = value.clone();
|
||||||
|
//! }
|
||||||
|
//!
|
||||||
|
//! uses_oco(static_str);
|
||||||
|
//! uses_oco(rc_str);
|
||||||
|
//! uses_oco(owned_str);
|
||||||
|
//! ```
|
||||||
|
|
||||||
|
#![forbid(unsafe_code)]
|
||||||
|
#![deny(missing_docs)]
|
||||||
|
|
||||||
use serde::{de::DeserializeOwned, Deserialize, Serialize};
|
use serde::{de::DeserializeOwned, Deserialize, Serialize};
|
||||||
use std::{
|
use std::{
|
||||||
|
@ -13,16 +44,24 @@ use std::{
|
||||||
rc::Rc,
|
rc::Rc,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// "Owned Clones Once" - a smart pointer that can be either a reference,
|
/// "Owned Clones Once": a smart pointer that can be either a reference,
|
||||||
/// an owned value, or a reference counted pointer. This is useful for
|
/// an owned value, or a reference-counted pointer. This is useful for
|
||||||
/// storing immutable values, such as strings, in a way that is cheap to
|
/// storing immutable values, such as strings, in a way that is cheap to
|
||||||
/// clone and pass around.
|
/// clone and pass around.
|
||||||
///
|
///
|
||||||
/// The `Clone` implementation is amortized `O(1)`. Cloning the [`Oco::Borrowed`]
|
/// The cost of the `Clone` implementation depends on the branch. Cloning the [`Oco::Borrowed`]
|
||||||
/// variant simply copies the references (`O(1)`). Cloning the [`Oco::Counted`]
|
/// variant simply copies the references (`O(1)`). Cloning the [`Oco::Counted`]
|
||||||
/// variant increments a reference count (`O(1)`). Cloning the [`Oco::Owned`]
|
/// variant increments a reference count (`O(1)`). Cloning the [`Oco::Owned`]
|
||||||
/// variant upgrades it to [`Oco::Counted`], which requires an `O(n)` clone of the
|
/// variant requires an `O(n)` clone of the data.
|
||||||
/// data, but all subsequent clones will be `O(1)`.
|
///
|
||||||
|
/// For an amortized `O(1)` clone, you can use [`Oco::clone_inplace()`]. Using this method,
|
||||||
|
/// [`Oco::Borrowed`] and [`Oco::Counted`] are still `O(1)`. [`Oco::Owned`] does a single `O(n)`
|
||||||
|
/// clone, but converts the object to the [`Oco::Counted`] branch, which means future clones will
|
||||||
|
/// be `O(1)`.
|
||||||
|
///
|
||||||
|
/// In general, you'll either want to call `clone_inplace()` once, before sharing the `Oco` with
|
||||||
|
/// other parts of your application (so that all future clones are `O(1)`), or simply use this as
|
||||||
|
/// if it is a [`Cow`] with an additional branch for reference-counted values.
|
||||||
pub enum Oco<'a, T: ?Sized + ToOwned + 'a> {
|
pub enum Oco<'a, T: ?Sized + ToOwned + 'a> {
|
||||||
/// A static reference to a value.
|
/// A static reference to a value.
|
||||||
Borrowed(&'a T),
|
Borrowed(&'a T),
|
||||||
|
@ -46,7 +85,7 @@ impl<'a, T: ?Sized + ToOwned> Oco<'a, T> {
|
||||||
/// # Examples
|
/// # Examples
|
||||||
/// ```
|
/// ```
|
||||||
/// # use std::rc::Rc;
|
/// # use std::rc::Rc;
|
||||||
/// # use leptos_reactive::oco::Oco;
|
/// # use oco_ref::Oco;
|
||||||
/// assert!(Oco::<str>::Borrowed("Hello").is_borrowed());
|
/// assert!(Oco::<str>::Borrowed("Hello").is_borrowed());
|
||||||
/// assert!(!Oco::<str>::Counted(Rc::from("Hello")).is_borrowed());
|
/// assert!(!Oco::<str>::Counted(Rc::from("Hello")).is_borrowed());
|
||||||
/// assert!(!Oco::<str>::Owned("Hello".to_string()).is_borrowed());
|
/// assert!(!Oco::<str>::Owned("Hello".to_string()).is_borrowed());
|
||||||
|
@ -59,7 +98,7 @@ impl<'a, T: ?Sized + ToOwned> Oco<'a, T> {
|
||||||
/// # Examples
|
/// # Examples
|
||||||
/// ```
|
/// ```
|
||||||
/// # use std::rc::Rc;
|
/// # use std::rc::Rc;
|
||||||
/// # use leptos_reactive::oco::Oco;
|
/// # use oco_ref::Oco;
|
||||||
/// assert!(Oco::<str>::Counted(Rc::from("Hello")).is_counted());
|
/// assert!(Oco::<str>::Counted(Rc::from("Hello")).is_counted());
|
||||||
/// assert!(!Oco::<str>::Borrowed("Hello").is_counted());
|
/// assert!(!Oco::<str>::Borrowed("Hello").is_counted());
|
||||||
/// assert!(!Oco::<str>::Owned("Hello".to_string()).is_counted());
|
/// assert!(!Oco::<str>::Owned("Hello".to_string()).is_counted());
|
||||||
|
@ -72,7 +111,7 @@ impl<'a, T: ?Sized + ToOwned> Oco<'a, T> {
|
||||||
/// # Examples
|
/// # Examples
|
||||||
/// ```
|
/// ```
|
||||||
/// # use std::rc::Rc;
|
/// # use std::rc::Rc;
|
||||||
/// # use leptos_reactive::oco::Oco;
|
/// # use oco_ref::Oco;
|
||||||
/// assert!(Oco::<str>::Owned("Hello".to_string()).is_owned());
|
/// assert!(Oco::<str>::Owned("Hello".to_string()).is_owned());
|
||||||
/// assert!(!Oco::<str>::Borrowed("Hello").is_owned());
|
/// assert!(!Oco::<str>::Borrowed("Hello").is_owned());
|
||||||
/// assert!(!Oco::<str>::Counted(Rc::from("Hello")).is_owned());
|
/// assert!(!Oco::<str>::Counted(Rc::from("Hello")).is_owned());
|
||||||
|
@ -130,7 +169,7 @@ impl Oco<'_, str> {
|
||||||
/// Returns a `&str` slice of this [`Oco`].
|
/// Returns a `&str` slice of this [`Oco`].
|
||||||
/// # Examples
|
/// # Examples
|
||||||
/// ```
|
/// ```
|
||||||
/// # use leptos_reactive::oco::Oco;
|
/// # use oco_ref::Oco;
|
||||||
/// let oco = Oco::<str>::Borrowed("Hello");
|
/// let oco = Oco::<str>::Borrowed("Hello");
|
||||||
/// let s: &str = oco.as_str();
|
/// let s: &str = oco.as_str();
|
||||||
/// assert_eq!(s, "Hello");
|
/// assert_eq!(s, "Hello");
|
||||||
|
@ -145,7 +184,7 @@ impl Oco<'_, CStr> {
|
||||||
/// Returns a `&CStr` slice of this [`Oco`].
|
/// Returns a `&CStr` slice of this [`Oco`].
|
||||||
/// # Examples
|
/// # Examples
|
||||||
/// ```
|
/// ```
|
||||||
/// # use leptos_reactive::oco::Oco;
|
/// # use oco_ref::Oco;
|
||||||
/// use std::ffi::CStr;
|
/// use std::ffi::CStr;
|
||||||
///
|
///
|
||||||
/// let oco =
|
/// let oco =
|
||||||
|
@ -163,7 +202,7 @@ impl Oco<'_, OsStr> {
|
||||||
/// Returns a `&OsStr` slice of this [`Oco`].
|
/// Returns a `&OsStr` slice of this [`Oco`].
|
||||||
/// # Examples
|
/// # Examples
|
||||||
/// ```
|
/// ```
|
||||||
/// # use leptos_reactive::oco::Oco;
|
/// # use oco_ref::Oco;
|
||||||
/// use std::ffi::OsStr;
|
/// use std::ffi::OsStr;
|
||||||
///
|
///
|
||||||
/// let oco = Oco::<OsStr>::Borrowed(OsStr::new("Hello"));
|
/// let oco = Oco::<OsStr>::Borrowed(OsStr::new("Hello"));
|
||||||
|
@ -180,7 +219,7 @@ impl Oco<'_, Path> {
|
||||||
/// Returns a `&Path` slice of this [`Oco`].
|
/// Returns a `&Path` slice of this [`Oco`].
|
||||||
/// # Examples
|
/// # Examples
|
||||||
/// ```
|
/// ```
|
||||||
/// # use leptos_reactive::oco::Oco;
|
/// # use oco_ref::Oco;
|
||||||
/// use std::path::Path;
|
/// use std::path::Path;
|
||||||
///
|
///
|
||||||
/// let oco = Oco::<Path>::Borrowed(Path::new("Hello"));
|
/// let oco = Oco::<Path>::Borrowed(Path::new("Hello"));
|
||||||
|
@ -200,7 +239,7 @@ where
|
||||||
/// Returns a `&[T]` slice of this [`Oco`].
|
/// Returns a `&[T]` slice of this [`Oco`].
|
||||||
/// # Examples
|
/// # Examples
|
||||||
/// ```
|
/// ```
|
||||||
/// # use leptos_reactive::oco::Oco;
|
/// # use oco_ref::Oco;
|
||||||
/// let oco = Oco::<[u8]>::Borrowed(b"Hello");
|
/// let oco = Oco::<[u8]>::Borrowed(b"Hello");
|
||||||
/// let s: &[u8] = oco.as_slice();
|
/// let s: &[u8] = oco.as_slice();
|
||||||
/// assert_eq!(s, b"Hello");
|
/// assert_eq!(s, b"Hello");
|
||||||
|
@ -222,7 +261,7 @@ where
|
||||||
/// # Examples
|
/// # Examples
|
||||||
/// [`String`] :
|
/// [`String`] :
|
||||||
/// ```
|
/// ```
|
||||||
/// # use leptos_reactive::oco::Oco;
|
/// # use oco_ref::Oco;
|
||||||
/// let oco = Oco::<str>::Owned("Hello".to_string());
|
/// let oco = Oco::<str>::Owned("Hello".to_string());
|
||||||
/// let oco2 = oco.clone();
|
/// let oco2 = oco.clone();
|
||||||
/// assert_eq!(oco, oco2);
|
/// assert_eq!(oco, oco2);
|
||||||
|
@ -230,7 +269,7 @@ where
|
||||||
/// ```
|
/// ```
|
||||||
/// [`Vec`] :
|
/// [`Vec`] :
|
||||||
/// ```
|
/// ```
|
||||||
/// # use leptos_reactive::oco::Oco;
|
/// # use oco_ref::Oco;
|
||||||
/// let oco = Oco::<[u8]>::Owned(b"Hello".to_vec());
|
/// let oco = Oco::<[u8]>::Owned(b"Hello".to_vec());
|
||||||
/// let oco2 = oco.clone();
|
/// let oco2 = oco.clone();
|
||||||
/// assert_eq!(oco, oco2);
|
/// assert_eq!(oco, oco2);
|
||||||
|
@ -254,7 +293,7 @@ where
|
||||||
/// was previously [`Oco::Owned`].
|
/// was previously [`Oco::Owned`].
|
||||||
/// # Examples
|
/// # Examples
|
||||||
/// ```
|
/// ```
|
||||||
/// # use leptos_reactive::oco::Oco;
|
/// # use oco_ref::Oco;
|
||||||
/// let mut oco1 = Oco::<str>::Owned("Hello".to_string());
|
/// let mut oco1 = Oco::<str>::Owned("Hello".to_string());
|
||||||
/// let oco2 = oco1.clone_inplace();
|
/// let oco2 = oco1.clone_inplace();
|
||||||
/// assert_eq!(oco1, oco2);
|
/// assert_eq!(oco1, oco2);
|
Loading…
Reference in New Issue