Skip to content

Commit eedb512

Browse files
authored
Rollup merge of #99460 - JanBeh:PR_asref_asmut_docs, r=joshtriplett
docs: Improve AsRef / AsMut docs on blanket impls There are several issues with the current state of `AsRef` and `AsMut` as [discussed here on IRLO](https://internals.rust-lang.org/t/semantics-of-asref/17016). See also #39397, #45742, #73390, #98905, and the FIXMEs [here](https://github.com/rust-lang/rust/blob/1.62.0/library/core/src/convert/mod.rs#L509-L515) and [here](https://github.com/rust-lang/rust/blob/1.62.0/library/core/src/convert/mod.rs#L530-L536). These issues are difficult to fix. This PR aims to update the documentation to better reflect the status-quo and to give advice on how `AsRef` and `AsMut` should be used. In particular: - Explicitly mention that `AsRef` and `AsMut` do not auto-dereference generally for all dereferencable types (but only if inner type is a shared and/or mutable reference) - Give advice to not use `AsRef` or `AsMut` for the sole purpose of dereferencing - Suggest providing a transitive `AsRef` or `AsMut` implementation for types which implement `Deref` - Add new section "Reflexivity" in documentation comments for `AsRef` and `AsMut` - Provide better example for `AsMut` - Added heading "Relation to `Borrow`" in `AsRef`'s docs to improve structure
2 parents 2110d2d + e6b761b commit eedb512

File tree

1 file changed

+187
-18
lines changed
  • library/core/src/convert

1 file changed

+187
-18
lines changed

library/core/src/convert/mod.rs

+187-18
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
//! # Generic Implementations
2626
//!
2727
//! - [`AsRef`] and [`AsMut`] auto-dereference if the inner type is a reference
28+
//! (but not generally for all [dereferenceable types][core::ops::Deref])
2829
//! - [`From`]`<U> for T` implies [`Into`]`<T> for U`
2930
//! - [`TryFrom`]`<U> for T` implies [`TryInto`]`<T> for U`
3031
//! - [`From`] and [`Into`] are reflexive, which means that all types can
@@ -109,10 +110,12 @@ pub const fn identity<T>(x: T) -> T {
109110
/// If you need to do a costly conversion it is better to implement [`From`] with type
110111
/// `&T` or write a custom function.
111112
///
113+
/// # Relation to `Borrow`
114+
///
112115
/// `AsRef` has the same signature as [`Borrow`], but [`Borrow`] is different in a few aspects:
113116
///
114117
/// - Unlike `AsRef`, [`Borrow`] has a blanket impl for any `T`, and can be used to accept either
115-
/// a reference or a value.
118+
/// a reference or a value. (See also note on `AsRef`'s reflexibility below.)
116119
/// - [`Borrow`] also requires that [`Hash`], [`Eq`] and [`Ord`] for a borrowed value are
117120
/// equivalent to those of the owned value. For this reason, if you want to
118121
/// borrow only a single field of a struct you can implement `AsRef`, but not [`Borrow`].
@@ -122,9 +125,66 @@ pub const fn identity<T>(x: T) -> T {
122125
///
123126
/// # Generic Implementations
124127
///
125-
/// - `AsRef` auto-dereferences if the inner type is a reference or a mutable
126-
/// reference (e.g.: `foo.as_ref()` will work the same if `foo` has type
127-
/// `&mut Foo` or `&&mut Foo`)
128+
/// `AsRef` auto-dereferences if the inner type is a reference or a mutable reference
129+
/// (e.g.: `foo.as_ref()` will work the same if `foo` has type `&mut Foo` or `&&mut Foo`).
130+
///
131+
/// Note that due to historic reasons, the above currently does not hold generally for all
132+
/// [dereferenceable types], e.g. `foo.as_ref()` will *not* work the same as
133+
/// `Box::new(foo).as_ref()`. Instead, many smart pointers provide an `as_ref` implementation which
134+
/// simply returns a reference to the [pointed-to value] (but do not perform a cheap
135+
/// reference-to-reference conversion for that value). However, [`AsRef::as_ref`] should not be
136+
/// used for the sole purpose of dereferencing; instead ['`Deref` coercion'] can be used:
137+
///
138+
/// [dereferenceable types]: core::ops::Deref
139+
/// [pointed-to value]: core::ops::Deref::Target
140+
/// ['`Deref` coercion']: core::ops::Deref#more-on-deref-coercion
141+
///
142+
/// ```
143+
/// let x = Box::new(5i32);
144+
/// // Avoid this:
145+
/// // let y: &i32 = x.as_ref();
146+
/// // Better just write:
147+
/// let y: &i32 = &x;
148+
/// ```
149+
///
150+
/// Types which implement [`Deref`] should consider implementing `AsRef<T>` as follows:
151+
///
152+
/// [`Deref`]: core::ops::Deref
153+
///
154+
/// ```
155+
/// # use core::ops::Deref;
156+
/// # struct SomeType;
157+
/// # impl Deref for SomeType {
158+
/// # type Target = [u8];
159+
/// # fn deref(&self) -> &[u8] {
160+
/// # &[]
161+
/// # }
162+
/// # }
163+
/// impl<T> AsRef<T> for SomeType
164+
/// where
165+
/// T: ?Sized,
166+
/// <SomeType as Deref>::Target: AsRef<T>,
167+
/// {
168+
/// fn as_ref(&self) -> &T {
169+
/// self.deref().as_ref()
170+
/// }
171+
/// }
172+
/// ```
173+
///
174+
/// # Reflexivity
175+
///
176+
/// Ideally, `AsRef` would be reflexive, i.e. there would be an `impl<T: ?Sized> AsRef<T> for T`
177+
/// with [`as_ref`] simply returning its argument unchanged.
178+
/// Such a blanket implementation is currently *not* provided due to technical restrictions of
179+
/// Rust's type system (it would be overlapping with another existing blanket implementation for
180+
/// `&T where T: AsRef<U>` which allows `AsRef` to auto-dereference, see "Generic Implementations"
181+
/// above).
182+
///
183+
/// [`as_ref`]: AsRef::as_ref
184+
///
185+
/// A trivial implementation of `AsRef<T> for T` must be added explicitly for a particular type `T`
186+
/// where needed or desired. Note, however, that not all types from `std` contain such an
187+
/// implementation, and those cannot be added by external code due to orphan rules.
128188
///
129189
/// # Examples
130190
///
@@ -172,29 +232,138 @@ pub trait AsRef<T: ?Sized> {
172232
///
173233
/// # Generic Implementations
174234
///
175-
/// - `AsMut` auto-dereferences if the inner type is a mutable reference
176-
/// (e.g.: `foo.as_mut()` will work the same if `foo` has type `&mut Foo`
177-
/// or `&mut &mut Foo`)
235+
/// `AsMut` auto-dereferences if the inner type is a mutable reference
236+
/// (e.g.: `foo.as_mut()` will work the same if `foo` has type `&mut Foo` or `&mut &mut Foo`).
237+
///
238+
/// Note that due to historic reasons, the above currently does not hold generally for all
239+
/// [mutably dereferenceable types], e.g. `foo.as_mut()` will *not* work the same as
240+
/// `Box::new(foo).as_mut()`. Instead, many smart pointers provide an `as_mut` implementation which
241+
/// simply returns a reference to the [pointed-to value] (but do not perform a cheap
242+
/// reference-to-reference conversion for that value). However, [`AsMut::as_mut`] should not be
243+
/// used for the sole purpose of mutable dereferencing; instead ['`Deref` coercion'] can be used:
244+
///
245+
/// [mutably dereferenceable types]: core::ops::DerefMut
246+
/// [pointed-to value]: core::ops::Deref::Target
247+
/// ['`Deref` coercion']: core::ops::DerefMut#more-on-deref-coercion
248+
///
249+
/// ```
250+
/// let mut x = Box::new(5i32);
251+
/// // Avoid this:
252+
/// // let y: &mut i32 = x.as_mut();
253+
/// // Better just write:
254+
/// let y: &mut i32 = &mut x;
255+
/// ```
256+
///
257+
/// Types which implement [`DerefMut`] should consider to add an implementation of `AsMut<T>` as
258+
/// follows:
259+
///
260+
/// [`DerefMut`]: core::ops::DerefMut
261+
///
262+
/// ```
263+
/// # use core::ops::{Deref, DerefMut};
264+
/// # struct SomeType;
265+
/// # impl Deref for SomeType {
266+
/// # type Target = [u8];
267+
/// # fn deref(&self) -> &[u8] {
268+
/// # &[]
269+
/// # }
270+
/// # }
271+
/// # impl DerefMut for SomeType {
272+
/// # fn deref_mut(&mut self) -> &mut [u8] {
273+
/// # &mut []
274+
/// # }
275+
/// # }
276+
/// impl<T> AsMut<T> for SomeType
277+
/// where
278+
/// <SomeType as Deref>::Target: AsMut<T>,
279+
/// {
280+
/// fn as_mut(&mut self) -> &mut T {
281+
/// self.deref_mut().as_mut()
282+
/// }
283+
/// }
284+
/// ```
285+
///
286+
/// # Reflexivity
287+
///
288+
/// Ideally, `AsMut` would be reflexive, i.e. there would be an `impl<T: ?Sized> AsMut<T> for T`
289+
/// with [`as_mut`] simply returning its argument unchanged.
290+
/// Such a blanket implementation is currently *not* provided due to technical restrictions of
291+
/// Rust's type system (it would be overlapping with another existing blanket implementation for
292+
/// `&mut T where T: AsMut<U>` which allows `AsMut` to auto-dereference, see "Generic
293+
/// Implementations" above).
294+
///
295+
/// [`as_mut`]: AsMut::as_mut
296+
///
297+
/// A trivial implementation of `AsMut<T> for T` must be added explicitly for a particular type `T`
298+
/// where needed or desired. Note, however, that not all types from `std` contain such an
299+
/// implementation, and those cannot be added by external code due to orphan rules.
178300
///
179301
/// # Examples
180302
///
181-
/// Using `AsMut` as trait bound for a generic function we can accept all mutable references
182-
/// that can be converted to type `&mut T`. Because [`Box<T>`] implements `AsMut<T>` we can
183-
/// write a function `add_one` that takes all arguments that can be converted to `&mut u64`.
184-
/// Because [`Box<T>`] implements `AsMut<T>`, `add_one` accepts arguments of type
185-
/// `&mut Box<u64>` as well:
303+
/// Using `AsMut` as trait bound for a generic function, we can accept all mutable references that
304+
/// can be converted to type `&mut T`. Unlike [dereference], which has a single [target type],
305+
/// there can be multiple implementations of `AsMut` for a type. In particular, `Vec<T>` implements
306+
/// both `AsMut<Vec<T>>` and `AsMut<[T]>`.
307+
///
308+
/// In the following, the example functions `caesar` and `null_terminate` provide a generic
309+
/// interface which work with any type that can be converted by cheap mutable-to-mutable conversion
310+
/// into a byte slice (`[u8]`) or byte vector (`Vec<u8>`), respectively.
311+
///
312+
/// [dereference]: core::ops::DerefMut
313+
/// [target type]: core::ops::Deref::Target
186314
///
187315
/// ```
188-
/// fn add_one<T: AsMut<u64>>(num: &mut T) {
189-
/// *num.as_mut() += 1;
316+
/// struct Document {
317+
/// info: String,
318+
/// content: Vec<u8>,
190319
/// }
191320
///
192-
/// let mut boxed_num = Box::new(0);
193-
/// add_one(&mut boxed_num);
194-
/// assert_eq!(*boxed_num, 1);
321+
/// impl<T: ?Sized> AsMut<T> for Document
322+
/// where
323+
/// Vec<u8>: AsMut<T>,
324+
/// {
325+
/// fn as_mut(&mut self) -> &mut T {
326+
/// self.content.as_mut()
327+
/// }
328+
/// }
329+
///
330+
/// fn caesar<T: AsMut<[u8]>>(data: &mut T, key: u8) {
331+
/// for byte in data.as_mut() {
332+
/// *byte = byte.wrapping_add(key);
333+
/// }
334+
/// }
335+
///
336+
/// fn null_terminate<T: AsMut<Vec<u8>>>(data: &mut T) {
337+
/// // Using a non-generic inner function, which contains most of the
338+
/// // functionality, helps to minimize monomorphization overhead.
339+
/// fn doit(data: &mut Vec<u8>) {
340+
/// let len = data.len();
341+
/// if len == 0 || data[len-1] != 0 {
342+
/// data.push(0);
343+
/// }
344+
/// }
345+
/// doit(data.as_mut());
346+
/// }
347+
///
348+
/// fn main() {
349+
/// let mut v: Vec<u8> = vec![1, 2, 3];
350+
/// caesar(&mut v, 5);
351+
/// assert_eq!(v, [6, 7, 8]);
352+
/// null_terminate(&mut v);
353+
/// assert_eq!(v, [6, 7, 8, 0]);
354+
/// let mut doc = Document {
355+
/// info: String::from("Example"),
356+
/// content: vec![17, 19, 8],
357+
/// };
358+
/// caesar(&mut doc, 1);
359+
/// assert_eq!(doc.content, [18, 20, 9]);
360+
/// null_terminate(&mut doc);
361+
/// assert_eq!(doc.content, [18, 20, 9, 0]);
362+
/// }
195363
/// ```
196364
///
197-
/// [`Box<T>`]: ../../std/boxed/struct.Box.html
365+
/// Note, however, that APIs don't need to be generic. In many cases taking a `&mut [u8]` or
366+
/// `&mut Vec<u8>`, for example, is the better choice (callers need to pass the correct type then).
198367
#[stable(feature = "rust1", since = "1.0.0")]
199368
#[cfg_attr(not(test), rustc_diagnostic_item = "AsMut")]
200369
#[const_trait]

0 commit comments

Comments
 (0)