Skip to content

Commit c5fec0b

Browse files
committed
---
yaml --- r: 208361 b: refs/heads/snap-stage3 c: e780fb2 h: refs/heads/master i: 208359: 03291f2 v: v3
1 parent 2d986ee commit c5fec0b

File tree

8 files changed

+170
-107
lines changed

8 files changed

+170
-107
lines changed

[refs]

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
---
22
refs/heads/master: 38a97becdf3e6a6157f6f7ec2d98ade8d8edc193
33
refs/heads/snap-stage1: e33de59e47c5076a89eadeb38f4934f58a3618a6
4-
refs/heads/snap-stage3: 3ca008dcf12283247122f25928630f2a484ff768
4+
refs/heads/snap-stage3: e780fb270c5296a87ff9dc1442fc141f69e77fcd
55
refs/heads/try: 7b4ef47b7805a402d756fb8157101f64880a522f
66
refs/tags/release-0.1: 1f5c5126e96c79d22cb7862f75304136e204f105
77
refs/heads/dist-snap: ba4081a5a8573875fed17545846f6f6902c8ba8d

branches/snap-stage3/src/doc/trpl/SUMMARY.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
* [Concurrency](concurrency.md)
1616
* [Error Handling](error-handling.md)
1717
* [FFI](ffi.md)
18+
* [Borrow and AsRef](borrow-and-asref.md)
1819
* [Syntax and Semantics](syntax-and-semantics.md)
1920
* [Variable Bindings](variable-bindings.md)
2021
* [Functions](functions.md)
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
% Borrow and AsRef
2+
3+
The [`Borrow`][borrow] and [`AsRef`][asref] traits are very similar, but
4+
different. Here’s a quick refresher on what these two traits mean.
5+
6+
[borrow]: ../std/borrow/trait.Borrow.html
7+
[asref]: ../std/convert/trait.AsRef.html
8+
9+
# Borrow
10+
11+
The `Borrow` trait is used when you’re writing a datastructure, and you want to
12+
use either an owned or borrowed type as synonymous for some purpose.
13+
14+
For example, [`HashMap`][hashmap] has a [`get` method][get] which uses `Borrow`:
15+
16+
```rust,ignore
17+
fn get<Q: ?Sized>(&self, k: &Q) -> Option<&V>
18+
where K: Borrow<Q>,
19+
Q: Hash + Eq
20+
```
21+
22+
[hashmap]: ../std/collections/struct.HashMap.html
23+
[get]: ../std/collections/struct.HashMap.html#method.get
24+
25+
This signature is pretty complicated. The `K` parameter is what we’re interested
26+
in here. It refers to a parameter of the `HashMap` itself:
27+
28+
```rust,ignore
29+
struct HashMap<K, V, S = RandomState> {
30+
```
31+
32+
The `K` parameter is the type of _key_ the `HashMap` uses. So, looking at
33+
the signature of `get()` again, we can use `get()` when the key implements
34+
`Borrow<Q>`. That way, we can make a `HashMap` which uses `String` keys,
35+
but use `&str`s when we’re searching:
36+
37+
```rust
38+
use std::collections::HashMap;
39+
40+
let mut map = HashMap::new();
41+
map.insert("Foo".to_string(), 42);
42+
43+
assert_eq!(map.get("Foo"), Some(&42));
44+
```
45+
46+
This is because the standard library has `impl Borrow<str> for String`.
47+
48+
For most types, when you want to take an owned or borrowed type, a `&T` is
49+
enough. But one area where `Borrow` is effective is when there’s more than one
50+
kind of borrowed value. Slices are an area where this is especially true: you
51+
can have both an `&[T]` or a `&mut [T]`. If we wanted to accept both of these
52+
types, `Borrow` is up for it:
53+
54+
```
55+
use std::borrow::Borrow;
56+
use std::fmt::Display;
57+
58+
fn foo<T: Borrow<i32> + Display>(a: T) {
59+
println!("a is borrowed: {}", a);
60+
}
61+
62+
let mut i = 5;
63+
64+
foo(&i);
65+
foo(&mut i);
66+
```
67+
68+
This will print out `a is borrowed: 5` twice.
69+
70+
# AsRef
71+
72+
The `AsRef` trait is a conversion trait. It’s used for converting some value to
73+
a reference in generic code. Like this:
74+
75+
```rust
76+
let s = "Hello".to_string();
77+
78+
fn foo<T: AsRef<str>>(s: T) {
79+
let slice = s.as_ref();
80+
}
81+
```
82+
83+
# Which should I use?
84+
85+
We can see how they’re kind of the same: they both deal with owned and borrowed
86+
versions of some type. However, they’re a bit different.
87+
88+
Choose `Borrow` when you want to abstract over different kinds of borrowing, or
89+
when you’re building a datastructure that treats owned and borrowed values in
90+
equivalent ways, such as hashing and comparison.
91+
92+
Choose `AsRef` when you want to convert something to a reference directly, and
93+
you’re writing generic code.

