try_clone/
lib.rs

1#![cfg_attr(
2    feature = "blanket-impl",
3    feature(auto_traits, negative_impls, min_specialization)
4)]
5#![cfg_attr(
6    all(feature = "alloc", feature = "nightly"),
7    feature(allocator_api, clone_from_ref)
8)]
9#![cfg_attr(feature = "doc-cfg", feature(doc_cfg))]
10#![cfg_attr(not(feature = "std"), no_std)]
11
12//! Fallible cloning.
13//!
14//! This crate defines [`TryClone`], a small trait for types whose cloning
15//! operation can fail. Unlike [`Clone`], which is infallible by design,
16//! [`TryClone`] returns a [`Result`] to allow implementations to report errors.
17//!
18//! Implementations are provided for standard library types that expose a
19//! `try_clone` API, such as [`File`](::std::fs::File), as well as for common containers
20//! and collections ([`Box`], [`Arc`](::std::sync::Arc), [`Vec`], ...) where appropriate APIs
21//! exists.
22//!
23//! A blanket implementation is available behind the `blanket-impl` feature,
24//! which implements [`TryClone`] for all [`Clone`] types.
25
26/// A fallible variant of [`Clone`].
27///
28/// this trait is intended for types where cloning can fail, for example due to
29/// allocation failures, resource limits, or external constraints.
30///
31/// Unlike [`Clone`], the cloning operation returns a [`Result`] with an
32/// associated error type.
33pub trait TryClone: Sized {
34    /// The error type returned when cloning fails.
35    type Error;
36
37    /// Tries to create a duplicate of the value.
38    ///
39    /// # Errors
40    /// Returns [`Error`](TryClone::Error) if cloning fails.
41    fn try_clone(&self) -> Result<Self, Self::Error>;
42
43    /// Performs copy-assignment from source.
44    /// `a.clone_from(&b)` is equivalent to `a = b.clone()` in functionality, but can be overridden to reuse the resources of `a` to avoid unnecessary allocations.
45    ///
46    /// # Errors
47    /// Returns [`Error`](TryClone::Error) if cloning fails.
48    fn try_clone_from(&mut self, source: &Self) -> Result<(), Self::Error> {
49        *self = source.try_clone()?;
50        Ok(())
51    }
52}
53
54/// A trait for fallibly cloning a value into an owned form.
55///
56/// This is similar in spirit to [`ToOwned`], but allows the conversion
57/// to fail and does not require `Owned` to implement [`Clone`].
58pub trait TryCloneToOwned: Sized {
59    /// The owned type produced by cloning.
60    type Owned;
61    /// The error type returned when cloning fails.
62    type Error;
63
64    /// Attempts to create an owned version of the value.
65    ///
66    /// # Errors
67    /// Returns [`Error`](TryCloneToOwned::Error) if cloning fails.
68    fn try_clone_to_owned(&self) -> Result<Self::Owned, Self::Error>;
69}
70
71/// Creates a new instance of a value by fallibly cloning it.
72///
73/// This is a convenience wrapper around [`TryClone::try_clone`].
74///
75/// # Errors
76/// Returns an error if the underlying cloning operation fails.
77pub fn try_clone<T: TryClone>(o: &T) -> Result<T, T::Error> {
78    o.try_clone()
79}
80
81/// Creates an owned version of a borrowed value fallibly.
82///
83/// This is a convenience wrapper around [`TryCloneToOwned::try_clone_to_owned`].
84///
85/// # Errors
86/// Returns an error if the conversion to an owned type fails.
87pub fn try_clone_to_owned<T: TryCloneToOwned>(o: &T) -> Result<T::Owned, T::Error> {
88    o.try_clone_to_owned()
89}
90
91#[cfg(feature = "blanket-impl")]
92use ::core::convert::Infallible;
93
94#[cfg(feature = "blanket-impl")]
95include!("blanket_impl.rs");
96
97#[cfg(feature = "blanket-impl")]
98impl<T: Clone + ForwardTryCloneToClone> TryClone for T {
99    type Error = Infallible;
100
101    default fn try_clone(&self) -> Result<Self, Self::Error> {
102        Ok(self.clone())
103    }
104
105    default fn try_clone_from(&mut self, source: &Self) -> Result<(), Self::Error> {
106        self.clone_from(source);
107        Ok(())
108    }
109}
110
111mod core;
112
113#[cfg(feature = "alloc")]
114mod alloc;
115
116#[cfg(feature = "std")]
117mod std;
118
119#[cfg(all(feature = "std", windows))]
120mod windows;
121
122#[cfg(all(feature = "std", unix))]
123mod unix;