implicit_clone/
lib.rs

1#![warn(missing_debug_implementations, missing_docs, unreachable_pub)]
2#![allow(clippy::unnecessary_lazy_evaluations)]
3#![allow(clippy::duplicate_mod)]
4#![doc(test(
5    no_crate_inject,
6    attr(deny(warnings, rust_2018_idioms), allow(dead_code, unused_variables))
7))]
8#![cfg_attr(docsrs, feature(doc_cfg))]
9//! # ImplicitClone
10//!
11//! This library introduces the marker trait [`ImplicitClone`](crate::ImplicitClone) intended for
12//! cheap-to-clone types that should be allowed to be cloned implicitly. It enables host libraries
13//! using this crate to have the syntax of [`Copy`][std::marker::Copy] while actually calling the
14//! [`Clone`][std::clone::Clone] implementation instead (usually when host library does such syntax
15//! in a macro).
16//!
17//! The idea is that you must implement this trait on your cheap-to-clone types, and then the host
18//! library using the trait will allow users to pass values of your types and they will be cloned
19//! automatically.
20//!
21//! Standard types that the [`ImplicitClone`](crate::ImplicitClone) is already implemented for:
22//!
23//! - [`std::rc::Rc`][std::rc::Rc]
24//! - [`std::sync::Arc`][std::sync::Arc]
25//! - Tuples with 1-12 elements, all of which are also [`ImplicitClone`](crate::ImplicitClone)
26//! - [`Option`][std::option::Option], where inner value is [`ImplicitClone`](crate::ImplicitClone)
27//! - Some built-in [`Copy`][std::marker::Copy] types, like `()`, `bool`, `&T`, etc.
28//!
29//! This crate is in the category `rust-patterns` but this is actually a Rust anti-pattern. In Rust
30//! the user should always handle borrowing and ownership by themselves. Nevertheless, this pattern
31//! is sometimes desirable. For example, UI frameworks that rely on propagating properties from
32//! ancestors to multiple children will always need to use `Rc`'d types to cheaply and concisely
33//! update every child component. This is the case in React-like frameworks like
34//! [Yew](https://yew.rs/).
35//!
36//! This crate also provides a few convenient immutable types for handling cheap-to-clone strings,
37//! arrays and maps, you can find them in the modules [`sync`](crate::sync) and
38//! [`unsync`](crate::unsync). Those types implement [`ImplicitClone`](crate::ImplicitClone) and
39//! hold only types that implement [`ImplicitClone`](crate::ImplicitClone) as well. **One big
40//! particularity: iterating on these types yields clones of the items and not references.** This
41//! can be particularly handy when using a React-like framework.
42//!
43//! ## Example
44//!
45//! As an example, here is an implementation of a macro called `html_input! {}` which allows its
46//! user to build an `<input>` HTML node:
47//!
48//! ```
49//! // In the host library source code:
50//!
51//! use implicit_clone::ImplicitClone;
52//! use implicit_clone::unsync::{IArray, IString};
53//!
54//! macro_rules! html_input {
55//!     (<input $(type={$ty:expr})? $(name={$name:expr})? $(value={$value:expr})?>) => {{
56//!         let mut input = Input::new();
57//!         $(input.set_type($ty);)*
58//!         $(input.set_name($name);)*
59//!         $(input.set_value($value);)*
60//!         input
61//!     }}
62//! }
63//!
64//! #[derive(Clone)]
65//! pub struct Input {
66//!     ty: IString,
67//!     name: Option<IString>,
68//!     value: Option<IString>,
69//! }
70//!
71//! impl ImplicitClone for Input {}
72//!
73//! impl Input {
74//!     pub fn new() -> Self {
75//!         Self {
76//!             ty: IString::Static("text"),
77//!             name: None,
78//!             value: None,
79//!         }
80//!     }
81//!
82//!     pub fn set_type(&mut self, ty: impl Into<IString>) {
83//!         self.ty = ty.into();
84//!     }
85//!
86//!     pub fn set_name(&mut self, name: impl Into<IString>) {
87//!         self.name.replace(name.into());
88//!     }
89//!
90//!     pub fn set_value(&mut self, value: impl Into<IString>) {
91//!         self.value.replace(value.into());
92//!     }
93//! }
94//!
95//! impl std::fmt::Display for Input {
96//!     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
97//!         write!(f, "<input type=\"{}\"", self.ty)?;
98//!         if let Some(name) = self.name.as_ref() {
99//!             write!(f, " name=\"{}\"", name)?;
100//!         }
101//!         if let Some(value) = self.value.as_ref() {
102//!             write!(f, " value=\"{}\"", value)?;
103//!         }
104//!         write!(f, ">")
105//!     }
106//! }
107//!
108//! // In the user's source code:
109//!
110//! fn component(age: &IString) -> IArray<Input> {
111//!     // `age` is implicitly cloned to the 2 different inputs
112//!     let input1 = html_input!(<input name={"age"} value={age}>);
113//!     let input2 = html_input!(<input name={"age"} value={age}>);
114//!
115//!     IArray::from(vec![input1, input2])
116//! }
117//!
118//! let age = IString::from(20.to_string());
119//! let output = component(&age);
120//! let output_str = output
121//!     .iter()
122//!     .map(|x| x.to_string())
123//!     .collect::<Vec<_>>()
124//!     .join("");
125//!
126//! assert_eq!(
127//!     output_str,
128//!     r#"<input type="text" name="age" value="20"><input type="text" name="age" value="20">"#,
129//! );
130//! ```
131//!
132//! [std::marker::Copy]: https://doc.rust-lang.org/std/marker/trait.Copy.html
133//! [std::clone::Clone]: https://doc.rust-lang.org/std/clone/trait.Clone.html
134//! [std::rc::Rc]: https://doc.rust-lang.org/std/rc/struct.Rc.html
135//! [std::sync::Arc]: https://doc.rust-lang.org/std/sync/struct.Arc.html
136//! [std::option::Option]: https://doc.rust-lang.org/stable/std/option/enum.Option.html
137
138/// Thread-safe version of immutable types.
139pub mod sync;
140/// Single-threaded version of immutable types.
141pub mod unsync;
142
143#[cfg(feature = "implicit-clone-derive")]
144pub use implicit_clone_derive::*;
145
146/// Marker trait for cheap-to-clone types that should be allowed to be cloned implicitly.
147///
148/// Enables host libraries to have the same syntax as [`Copy`] while calling the [`Clone`]
149/// implementation instead.
150pub trait ImplicitClone: Clone {
151    /// This function is not magic; it is literally defined as
152    ///
153    /// ```ignore
154    /// fn implicit_clone(&self) -> Self {
155    ///     self.clone()
156    /// }
157    /// ```
158    ///
159    /// It is useful when you want to clone but also ensure that the type implements
160    /// [`ImplicitClone`].
161    ///
162    /// Examples:
163    ///
164    /// ```
165    /// use implicit_clone::ImplicitClone;
166    /// let x: u32 = Default::default();
167    /// let clone = ImplicitClone::implicit_clone(&x);
168    /// ```
169    ///
170    /// ```compile_fail
171    /// use implicit_clone::ImplicitClone;
172    /// let x: Vec<u32> = Default::default();
173    /// // does not compile because Vec<_> does not implement ImplicitClone
174    /// let clone = ImplicitClone::implicit_clone(&x);
175    /// ```
176    #[inline]
177    fn implicit_clone(&self) -> Self {
178        self.clone()
179    }
180}
181
182impl<T: ?Sized> ImplicitClone for &T {}
183
184impl<T: ImplicitClone> ImplicitClone for Option<T> {}
185
186macro_rules! impl_implicit_clone {
187    ($($ty:ty),+ $(,)?) => {
188        $(impl ImplicitClone for $ty {})*
189    };
190}
191
192#[rustfmt::skip]
193impl_implicit_clone!(
194    u8, u16, u32, u64, u128,
195    i8, i16, i32, i64, i128,
196    f32, f64,
197    bool,
198    usize, isize,
199    char,
200    (),
201);
202
203impl<const N: usize, T: ImplicitClone> ImplicitClone for [T; N] {}
204
205macro_rules! impl_implicit_clone_for_tuple {
206    ($($param:ident),+ $(,)?) => {
207        impl<$($param: ImplicitClone),+> ImplicitClone for ($($param,)+) {}
208    };
209}
210
211impl_implicit_clone_for_tuple!(T1,);
212impl_implicit_clone_for_tuple!(T1, T2);
213impl_implicit_clone_for_tuple!(T1, T2, T3);
214impl_implicit_clone_for_tuple!(T1, T2, T3, T4);
215impl_implicit_clone_for_tuple!(T1, T2, T3, T4, T5);
216impl_implicit_clone_for_tuple!(T1, T2, T3, T4, T5, T6);
217impl_implicit_clone_for_tuple!(T1, T2, T3, T4, T5, T6, T7);
218impl_implicit_clone_for_tuple!(T1, T2, T3, T4, T5, T6, T7, T8);
219impl_implicit_clone_for_tuple!(T1, T2, T3, T4, T5, T6, T7, T8, T9);
220impl_implicit_clone_for_tuple!(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10);
221impl_implicit_clone_for_tuple!(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11);
222impl_implicit_clone_for_tuple!(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12);
223
224/// A macro to help deconstructs maps inspired by JS.
225///
226/// This macro is an experiment and may change or be entirely deleted before the 1.0 release.
227///
228/// # Usage
229///
230/// ```rust
231/// use implicit_clone::unsync::*;
232/// use implicit_clone::imap_deconstruct;
233///
234/// let my_imap = [(IString::from("foo"), 1), (IString::from("bar"), 2)]
235///     .into_iter()
236///     .collect::<IMap<IString, u32>>();
237/// imap_deconstruct!(
238///     let { foo, bar, baz } = my_imap;
239///     let { foobarbaz } = my_imap;
240/// );
241/// assert_eq!(foo, Some(1));
242/// assert_eq!(bar, Some(2));
243/// assert_eq!(baz, None);
244/// assert_eq!(foobarbaz, None);
245/// ```
246#[cfg(feature = "map")]
247#[cfg_attr(docsrs, doc(cfg(feature = "map")))]
248#[macro_export]
249macro_rules! imap_deconstruct {
250    ($(let { $($key:ident),+ $(,)? } = $map:expr;)*) => {
251        $(
252        $(
253            let $key = $map.get_static_str(stringify!($key));
254        )*
255        )*
256    };
257}
258
259#[cfg(test)]
260mod test {
261    use super::*;
262    use static_assertions::*;
263
264    #[test]
265    fn custom() {
266        #[derive(Clone)]
267        #[allow(dead_code)]
268        struct ImplicitCloneType;
269
270        impl ImplicitClone for ImplicitCloneType {}
271
272        assert_impl_all!(ImplicitCloneType: ImplicitClone);
273    }
274
275    #[test]
276    fn copy_types() {
277        macro_rules! test_all {
278            ($($t:ty),* $(,)?) => {
279                $(assert_impl_all!($t: ImplicitClone, Copy);)*
280            };
281        }
282
283        #[rustfmt::skip]
284        test_all!(
285            u8, u16, u32, u64, u128,
286            i8, i16, i32, i64, i128,
287            f32, f64,
288            bool,
289            usize, isize, char,
290            (),
291            [u8; 4],
292            &[u8],
293        );
294    }
295
296    #[test]
297    fn ref_type() {
298        assert_impl_all!(&Vec<u8>: ImplicitClone);
299        assert_not_impl_all!(Vec<u8>: ImplicitClone);
300    }
301
302    #[test]
303    fn option() {
304        assert_impl_all!(Option<&'static str>: ImplicitClone);
305        assert_not_impl_all!(Option<Vec<u8>>: ImplicitClone);
306    }
307
308    #[test]
309    fn tuples() {
310        assert_impl_all!((u8,): ImplicitClone);
311        assert_impl_all!((u8, u8): ImplicitClone);
312        assert_impl_all!((u8, u8, u8): ImplicitClone);
313        assert_impl_all!((u8, u8, u8, u8): ImplicitClone);
314        assert_impl_all!((u8, u8, u8, u8, u8): ImplicitClone);
315        assert_impl_all!((u8, u8, u8, u8, u8, u8): ImplicitClone);
316        assert_impl_all!((u8, u8, u8, u8, u8, u8, u8): ImplicitClone);
317        assert_impl_all!((u8, u8, u8, u8, u8, u8, u8, u8): ImplicitClone);
318        assert_impl_all!((u8, u8, u8, u8, u8, u8, u8, u8, u8): ImplicitClone);
319        assert_impl_all!((u8, u8, u8, u8, u8, u8, u8, u8, u8, u8): ImplicitClone);
320        assert_impl_all!((u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8): ImplicitClone);
321        assert_impl_all!((u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8): ImplicitClone);
322        assert_not_impl_all!((u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8): ImplicitClone);
323        assert_not_impl_all!((Vec<u8>,): ImplicitClone);
324    }
325}