branches/snap-stage3/src/libcollections/borrow.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,11 @@ use self::Cow::*;
3737
/// trait: if `T: Borrow<U>`, then `&U` can be borrowed from `&T`. A given
3838
/// type can be borrowed as multiple different types. In particular, `Vec<T>:
3939
/// Borrow<Vec<T>>` and `Vec<T>: Borrow<[T]>`.
40+
///
41+
/// `Borrow` is very similar to, but different than, `AsRef`. See
42+
/// [the book][book] for more.
43+
///
44+
/// [book]: ../../book/borrow-and-asref.html
4045
#[stable(feature = "rust1", since = "1.0.0")]
4146
pub trait Borrow<Borrowed: ?Sized> {
4247
/// Immutably borrows from an owned value.

branches/snap-stage3/src/libcore/convert.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,11 @@ use marker::Sized;
2424

2525
/// A cheap, reference-to-reference conversion.
2626
///
27+
/// `AsRef` is very similar to, but different than, `Borrow`. See
28+
/// [the book][book] for more.
29+
///
30+
/// [book]: ../../book/borrow-and-asref.html
31+
///
2732
/// # Examples
2833
///
2934
/// Both `String` and `&str` implement `AsRef<str>`:

branches/snap-stage3/src/libcore/slice.rs

Lines changed: 64 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,7 @@ impl<T> SliceExt for [T] {
140140
assume(!p.is_null());
141141
if mem::size_of::<T>() == 0 {
142142
Iter {ptr: p,
143-
end: ((p as usize).wrapping_add(self.len())) as *const T,
143+
end: (p as usize + self.len()) as *const T,
144144
_marker: marker::PhantomData}
145145
} else {
146146
Iter {ptr: p,
@@ -277,7 +277,7 @@ impl<T> SliceExt for [T] {
277277
assume(!p.is_null());
278278
if mem::size_of::<T>() == 0 {
279279
IterMut {ptr: p,
280-
end: ((p as usize).wrapping_add(self.len())) as *mut T,
280+
end: (p as usize + self.len()) as *mut T,
281281
_marker: marker::PhantomData}
282282
} else {
283283
IterMut {ptr: p,
@@ -632,17 +632,35 @@ fn size_from_ptr<T>(_: *const T) -> usize {
632632

633633

634634
// Use macros to be generic over const/mut
635-
macro_rules! slice_offset {
635+
//
636+
// They require non-negative `$by` because otherwise the expression
637+
// `(ptr as usize + $by)` would interpret `-1` as `usize::MAX` (and
638+
// thus trigger a panic when overflow checks are on).
639+
640+
// Use this to do `$ptr + $by`, where `$by` is non-negative.
641+
macro_rules! slice_add_offset {
636642
($ptr:expr, $by:expr) => {{
637643
let ptr = $ptr;
638644
if size_from_ptr(ptr) == 0 {
639-
transmute((ptr as isize).wrapping_add($by))
645+
transmute(ptr as usize + $by)
640646
} else {
641647
ptr.offset($by)
642648
}
643649
}};
644650
}
645651

652+
// Use this to do `$ptr - $by`, where `$by` is non-negative.
653+
macro_rules! slice_sub_offset {
654+
($ptr:expr, $by:expr) => {{
655+
let ptr = $ptr;
656+
if size_from_ptr(ptr) == 0 {
657+
transmute(ptr as usize - $by)
658+
} else {
659+
ptr.offset(-$by)
660+
}
661+
}};
662+
}
663+
646664
macro_rules! slice_ref {
647665
($ptr:expr) => {{
648666
let ptr = $ptr;
@@ -665,24 +683,22 @@ macro_rules! iterator {
665683
#[inline]
666684
fn next(&mut self) -> Option<$elem> {
667685
// could be implemented with slices, but this avoids bounds checks
668-
if self.ptr == self.end {
669-
None
670-
} else {
671-
unsafe {
672-
if mem::size_of::<T>() != 0 {
673-
::intrinsics::assume(!self.ptr.is_null());
674-
::intrinsics::assume(!self.end.is_null());
675-
}
686+
unsafe {
687+
::intrinsics::assume(!self.ptr.is_null());
688+
::intrinsics::assume(!self.end.is_null());
689+
if self.ptr == self.end {
690+
None
691+
} else {
676692
let old = self.ptr;
677-
self.ptr = slice_offset!(self.ptr, 1);
693+
self.ptr = slice_add_offset!(self.ptr, 1);
678694
Some(slice_ref!(old))
679695
}
680696
}
681697
}
682698

683699
#[inline]
684700
fn size_hint(&self) -> (usize, Option<usize>) {
685-
let diff = (self.end as usize).wrapping_sub(self.ptr as usize);
701+
let diff = (self.end as usize) - (self.ptr as usize);
686702
let size = mem::size_of::<T>();
687703
let exact = diff / (if size == 0 {1} else {size});
688704
(exact, Some(exact))
@@ -710,15 +726,13 @@ macro_rules! iterator {
710726
#[inline]
711727
fn next_back(&mut self) -> Option<$elem> {
712728
// could be implemented with slices, but this avoids bounds checks
713-
if self.end == self.ptr {
714-
None
715-
} else {
716-
unsafe {
717-
self.end = slice_offset!(self.end, -1);
718-
if mem::size_of::<T>() != 0 {
719-
::intrinsics::assume(!self.ptr.is_null());
720-
::intrinsics::assume(!self.end.is_null());
721-
}
729+
unsafe {
730+
::intrinsics::assume(!self.ptr.is_null());
731+
::intrinsics::assume(!self.end.is_null());
732+
if self.end == self.ptr {
733+
None
734+
} else {
735+
self.end = slice_sub_offset!(self.end, 1);
722736
Some(slice_ref!(self.end))
723737
}
724738
}
@@ -728,29 +742,29 @@ macro_rules! iterator {
728742
}
729743

730744
macro_rules! make_slice {
731-
($start: expr, $end: expr) => {{
732-
let start = $start;
733-
let diff = ($end as usize).wrapping_sub(start as usize);
734-
if size_from_ptr(start) == 0 {
735-
// use a non-null pointer value
736-
unsafe { from_raw_parts(1 as *const _, diff) }
745+
($t: ty => $result: ty: $start: expr, $end: expr) => {{
746+
let diff = $end as usize - $start as usize;
747+
let len = if mem::size_of::<T>() == 0 {
748+
diff
737749
} else {
738-
let len = diff / size_from_ptr(start);
739-
unsafe { from_raw_parts(start, len) }
750+
diff / mem::size_of::<$t>()
751+
};
752+
unsafe {
753+
from_raw_parts($start, len)
740754
}
741755
}}
742756
}
743757

744758
macro_rules! make_mut_slice {
745-
($start: expr, $end: expr) => {{
746-
let start = $start;
747-
let diff = ($end as usize).wrapping_sub(start as usize);
748-
if size_from_ptr(start) == 0 {
749-
// use a non-null pointer value
750-
unsafe { from_raw_parts_mut(1 as *mut _, diff) }
759+
($t: ty => $result: ty: $start: expr, $end: expr) => {{
760+
let diff = $end as usize - $start as usize;
761+
let len = if mem::size_of::<T>() == 0 {
762+
diff
751763
} else {
752-
let len = diff / size_from_ptr(start);
753-
unsafe { from_raw_parts_mut(start, len) }
764+
diff / mem::size_of::<$t>()
765+
};
766+
unsafe {
767+
from_raw_parts_mut($start, len)
754768
}
755769
}}
756770
}
@@ -773,14 +787,14 @@ impl<'a, T> Iter<'a, T> {
773787
/// iterator can continue to be used while this exists.
774788
#[unstable(feature = "core")]
775789
pub fn as_slice(&self) -> &'a [T] {
776-
make_slice!(self.ptr, self.end)
790+
make_slice!(T => &'a [T]: self.ptr, self.end)
777791
}
778792

779793
// Helper function for Iter::nth
780794
fn iter_nth(&mut self, n: usize) -> Option<&'a T> {
781795
match self.as_slice().get(n) {
782796
Some(elem_ref) => unsafe {
783-
self.ptr = slice_offset!(self.ptr, (n as isize).wrapping_add(1));
797+
self.ptr = slice_add_offset!(elem_ref as *const _, 1);
784798
Some(slice_ref!(elem_ref))
785799
},
786800
None => {
@@ -813,7 +827,12 @@ impl<'a, T> RandomAccessIterator for Iter<'a, T> {
813827
fn idx(&mut self, index: usize) -> Option<&'a T> {
814828
unsafe {
815829
if index < self.indexable() {
816-
Some(slice_ref!(self.ptr.offset(index as isize)))
830+
if mem::size_of::<T>() == 0 {
831+
// Use a non-null pointer value
832+
Some(&mut *(1 as *mut _))
833+
} else {
834+
Some(transmute(self.ptr.offset(index as isize)))
835+
}
817836
} else {
818837
None
819838
}
@@ -841,14 +860,14 @@ impl<'a, T> IterMut<'a, T> {
841860
/// restricted lifetimes that do not consume the iterator.
842861
#[unstable(feature = "core")]
843862
pub fn into_slice(self) -> &'a mut [T] {
844-
make_mut_slice!(self.ptr, self.end)
863+
make_mut_slice!(T => &'a mut [T]: self.ptr, self.end)
845864
}
846865

847866
// Helper function for IterMut::nth
848867
fn iter_nth(&mut self, n: usize) -> Option<&'a mut T> {
849-
match make_mut_slice!(self.ptr, self.end).get_mut(n) {
868+
match make_mut_slice!(T => &'a mut [T]: self.ptr, self.end).get_mut(n) {
850869
Some(elem_ref) => unsafe {
851-
self.ptr = slice_offset!(self.ptr, (n as isize).wrapping_add(1));
870+
self.ptr = slice_add_offset!(elem_ref as *mut _, 1);
852871
Some(slice_ref!(elem_ref))
853872
},
854873
None => {
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
Subproject commit e54d4823d26cdb3f98e5a1b17e1c257cd329aa61
1+
Subproject commit ebc6b04c29591108d3f28e724b4b9b74cd1232e6

0 commit comments

Comments
 (0)