From cba5f6bd01bc3ba692c355ca82212db069cd800c Mon Sep 17 00:00:00 2001 From: Martin Hoffmann Date: Tue, 5 Dec 2017 18:07:28 +0100 Subject: [PATCH 1/9] Rewrite Borrow's trait documentation. --- src/libcore/borrow.rs | 147 +++++++++++++++++++++++++++++++++++++----- 1 file changed, 132 insertions(+), 15 deletions(-) diff --git a/src/libcore/borrow.rs b/src/libcore/borrow.rs index 61558034e63..76f6215fae6 100644 --- a/src/libcore/borrow.rs +++ b/src/libcore/borrow.rs @@ -12,26 +12,143 @@ #![stable(feature = "rust1", since = "1.0.0")] -/// A trait for borrowing data. +// impl Borrow for String +// impl Borrow for Arc +// impl HashSet { fn get(&self, q: &Q) where K: Borrow } + +/// A trait identifying how borrowed data behaves. /// -/// In general, there may be several ways to "borrow" a piece of data. The -/// typical ways of borrowing a type `T` are `&T` (a shared borrow) and `&mut T` -/// (a mutable borrow). But types like `Vec` provide additional kinds of -/// borrows: the borrowed slices `&[T]` and `&mut [T]`. +/// If a type implements this trait, it signals that a reference to it behaves +/// exactly like a reference to `Borrowed`. As a consequence, if a trait is +/// implemented both by `Self` and `Borrowed`, all trait methods that +/// take a `&self` argument must produce the same result in both +/// implementations. /// -/// When writing generic code, it is often desirable to abstract over all ways -/// of borrowing data from a given type. That is the role of the `Borrow` -/// trait: if `T: Borrow`, then `&U` can be borrowed from `&T`. A given -/// type can be borrowed as multiple different types. In particular, `Vec: -/// Borrow>` and `Vec: Borrow<[T]>`. +/// As a consequence, this trait should only be implemented for types managing +/// a value of another type without modifying its behavior. Examples are +/// smart pointers such as [`Box`] or [`Rc`] as well the owned version of +/// slices such as [`Vec`]. /// -/// If you are implementing `Borrow` and both `Self` and `Borrowed` implement -/// `Hash`, `Eq`, and/or `Ord`, they must produce the same result. +/// A relaxed version that allows providing a reference to some other type +/// without any further promises is available through [`AsRef`]. /// -/// `Borrow` is very similar to, but different than, `AsRef`. See -/// [the book][book] for more. +/// When writing generic code, a use of `Borrow` should always be justified +/// by additional trait bounds, making it clear that the two types need to +/// behave identically in a certain context. If the code should merely be +/// able to operate on any type that can produce a reference to a given type, +/// you should use [`AsRef`] instead. /// -/// [book]: ../../book/first-edition/borrow-and-asref.html +/// The companion trait [`BorrowMut`] provides the same guarantees for +/// mutable references. +/// +/// [`Box`]: ../boxed/struct.Box.html +/// [`Rc`]: ../rc/struct.Rc.html +/// [`Vec`]: ../vec/struct.Vec.html +/// [`AsRef`]: ../convert/trait.AsRef.html +/// [`BorrowMut`]: trait.BorrowMut.html +/// +/// # Examples +/// +/// As a data collection, [`HashMap`] owns both keys and values. If the key’s +/// actual data is wrapped in a managing type of some kind, it should, +/// however, still be possible to search for a value using a reference to the +/// key’s data. For instance, if the key is a string, then it is likely +/// stored with the hash map as a [`String`], while it should be possible +/// to search using a [`&str`][`str`]. Thus, `insert` needs to operate on a +/// string while `get` needs to be able to use a `&str`. +/// +/// Slightly simplified, the relevant parts of `HashMap` look like this: +/// +/// ``` +/// use std::borrow::Borrow; +/// use std::hash::Hash; +/// +/// pub struct HashMap { +/// # marker: ::std::marker::PhantomData<(K, V)>, +/// // fields omitted +/// } +/// +/// impl HashMap { +/// pub fn insert(&self, key: K, value: V) -> Option +/// where K: Hash + Eq +/// { +/// # unimplemented!() +/// // ... +/// } +/// +/// pub fn get(&self, k: &Q) -> Option<&V> +/// where K: Borrow, +/// Q: Hash + Eq + ?Sized +/// { +/// # unimplemented!() +/// // ... +/// } +/// } +/// ``` +/// +/// The entire hash map is generic over the stored type for the key, `K`. +/// When inserting a value, the map is given such a `K` and needs to find +/// the correct hash bucket and check if the key is already present based +/// on that `K` value. It therefore requires `K: Hash + Eq`. +/// +/// In order to search for a value based on the key’s data, the `get` method +/// is generic over some type `Q`. Technically, it needs to convert that `Q` +/// into a `K` in order to use `K`’s [`Hash`] implementation to be able to +/// arrive at the same hash value as during insertion in order to look into +/// the right hash bucket. Since `K` is some kind of owned value, this likely +/// would involve cloning and isn’t really practical. +/// +/// Instead, `get` relies on `Q`’s implementation of `Hash` and uses `Borrow` +/// to indicate that `K`’s implementation of `Hash` must produce the same +/// result as `Q`’s by demanding that `K: Borrow`. +/// +/// As a consequence, the hash map breaks if a `K` wrapping a `Q` value +/// produces a different hash than `Q`. For instance, image you have a +/// type that wraps a string but compares ASCII letters case-insensitive: +/// +/// ``` +/// use std::ascii::AsciiExt; +/// +/// pub struct CIString(String); +/// +/// impl PartialEq for CIString { +/// fn eq(&self, other: &Self) -> bool { +/// self.0.eq_ignore_ascii_case(&other.0) +/// } +/// } +/// +/// impl Eq for CIString { } +/// ``` +/// +/// Because two equal values need to produce the same hash value, the +/// implementation of `Hash` need to reflect that, too: +/// +/// ``` +/// # use std::ascii::AsciiExt; +/// # use std::hash::{Hash, Hasher}; +/// # pub struct CIString(String); +/// impl Hash for CIString { +/// fn hash(&self, state: &mut H) { +/// for c in self.0.as_bytes() { +/// c.to_ascii_lowercase().hash(state) +/// } +/// } +/// } +/// ``` +/// +/// Can `CIString` implement `Borrow`? It certainly can provide a +/// reference to a string slice via its contained owned string. But because +/// its `Hash` implementation differs, it cannot fulfill the guarantee for +/// `Borrow` that all common trait implementations must behave the same way +/// and must not, in fact, implement `Borrow`. If it wants to allow +/// others access to the underlying `str`, it can do that via `AsRef` +/// which doesn’t carry any such restrictions. +/// +/// [`Hash`]: ../hash/trait.Hash.html +/// [`HashMap`]: ../collections/struct.HashMap.html +/// [`String`]: ../string/struct.String.html +/// [`str`]: ../primitive.str.html +/// #[stable(feature = "rust1", since = "1.0.0")] pub trait Borrow { /// Immutably borrows from an owned value. From c4ea700041f78a016dca557c2da86006a7bbedf8 Mon Sep 17 00:00:00 2001 From: Martin Hoffmann Date: Tue, 5 Dec 2017 18:28:29 +0100 Subject: [PATCH 2/9] Remove trailing white space. --- src/libcore/borrow.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/libcore/borrow.rs b/src/libcore/borrow.rs index 76f6215fae6..4d4a07f59d1 100644 --- a/src/libcore/borrow.rs +++ b/src/libcore/borrow.rs @@ -100,12 +100,12 @@ /// /// Instead, `get` relies on `Q`’s implementation of `Hash` and uses `Borrow` /// to indicate that `K`’s implementation of `Hash` must produce the same -/// result as `Q`’s by demanding that `K: Borrow`. +/// result as `Q`’s by demanding that `K: Borrow`. /// /// As a consequence, the hash map breaks if a `K` wrapping a `Q` value /// produces a different hash than `Q`. For instance, image you have a /// type that wraps a string but compares ASCII letters case-insensitive: -/// +/// /// ``` /// use std::ascii::AsciiExt; /// @@ -148,7 +148,7 @@ /// [`HashMap`]: ../collections/struct.HashMap.html /// [`String`]: ../string/struct.String.html /// [`str`]: ../primitive.str.html -/// +/// #[stable(feature = "rust1", since = "1.0.0")] pub trait Borrow { /// Immutably borrows from an owned value. From 85e8a9ba00e8ac090ceaac619110264e8e8bf6c6 Mon Sep 17 00:00:00 2001 From: Martin Hoffmann Date: Thu, 7 Dec 2017 16:50:37 +0100 Subject: [PATCH 3/9] Include feedback and try to make examples build on all channels. --- src/libcore/borrow.rs | 60 +++++++++++++++++++++---------------------- 1 file changed, 30 insertions(+), 30 deletions(-) diff --git a/src/libcore/borrow.rs b/src/libcore/borrow.rs index 4d4a07f59d1..77006193a58 100644 --- a/src/libcore/borrow.rs +++ b/src/libcore/borrow.rs @@ -12,10 +12,6 @@ #![stable(feature = "rust1", since = "1.0.0")] -// impl Borrow for String -// impl Borrow for Arc -// impl HashSet { fn get(&self, q: &Q) where K: Borrow } - /// A trait identifying how borrowed data behaves. /// /// If a type implements this trait, it signals that a reference to it behaves @@ -26,10 +22,10 @@ /// /// As a consequence, this trait should only be implemented for types managing /// a value of another type without modifying its behavior. Examples are -/// smart pointers such as [`Box`] or [`Rc`] as well the owned version of -/// slices such as [`Vec`]. +/// smart pointers such as [`Box`] or [`Rc`] as well the owned version +/// of slices such as [`Vec`]. /// -/// A relaxed version that allows providing a reference to some other type +/// A relaxed version that allows converting a reference to some other type /// without any further promises is available through [`AsRef`]. /// /// When writing generic code, a use of `Borrow` should always be justified @@ -41,23 +37,24 @@ /// The companion trait [`BorrowMut`] provides the same guarantees for /// mutable references. /// -/// [`Box`]: ../boxed/struct.Box.html -/// [`Rc`]: ../rc/struct.Rc.html -/// [`Vec`]: ../vec/struct.Vec.html +/// [`Box`]: ../boxed/struct.Box.html +/// [`Rc`]: ../rc/struct.Rc.html +/// [`Vec`]: ../vec/struct.Vec.html /// [`AsRef`]: ../convert/trait.AsRef.html /// [`BorrowMut`]: trait.BorrowMut.html /// /// # Examples /// -/// As a data collection, [`HashMap`] owns both keys and values. If the key’s -/// actual data is wrapped in a managing type of some kind, it should, -/// however, still be possible to search for a value using a reference to the -/// key’s data. For instance, if the key is a string, then it is likely -/// stored with the hash map as a [`String`], while it should be possible -/// to search using a [`&str`][`str`]. Thus, `insert` needs to operate on a -/// string while `get` needs to be able to use a `&str`. +/// As a data collection, [`HashMap`] owns both keys and values. If +/// the key’s actual data is wrapped in a managing type of some kind, it +/// should, however, still be possible to search for a value using a +/// reference to the key’s data. For instance, if the key is a string, then +/// it is likely stored with the hash map as a [`String`], while it should +/// be possible to search using a [`&str`][`str`]. Thus, `insert` needs to +/// operate on a `String` while `get` needs to be able to use a `&str`. /// -/// Slightly simplified, the relevant parts of `HashMap` look like this: +/// Slightly simplified, the relevant parts of `HashMap` look like +/// this: /// /// ``` /// use std::borrow::Borrow; @@ -70,15 +67,16 @@ /// /// impl HashMap { /// pub fn insert(&self, key: K, value: V) -> Option -/// where K: Hash + Eq +/// where K: Hash + Eq /// { /// # unimplemented!() /// // ... /// } /// /// pub fn get(&self, k: &Q) -> Option<&V> -/// where K: Borrow, -/// Q: Hash + Eq + ?Sized +/// where +/// K: Borrow, +/// Q: Hash + Eq + ?Sized /// { /// # unimplemented!() /// // ... @@ -86,10 +84,11 @@ /// } /// ``` /// -/// The entire hash map is generic over the stored type for the key, `K`. -/// When inserting a value, the map is given such a `K` and needs to find -/// the correct hash bucket and check if the key is already present based -/// on that `K` value. It therefore requires `K: Hash + Eq`. +/// The entire hash map is generic over a key type `K`. Because these keys +/// are stored by with the hash map, this type as to own the key’s data. +/// When inserting a key-value pair, the map is given such a `K` and needs +/// to find the correct hash bucket and check if the key is already present +/// based on that `K`. It therefore requires `K: Hash + Eq`. /// /// In order to search for a value based on the key’s data, the `get` method /// is generic over some type `Q`. Technically, it needs to convert that `Q` @@ -103,10 +102,11 @@ /// result as `Q`’s by demanding that `K: Borrow`. /// /// As a consequence, the hash map breaks if a `K` wrapping a `Q` value -/// produces a different hash than `Q`. For instance, image you have a -/// type that wraps a string but compares ASCII letters case-insensitive: +/// produces a different hash than `Q`. For instance, imagine you have a +/// type that wraps a string but compares ASCII letters ignoring their case: /// /// ``` +/// # #[allow(unused_imports)] /// use std::ascii::AsciiExt; /// /// pub struct CIString(String); @@ -121,10 +121,10 @@ /// ``` /// /// Because two equal values need to produce the same hash value, the -/// implementation of `Hash` need to reflect that, too: +/// implementation of `Hash` needs to reflect that, too: /// /// ``` -/// # use std::ascii::AsciiExt; +/// # #[allow(unused_imports)] use std::ascii::AsciiExt; /// # use std::hash::{Hash, Hasher}; /// # pub struct CIString(String); /// impl Hash for CIString { @@ -145,7 +145,7 @@ /// which doesn’t carry any such restrictions. /// /// [`Hash`]: ../hash/trait.Hash.html -/// [`HashMap`]: ../collections/struct.HashMap.html +/// [`HashMap`]: ../collections/struct.HashMap.html /// [`String`]: ../string/struct.String.html /// [`str`]: ../primitive.str.html /// From fc6c6383f6999d87c92be3dfd5f09c357be41135 Mon Sep 17 00:00:00 2001 From: Martin Hoffmann Date: Wed, 13 Dec 2017 08:48:29 +0100 Subject: [PATCH 4/9] Fix documentation links. --- src/libcore/borrow.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/libcore/borrow.rs b/src/libcore/borrow.rs index 77006193a58..33e4c8780d6 100644 --- a/src/libcore/borrow.rs +++ b/src/libcore/borrow.rs @@ -37,10 +37,10 @@ /// The companion trait [`BorrowMut`] provides the same guarantees for /// mutable references. /// -/// [`Box`]: ../boxed/struct.Box.html -/// [`Rc`]: ../rc/struct.Rc.html -/// [`Vec`]: ../vec/struct.Vec.html -/// [`AsRef`]: ../convert/trait.AsRef.html +/// [`Box`]: ../../std/boxed/struct.Box.html +/// [`Rc`]: ../../std/rc/struct.Rc.html +/// [`Vec`]: ../../std/vec/struct.Vec.html +/// [`AsRef`]: ../../std/convert/trait.AsRef.html /// [`BorrowMut`]: trait.BorrowMut.html /// /// # Examples @@ -144,10 +144,10 @@ /// others access to the underlying `str`, it can do that via `AsRef` /// which doesn’t carry any such restrictions. /// -/// [`Hash`]: ../hash/trait.Hash.html -/// [`HashMap`]: ../collections/struct.HashMap.html -/// [`String`]: ../string/struct.String.html -/// [`str`]: ../primitive.str.html +/// [`Hash`]: ../../std/hash/trait.Hash.html +/// [`HashMap`]: ../../std/collections/struct.HashMap.html +/// [`String`]: ../../std/string/struct.String.html +/// [`str`]: ../../std/primitive.str.html /// #[stable(feature = "rust1", since = "1.0.0")] pub trait Borrow { From 7ae7e5393367cdc9a630cd56911ab42f499c091f Mon Sep 17 00:00:00 2001 From: Martin Hoffmann Date: Thu, 8 Feb 2018 11:07:05 +0100 Subject: [PATCH 5/9] New introduction and revised hash map explanation. --- src/libcore/borrow.rs | 70 ++++++++++++++++++++++++++----------------- 1 file changed, 42 insertions(+), 28 deletions(-) diff --git a/src/libcore/borrow.rs b/src/libcore/borrow.rs index 33e4c8780d6..1f692d019c3 100644 --- a/src/libcore/borrow.rs +++ b/src/libcore/borrow.rs @@ -14,19 +14,28 @@ /// A trait identifying how borrowed data behaves. /// -/// If a type implements this trait, it signals that a reference to it behaves -/// exactly like a reference to `Borrowed`. As a consequence, if a trait is -/// implemented both by `Self` and `Borrowed`, all trait methods that -/// take a `&self` argument must produce the same result in both -/// implementations. +/// In Rust, it is common to provide different representations of a type for +/// different use cases. For instance, storage location and management for a +/// value can be specifically chosen as appropriate for a particular use via +/// pointer types such as [`Box`] or [`Rc`] or one can opt into +/// concurrency via synchronization types such as [`Mutex`], avoiding the +/// associated cost when in parallel doesn’t happen. Beyond these generic +/// wrappers that can be used with any type, some types provide optional +/// facets providing potentially costly functionality. An example for such a +/// type is [`String`] which adds the ability to extend a string to the basic +/// [`str`]. This requires keeping additional information unnecessary for a +/// simple, imutable string. /// -/// As a consequence, this trait should only be implemented for types managing -/// a value of another type without modifying its behavior. Examples are -/// smart pointers such as [`Box`] or [`Rc`] as well the owned version -/// of slices such as [`Vec`]. +/// These types signal that they are a specialized representation of a basic +/// type `T` by implementing `Borrow`. The method `borrow` provides a way +/// to convert a reference to the type into a reference to the underlying +/// basic type. /// -/// A relaxed version that allows converting a reference to some other type -/// without any further promises is available through [`AsRef`]. +/// If a type implementing `Borrow` implements other traits also +/// implemented by `T`, these implementations behave identically if the trait +/// is concerned with the data rather than its representation. For instance, +/// the comparison traits such as `PartialEq` or `PartialOrd` must behave +/// identical for `T` and any type implemeting `Borrow`. /// /// When writing generic code, a use of `Borrow` should always be justified /// by additional trait bounds, making it clear that the two types need to @@ -37,11 +46,13 @@ /// The companion trait [`BorrowMut`] provides the same guarantees for /// mutable references. /// -/// [`Box`]: ../../std/boxed/struct.Box.html -/// [`Rc`]: ../../std/rc/struct.Rc.html -/// [`Vec`]: ../../std/vec/struct.Vec.html /// [`AsRef`]: ../../std/convert/trait.AsRef.html /// [`BorrowMut`]: trait.BorrowMut.html +/// [`Box`]: ../../std/boxed/struct.Box.html +/// [`Mutex`]: ../../std/sync/struct.Mutex.html +/// [`Rc`]: ../../std/rc/struct.Rc.html +/// [`str`]: ../../std/primitive.str.html +/// [`String`]: ../../std/string/struct.String.html /// /// # Examples /// @@ -85,30 +96,34 @@ /// ``` /// /// The entire hash map is generic over a key type `K`. Because these keys -/// are stored by with the hash map, this type as to own the key’s data. +/// are stored with the hash map, this type has to own the key’s data. /// When inserting a key-value pair, the map is given such a `K` and needs /// to find the correct hash bucket and check if the key is already present /// based on that `K`. It therefore requires `K: Hash + Eq`. /// -/// In order to search for a value based on the key’s data, the `get` method -/// is generic over some type `Q`. Technically, it needs to convert that `Q` -/// into a `K` in order to use `K`’s [`Hash`] implementation to be able to -/// arrive at the same hash value as during insertion in order to look into -/// the right hash bucket. Since `K` is some kind of owned value, this likely -/// would involve cloning and isn’t really practical. +/// When searching for a value in the map, however, having to provide a +/// reference to a `K` as the key to search for would require to always +/// create such an owned value. For string keys, this would mean a `String` +/// value needs to be created just for the search for cases where only a +/// `str` is available. /// -/// Instead, `get` relies on `Q`’s implementation of `Hash` and uses `Borrow` -/// to indicate that `K`’s implementation of `Hash` must produce the same -/// result as `Q`’s by demanding that `K: Borrow`. +/// Instead, the `get` method is generic over the type of the underlying key +/// data, called `Q` in the method signature above. It states that `K` is a +/// representation of `Q` by requiring that `K: Borrow`. By additionally +/// requiring `Q: Hash + Eq`, it demands that `K` and `Q` have +/// implementations of the `Hash` and `Eq` traits that procude identical +/// results. +/// +/// The implementation of `get` relies in particular on identical +/// implementations of `Hash` by determining the key’s hash bucket by calling +/// `Hash::hash` on the `Q` value even though it inserted the key based on +/// the hash value calculated from the `K` value. /// /// As a consequence, the hash map breaks if a `K` wrapping a `Q` value /// produces a different hash than `Q`. For instance, imagine you have a /// type that wraps a string but compares ASCII letters ignoring their case: /// /// ``` -/// # #[allow(unused_imports)] -/// use std::ascii::AsciiExt; -/// /// pub struct CIString(String); /// /// impl PartialEq for CIString { @@ -124,7 +139,6 @@ /// implementation of `Hash` needs to reflect that, too: /// /// ``` -/// # #[allow(unused_imports)] use std::ascii::AsciiExt; /// # use std::hash::{Hash, Hasher}; /// # pub struct CIString(String); /// impl Hash for CIString { From 44be054a2acbeeb682d02a5f88ddedc0cb5c9bf2 Mon Sep 17 00:00:00 2001 From: Martin Hoffmann Date: Tue, 27 Feb 2018 16:24:52 +0100 Subject: [PATCH 6/9] Further refinement of Borrow documentation. --- src/libcore/borrow.rs | 68 +++++++++++++++++++++++-------------------- 1 file changed, 36 insertions(+), 32 deletions(-) diff --git a/src/libcore/borrow.rs b/src/libcore/borrow.rs index 1f692d019c3..c0f1989f879 100644 --- a/src/libcore/borrow.rs +++ b/src/libcore/borrow.rs @@ -17,36 +17,41 @@ /// In Rust, it is common to provide different representations of a type for /// different use cases. For instance, storage location and management for a /// value can be specifically chosen as appropriate for a particular use via -/// pointer types such as [`Box`] or [`Rc`] or one can opt into -/// concurrency via synchronization types such as [`Mutex`], avoiding the -/// associated cost when in parallel doesn’t happen. Beyond these generic +/// pointer types such as [`Box`] or [`Rc`]. Beyond these generic /// wrappers that can be used with any type, some types provide optional /// facets providing potentially costly functionality. An example for such a /// type is [`String`] which adds the ability to extend a string to the basic /// [`str`]. This requires keeping additional information unnecessary for a -/// simple, imutable string. +/// simple, immutable string. /// /// These types signal that they are a specialized representation of a basic /// type `T` by implementing `Borrow`. The method `borrow` provides a way -/// to convert a reference to the type into a reference to the underlying -/// basic type. +/// to convert a reference to the type into a reference to this basic type +/// `T`. /// -/// If a type implementing `Borrow` implements other traits also -/// implemented by `T`, these implementations behave identically if the trait -/// is concerned with the data rather than its representation. For instance, -/// the comparison traits such as `PartialEq` or `PartialOrd` must behave -/// identical for `T` and any type implemeting `Borrow`. +/// Further, when providing implementations for additional traits, it needs +/// to be considered whether they should behave identical to those of the +/// underlying type as a consequence of acting as a representation of that +/// underlying type. /// -/// When writing generic code, a use of `Borrow` should always be justified -/// by additional trait bounds, making it clear that the two types need to -/// behave identically in a certain context. If the code should merely be -/// able to operate on any type that can produce a reference to a given type, -/// you should use [`AsRef`] instead. +/// Generic code typically uses `Borrow` when it not only needs access +/// to a reference of the underlying type but relies on the identical +/// behavior of these additional trait implementations. These traits are +/// likely to appear as additional trait bounds. /// -/// The companion trait [`BorrowMut`] provides the same guarantees for -/// mutable references. +/// If generic code merely needs to work for all types that can +/// provide a reference to related type `T`, it is often better to use +/// [`AsRef`] as more types can safely implement it. /// -/// [`AsRef`]: ../../std/convert/trait.AsRef.html +/// If a type implementing `Borrow` also wishes to allow mutable access +/// to the underlying type `T`, it can do so by implementing the companion +/// trait [`BorrowMut`]. +/// +/// Note also that it is perfectly fine for a single type to have multiple +/// implementations of `Borrow` for different `T`s. In fact, a blanket +/// implementation lets every type be at least a borrow of itself. +/// +/// [`AsRef`]: ../../std/convert/trait.AsRef.html /// [`BorrowMut`]: trait.BorrowMut.html /// [`Box`]: ../../std/boxed/struct.Box.html /// [`Mutex`]: ../../std/sync/struct.Mutex.html @@ -111,7 +116,7 @@ /// data, called `Q` in the method signature above. It states that `K` is a /// representation of `Q` by requiring that `K: Borrow`. By additionally /// requiring `Q: Hash + Eq`, it demands that `K` and `Q` have -/// implementations of the `Hash` and `Eq` traits that procude identical +/// implementations of the `Hash` and `Eq` traits that produce identical /// results. /// /// The implementation of `get` relies in particular on identical @@ -124,15 +129,15 @@ /// type that wraps a string but compares ASCII letters ignoring their case: /// /// ``` -/// pub struct CIString(String); +/// pub struct CaseInsensitiveString(String); /// -/// impl PartialEq for CIString { +/// impl PartialEq for CaseInsensitiveString { /// fn eq(&self, other: &Self) -> bool { /// self.0.eq_ignore_ascii_case(&other.0) /// } /// } /// -/// impl Eq for CIString { } +/// impl Eq for CaseInsensitiveString { } /// ``` /// /// Because two equal values need to produce the same hash value, the @@ -140,8 +145,8 @@ /// /// ``` /// # use std::hash::{Hash, Hasher}; -/// # pub struct CIString(String); -/// impl Hash for CIString { +/// # pub struct CaseInsensitiveString(String); +/// impl Hash for CaseInsensitiveString { /// fn hash(&self, state: &mut H) { /// for c in self.0.as_bytes() { /// c.to_ascii_lowercase().hash(state) @@ -150,13 +155,12 @@ /// } /// ``` /// -/// Can `CIString` implement `Borrow`? It certainly can provide a -/// reference to a string slice via its contained owned string. But because -/// its `Hash` implementation differs, it cannot fulfill the guarantee for -/// `Borrow` that all common trait implementations must behave the same way -/// and must not, in fact, implement `Borrow`. If it wants to allow -/// others access to the underlying `str`, it can do that via `AsRef` -/// which doesn’t carry any such restrictions. +/// Can `CaseInsensitiveString` implement `Borrow`? It certainly can +/// provide a reference to a string slice via its contained owned string. +/// But because its `Hash` implementation differs, it behaves differently +/// from `str` and therefore must not, in fact, implement `Borrow`. +/// If it wants to allow others access to the underlying `str`, it can do +/// that via `AsRef` which doesn’t carry any extra requirements. /// /// [`Hash`]: ../../std/hash/trait.Hash.html /// [`HashMap`]: ../../std/collections/struct.HashMap.html From 5bef034b198c58fd02a9e8a584a24fd516dc969c Mon Sep 17 00:00:00 2001 From: Martin Hoffmann Date: Sat, 17 Mar 2018 14:05:24 +0100 Subject: [PATCH 7/9] Bring back the phrase 'borrowing as' for what Borrow does. --- src/libcore/borrow.rs | 47 ++++++++++++++++++++----------------------- 1 file changed, 22 insertions(+), 25 deletions(-) diff --git a/src/libcore/borrow.rs b/src/libcore/borrow.rs index c0f1989f879..0014bddb55c 100644 --- a/src/libcore/borrow.rs +++ b/src/libcore/borrow.rs @@ -12,7 +12,7 @@ #![stable(feature = "rust1", since = "1.0.0")] -/// A trait identifying how borrowed data behaves. +/// A trait for borrowing data. /// /// In Rust, it is common to provide different representations of a type for /// different use cases. For instance, storage location and management for a @@ -24,40 +24,37 @@ /// [`str`]. This requires keeping additional information unnecessary for a /// simple, immutable string. /// -/// These types signal that they are a specialized representation of a basic -/// type `T` by implementing `Borrow`. The method `borrow` provides a way -/// to convert a reference to the type into a reference to this basic type -/// `T`. +/// These types provide access to the underlying data through references +/// to the type of that data. They are said to be ‘borrowed as’ that type. +/// For instance, a [`Box`] can be borrowed as `T` while a [`String`] +/// can be borrowed as `str`. +/// +/// Types express that they can be borrowed as some type `T` by implementing +/// `Borrow`, providing a reference to a `T` in the trait’s +/// [`borrow`] method. A type is free to borrow as several different types. +/// If it wishes to mutably borrow as the type – allowing the underlying data +/// to be modified, it can additionally implement [`BorrowMut`]. /// /// Further, when providing implementations for additional traits, it needs /// to be considered whether they should behave identical to those of the /// underlying type as a consequence of acting as a representation of that -/// underlying type. -/// -/// Generic code typically uses `Borrow` when it not only needs access -/// to a reference of the underlying type but relies on the identical -/// behavior of these additional trait implementations. These traits are -/// likely to appear as additional trait bounds. +/// underlying type. Generic code typically uses `Borrow` when it relies +/// on the identical behavior of these additional trait implementations. +/// These traits will likely appear as additional trait bounds. /// /// If generic code merely needs to work for all types that can /// provide a reference to related type `T`, it is often better to use /// [`AsRef`] as more types can safely implement it. /// -/// If a type implementing `Borrow` also wishes to allow mutable access -/// to the underlying type `T`, it can do so by implementing the companion -/// trait [`BorrowMut`]. -/// -/// Note also that it is perfectly fine for a single type to have multiple -/// implementations of `Borrow` for different `T`s. In fact, a blanket -/// implementation lets every type be at least a borrow of itself. -/// /// [`AsRef`]: ../../std/convert/trait.AsRef.html -/// [`BorrowMut`]: trait.BorrowMut.html +/// [`BorrowMut`]: trait.BorrowMut.html /// [`Box`]: ../../std/boxed/struct.Box.html /// [`Mutex`]: ../../std/sync/struct.Mutex.html /// [`Rc`]: ../../std/rc/struct.Rc.html /// [`str`]: ../../std/primitive.str.html /// [`String`]: ../../std/string/struct.String.html +/// [`borrow`]: #tymethod.borrow +/// /// /// # Examples /// @@ -113,10 +110,10 @@ /// `str` is available. /// /// Instead, the `get` method is generic over the type of the underlying key -/// data, called `Q` in the method signature above. It states that `K` is a -/// representation of `Q` by requiring that `K: Borrow`. By additionally -/// requiring `Q: Hash + Eq`, it demands that `K` and `Q` have -/// implementations of the `Hash` and `Eq` traits that produce identical +/// data, called `Q` in the method signature above. It states that `K` +/// borrows as a `Q` by requiring that `K: Borrow`. By additionally +/// requiring `Q: Hash + Eq`, it signals the requirement that `K` and `Q` +/// have implementations of the `Hash` and `Eq` traits that produce identical /// results. /// /// The implementation of `get` relies in particular on identical @@ -141,7 +138,7 @@ /// ``` /// /// Because two equal values need to produce the same hash value, the -/// implementation of `Hash` needs to reflect that, too: +/// implementation of `Hash` needs to ignore ASCII case, too: /// /// ``` /// # use std::hash::{Hash, Hasher}; From d664b8954e83e74870a90b871161942d6e827aa6 Mon Sep 17 00:00:00 2001 From: Martin Hoffmann Date: Sat, 17 Mar 2018 14:09:45 +0100 Subject: [PATCH 8/9] Rewrite the documentation for BorrowMut. --- src/libcore/borrow.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/libcore/borrow.rs b/src/libcore/borrow.rs index 0014bddb55c..7470512e2b2 100644 --- a/src/libcore/borrow.rs +++ b/src/libcore/borrow.rs @@ -191,7 +191,11 @@ pub trait Borrow { /// A trait for mutably borrowing data. /// -/// Similar to `Borrow`, but for mutable borrows. +/// As a companion to [`Borrow`] this trait allows a type to borrow as +/// an underlying type by providing a mutable reference. See [`Borrow`] +/// for more information on borrowing as another type. +/// +/// [`Borrow`]: trait.Borrow.html #[stable(feature = "rust1", since = "1.0.0")] pub trait BorrowMut : Borrow { /// Mutably borrows from an owned value. From 13d94d666e037162808174f0bedbd5db9d65c7fe Mon Sep 17 00:00:00 2001 From: Martin Hoffmann Date: Sun, 18 Mar 2018 13:05:00 +0100 Subject: [PATCH 9/9] Fix formatting. --- src/libcore/borrow.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/libcore/borrow.rs b/src/libcore/borrow.rs index 7470512e2b2..f45a32d4b94 100644 --- a/src/libcore/borrow.rs +++ b/src/libcore/borrow.rs @@ -55,7 +55,6 @@ /// [`String`]: ../../std/string/struct.String.html /// [`borrow`]: #tymethod.borrow /// -/// /// # Examples /// /// As a data collection, [`HashMap`] owns both keys and values. If @@ -163,7 +162,6 @@ /// [`HashMap`]: ../../std/collections/struct.HashMap.html /// [`String`]: ../../std/string/struct.String.html /// [`str`]: ../../std/primitive.str.html -/// #[stable(feature = "rust1", since = "1.0.0")] pub trait Borrow { /// Immutably borrows from an owned value.