@@ -124,9 +124,59 @@ pub trait Clone: Sized {
124
124
125
125
/// Performs copy-assignment from `source`.
126
126
///
127
- /// `a.clone_from(&b)` is equivalent to `a = b.clone()` in functionality,
128
- /// but can be overridden to reuse the resources of `a` to avoid unnecessary
129
- /// allocations.
127
+ /// `a.clone_from(&b)` is equivalent to `a = b.clone()` in functionality except cases
128
+ /// when it panics in the middle of operation. It can be overridden to reuse the resources
129
+ /// of `a` to avoid unnecessary allocations.
130
+ ///
131
+ /// # Panic behaviour
132
+ ///
133
+ /// Due to it's nature, this method cannot guarantee that it would be transactional.
134
+ /// If call panics, `self` can be left in inconsistent state.
135
+ /// This is different from `a = b.clone()` because in that case `a` is overwritten
136
+ /// only if `clone()` succeedes. Therefore, if you need transactional behaviour,
137
+ /// you shouldn't use this method.
138
+ ///
139
+ /// `clone_from` is intended to preserve resources owned by `self`
140
+ /// so it cannot preserve old data stored in those resources.
141
+ ///
142
+ /// That example shows one case of such behaviour:
143
+ /// ```no_run
144
+ /// use std::sync::Mutex;
145
+ ///
146
+ /// #[derive(PartialEq, Eq, Debug)]
147
+ /// struct PanicAtTheClone(bool);
148
+ ///
149
+ /// impl Clone for PanicAtTheClone {
150
+ /// fn clone(&self) -> Self {
151
+ /// if self.0 {
152
+ /// panic!()
153
+ /// } else {
154
+ /// PanicAtTheClone(false)
155
+ /// }
156
+ /// }
157
+ /// }
158
+ ///
159
+ /// // first element will copy just fine, second element will panic if cloned!
160
+ /// let src = vec![PanicAtTheClone(false), PanicAtTheClone(true)];
161
+ /// // start with an empty vec
162
+ /// let dest = Mutex::new(vec![]);
163
+ ///
164
+ /// // clone from src into dest
165
+ /// std::panic::catch_unwind(|| {
166
+ /// dest.lock().unwrap().clone_from(&src);
167
+ /// })
168
+ /// .expect_err("Must panic");
169
+ ///
170
+ /// // handle the poisoned mutex (without the mutex even attempting this produces a compiler error!)
171
+ /// let guard = dest
172
+ /// .lock()
173
+ /// .expect_err("mutex should be poisoned by the panic")
174
+ /// .into_inner();
175
+ ///
176
+ /// // dest is left in an incomplete state with only half of the clone having
177
+ /// // completed successfully
178
+ /// assert_eq!(vec![PanicAtTheClone(false)], *guard);
179
+ /// ```
130
180
#[ inline]
131
181
#[ stable( feature = "rust1" , since = "1.0.0" ) ]
132
182
#[ cfg_attr( bootstrap, default_method_body_is_const) ]
0 commit comments