From dbc3cb3a54c02211d8e4f9ff082c4ee2d544ec7d Mon Sep 17 00:00:00 2001 From: Tobias Bucher Date: Tue, 1 Jul 2014 15:10:22 +0200 Subject: [PATCH 1/8] Add support for in-place map for `Vec`s of types with same size This is implemented using a new struct `PartialVec` which implements the proper drop semantics in case the conversion is interrupted by an unwind. --- src/libcollections/vec.rs | 258 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 258 insertions(+) diff --git a/src/libcollections/vec.rs b/src/libcollections/vec.rs index a7005cf454db5..96592798f7a1b 100644 --- a/src/libcollections/vec.rs +++ b/src/libcollections/vec.rs @@ -1710,6 +1710,252 @@ pub mod raw { } } +// TODO: Find some way to statically assert that `T` and `U` have the same +// size. +// +/// An owned, partially type-converted vector. +/// +/// No allocations are performed by usage, only a deallocation happens in the +/// destructor which should only run when unwinding. +/// +/// It can be used to convert a vector of `T`s into a vector of `U`s, by +/// converting the individual elements one-by-one. +/// +/// You may call the `push` method as often as you get a `Some(t)` from `pop`. +/// After pushing the same number of `U`s as you got `T`s, you can `unwrap` the +/// vector. +/// +/// # Example +/// +/// ```rust +/// let pv = PartialVec::new(vec![0u, 1]); +/// assert_eq!(pv.pop(), Some(0)); +/// assert_eq!(pv.pop(), Some(1)); +/// assert_eq!(pv.pop(), None); +/// pv.push(2u); +/// pv.push(3); +/// assert_eq!(pv.unwrap(), vec![2, 3]); +/// ``` +// +// Upheld invariants: +// +// (a) `vec` isn't modified except when the `PartialVec` goes out of scope, the +// only thing it is used for is keeping the memory which the `PartialVec` +// uses for the inplace conversion. +// +// (b) `start_u` points to the start of the vector. +// +// (c) `end_u` points to one element beyond the vector. +// +// (d) `start_u` <= `end_u` <= `start_t` <= `end_t`. +// +// (e) From `start_u` (incl.) to `end_u` (excl.) there are sequential instances +// of type `U`. +// +// (f) From `start_t` (incl.) to `end_t` (excl.) there are sequential instances +// of type `T`. + +pub struct PartialVec { + vec: Vec, + + start_u: *mut U, + end_u: *mut U, + start_t: *mut T, + end_t: *mut T, +} + +impl PartialVec { + /// Creates a `PartialVec` from a `Vec`. + pub fn new(mut vec: Vec) -> PartialVec { + // TODO: do this statically + assert!(mem::size_of::() != 0); + assert!(mem::size_of::() != 0); + assert!(mem::size_of::() == mem::size_of::()); + + let start = vec.as_mut_ptr(); + + // This `as int` cast is safe, because the size of the elements of the + // vector is not 0, and: + // + // 1) If the size of the elements in the vector is 1, the `int` may + // overflow, but it has the correct bit pattern so that the + // `.offset()` function will work. + // + // Example: + // Address space 0x0-0xF. + // `u8` array at: 0x1. + // Size of `u8` array: 0x8. + // Calculated `offset`: -0x8. + // After `array.offset(offset)`: 0x9. + // (0x1 + 0x8 = 0x1 - 0x8) + // + // 2) If the size of the elements in the vector is >1, the `uint` -> + // `int` conversion can't overflow. + let offset = vec.len() as int; + + let start_u = start as *mut U; + let end_u = start as *mut U; + let start_t = start; + let end_t = unsafe { start_t.offset(offset) }; + + // (b) is satisfied, `start_u` points to the start of `vec`. + + // (c) is also satisfied, `end_t` points to the end of `vec`. + + // `start_u == end_u == start_t <= end_t`, so also `start_u <= end_u <= + // start_t <= end_t`, thus (b). + + // As `start_u == end_u`, it is represented correctly that there are no + // instances of `U` in `vec`, thus (e) is satisfied. + + // At start, there are only elements of type `T` in `vec`, so (f) is + // satisfied, as `start_t` points to the start of `vec` and `end_t` to + // the end of it. + + // This points inside the vector, as the vector has length `offset`. + + PartialVec { + // (a) is satisfied, `vec` isn't modified in the function. + vec: vec, + start_u: start_u, + end_u: end_u, + start_t: start_t, + end_t: end_t, + } + } + + /// Pops a `T` from the `PartialVec`. + /// + /// Returns `Some(t)` if there are more `T`s in the vector, otherwise + /// `None`. + fn pop(&mut self) -> Option { + // The `if` ensures that there are more `T`s in `vec`. + if self.start_t < self.end_t { + let result; + unsafe { + // (f) is satisfied before, so in this if branch there actually + // is a `T` at `start_t`. After shifting the pointer by one, + // (f) is again satisfied. + result = ptr::read(self.start_t as *const T); + self.start_t = self.start_t.offset(1); + } + Some(result) + } else { + None + } + } + + /// Pushes a new `U` to the `PartialVec`. + /// + /// # Failure + /// + /// Fails if not enough `T`s were popped to have enough space for the new + /// `U`. + pub fn push(&mut self, value: U) { + // The assert assures that still `end_u <= start_t` (d) after + // the function. + assert!(self.end_u as *const () < self.start_t as *const (), + "writing more elements to PartialVec than reading from it") + unsafe { + // (e) is satisfied before, and after writing one `U` + // to `end_u` and shifting it by one, it's again + // satisfied. + ptr::write(self.end_u, value); + self.end_u = self.end_u.offset(1); + } + } + + /// Unwraps the new `Vec` of `U`s after having pushed enough `U`s and + /// popped all `T`s. + /// + /// # Failure + /// + /// Fails if not all `T`s were popped, also fails if not the same amount of + /// `U`s was pushed before calling `unwrap`. + pub fn unwrap(self) -> Vec { + // If `self.end_u == self.end_t`, we know from (e) that there are no + // more `T`s in `vec`, we also know that the whole length of `vec` is + // now used by `U`s, thus we can just transmute `vec` from a vector of + // `T`s to a vector of `U`s safely. + + assert!(self.end_u as *const () == self.end_t as *const (), + "trying to unwrap a PartialVec before completing the writes to it"); + + // Extract `vec` and prevent the destructor of `PartialVec` from + // running. + unsafe { + let vec = ptr::read(&self.vec); + mem::forget(self); + mem::transmute(vec) + } + } +} + +#[unsafe_destructor] +impl Drop for PartialVec { + fn drop(&mut self) { + unsafe { + // As per (a) `vec` hasn't been modified until now. As it has a + // length currently, this would run destructors of `T`s which might + // not be there. So at first, set `vec`s length to `0`. This must + // be done at first to remain memory-safe as the destructors of `U` + // or `T` might cause unwinding where `vec`s destructor would be + // executed. + self.vec.set_len(0); + + // As per (e) and (f) we have instances of `U`s and `T`s in `vec`. + // Destruct them. + while self.start_u < self.end_u { + let _ = ptr::read(self.start_u as *const U); // Run a `U` destructor. + self.start_u = self.start_u.offset(1); + } + while self.start_t < self.end_t { + let _ = ptr::read(self.start_t as *const T); // Run a `T` destructor. + self.start_t = self.start_t.offset(1); + } + // After this destructor ran, the destructor of `vec` will run, + // deallocating the underlying memory. + } + } +} + +impl Iterator for PartialVec { + fn next(&mut self) -> Option { + self.pop() + } +} + +impl Vec { + /// Converts a `Vec` to a `Vec` where `T` and `U` have the same size. + /// + /// # Example + /// + /// ```rust + /// let v = vec![0u, 1, 2]; + /// let w = v.map_inplace(|i| i + 3); + /// assert_eq!(w.as_slice() == &[3, 4, 5]); + /// + /// let big_endian_u16s = vec![0x1122u16, 0x3344]; + /// let u8s = big_endian_u16s.map_inplace(|x| [ + /// ((x >> 8) & 0xff) as u8, + /// (x & 0xff) as u8 + /// ]); + /// assert_eq!(u8s.as_slice() == &[[0x11, 0x22], [0x33, 0x44]]); + /// ``` + pub fn map_inplace(self, f: |T| -> U) -> Vec { + let mut pv = PartialVec::new(self); + loop { + // TODO: need this extra assignment for borrowck to pass + let maybe_t = pv.pop(); + match maybe_t { + Some(t) => pv.push(f(t)), + None => return pv.unwrap(), + }; + } + } +} + + #[cfg(test)] mod tests { extern crate test; @@ -2039,6 +2285,18 @@ mod tests { assert_eq!(vec.as_ptr(), ptr); assert_eq!(vec.capacity(), 7); assert_eq!(vec.len(), 0); + + #[test] + #[should_fail] + fn test_map_inplace_incompatible_types_fail() { + let v = vec![0u, 1, 2]; + v.map_inplace(|_| ()); + } + + #[test] + fn test_map_inplace() { + let v = vec![0u, 1, 2]; + assert_eq!(v.map_inplace(|i: uint| i as int - 1).as_slice, &[-1i, 0, 1]); } #[bench] From af293372e4ea9578840338bdd1b765bfc3c80352 Mon Sep 17 00:00:00 2001 From: Tobias Bucher Date: Wed, 2 Jul 2014 00:17:28 +0200 Subject: [PATCH 2/8] PartialVec: Remove TODOs and rename `unwrap` to `into_vec` --- src/libcollections/vec.rs | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/src/libcollections/vec.rs b/src/libcollections/vec.rs index 96592798f7a1b..488661d2e8b5b 100644 --- a/src/libcollections/vec.rs +++ b/src/libcollections/vec.rs @@ -1710,9 +1710,6 @@ pub mod raw { } } -// TODO: Find some way to statically assert that `T` and `U` have the same -// size. -// /// An owned, partially type-converted vector. /// /// No allocations are performed by usage, only a deallocation happens in the @@ -1734,7 +1731,7 @@ pub mod raw { /// assert_eq!(pv.pop(), None); /// pv.push(2u); /// pv.push(3); -/// assert_eq!(pv.unwrap(), vec![2, 3]); +/// assert_eq!(pv.into_vec(), vec![2, 3]); /// ``` // // Upheld invariants: @@ -1767,7 +1764,7 @@ pub struct PartialVec { impl PartialVec { /// Creates a `PartialVec` from a `Vec`. pub fn new(mut vec: Vec) -> PartialVec { - // TODO: do this statically + // FIXME: Assert that the types `T` and `U` have the same size. assert!(mem::size_of::() != 0); assert!(mem::size_of::() != 0); assert!(mem::size_of::() == mem::size_of::()); @@ -1872,7 +1869,7 @@ impl PartialVec { /// /// Fails if not all `T`s were popped, also fails if not the same amount of /// `U`s was pushed before calling `unwrap`. - pub fn unwrap(self) -> Vec { + pub fn into_vec(self) -> Vec { // If `self.end_u == self.end_t`, we know from (e) that there are no // more `T`s in `vec`, we also know that the whole length of `vec` is // now used by `U`s, thus we can just transmute `vec` from a vector of @@ -1945,11 +1942,10 @@ impl Vec { pub fn map_inplace(self, f: |T| -> U) -> Vec { let mut pv = PartialVec::new(self); loop { - // TODO: need this extra assignment for borrowck to pass let maybe_t = pv.pop(); match maybe_t { Some(t) => pv.push(f(t)), - None => return pv.unwrap(), + None => return pv.into_vec(), }; } } From 23f2c78d21440a8699cfa917b422795b5ec4adc7 Mon Sep 17 00:00:00 2001 From: Tobias Bucher Date: Sun, 3 Aug 2014 14:16:10 +0200 Subject: [PATCH 3/8] Fix some of the issues mentioned in the PR on Github This specifically includes: - Fix of the tests - Remove `transmute` between `Vec`s of different types --- src/libcollections/vec.rs | 65 ++++++++++++++++++++++++++------------- 1 file changed, 43 insertions(+), 22 deletions(-) diff --git a/src/libcollections/vec.rs b/src/libcollections/vec.rs index 488661d2e8b5b..e04eadb084fb0 100644 --- a/src/libcollections/vec.rs +++ b/src/libcollections/vec.rs @@ -1712,6 +1712,9 @@ pub mod raw { /// An owned, partially type-converted vector. /// +/// This struct takes two type parameters `T` and `U` which must be of the +/// same, non-zero size. +/// /// No allocations are performed by usage, only a deallocation happens in the /// destructor which should only run when unwinding. /// @@ -1725,13 +1728,13 @@ pub mod raw { /// # Example /// /// ```rust -/// let pv = PartialVec::new(vec![0u, 1]); +/// let pv = PartialVec::from_vec(vec![0u, 1]); /// assert_eq!(pv.pop(), Some(0)); /// assert_eq!(pv.pop(), Some(1)); /// assert_eq!(pv.pop(), None); /// pv.push(2u); /// pv.push(3); -/// assert_eq!(pv.into_vec(), vec![2, 3]); +/// assert_eq!(pv.into_vec().as_slice(), &[2, 3]); /// ``` // // Upheld invariants: @@ -1751,6 +1754,8 @@ pub mod raw { // // (f) From `start_t` (incl.) to `end_t` (excl.) there are sequential instances // of type `T`. +// +// (g) The size of `T` and `U` is equal and non-zero. pub struct PartialVec { vec: Vec, @@ -1763,8 +1768,14 @@ pub struct PartialVec { impl PartialVec { /// Creates a `PartialVec` from a `Vec`. - pub fn new(mut vec: Vec) -> PartialVec { + /// + /// # Failure + /// + /// Fails if `T` and `U` have differing sizes or are zero-sized. + pub fn from_vec(mut vec: Vec) -> PartialVec { // FIXME: Assert that the types `T` and `U` have the same size. + // + // These asserts make sure (g) is satisfied. assert!(mem::size_of::() != 0); assert!(mem::size_of::() != 0); assert!(mem::size_of::() == mem::size_of::()); @@ -1793,24 +1804,24 @@ impl PartialVec { let start_u = start as *mut U; let end_u = start as *mut U; let start_t = start; + + // This points inside the vector, as the vector has length `offset`. let end_t = unsafe { start_t.offset(offset) }; // (b) is satisfied, `start_u` points to the start of `vec`. - + // // (c) is also satisfied, `end_t` points to the end of `vec`. - + // // `start_u == end_u == start_t <= end_t`, so also `start_u <= end_u <= // start_t <= end_t`, thus (b). - + // // As `start_u == end_u`, it is represented correctly that there are no // instances of `U` in `vec`, thus (e) is satisfied. - + // // At start, there are only elements of type `T` in `vec`, so (f) is // satisfied, as `start_t` points to the start of `vec` and `end_t` to // the end of it. - // This points inside the vector, as the vector has length `offset`. - PartialVec { // (a) is satisfied, `vec` isn't modified in the function. vec: vec, @@ -1823,8 +1834,8 @@ impl PartialVec { /// Pops a `T` from the `PartialVec`. /// - /// Returns `Some(t)` if there are more `T`s in the vector, otherwise - /// `None`. + /// Removes the next `T` from the vector and returns it as `Some(T)`, or + /// `None` if there are none left. fn pop(&mut self) -> Option { // The `if` ensures that there are more `T`s in `vec`. if self.start_t < self.end_t { @@ -1869,21 +1880,26 @@ impl PartialVec { /// /// Fails if not all `T`s were popped, also fails if not the same amount of /// `U`s was pushed before calling `unwrap`. - pub fn into_vec(self) -> Vec { + pub fn into_vec(mut self) -> Vec { // If `self.end_u == self.end_t`, we know from (e) that there are no // more `T`s in `vec`, we also know that the whole length of `vec` is - // now used by `U`s, thus we can just transmute `vec` from a vector of - // `T`s to a vector of `U`s safely. + // now used by `U`s, thus we can just interpret `vec` as a vector of + // `U` safely. assert!(self.end_u as *const () == self.end_t as *const (), "trying to unwrap a PartialVec before completing the writes to it"); // Extract `vec` and prevent the destructor of `PartialVec` from - // running. + // running. Note that none of the function calls can fail, thus no + // resources can be leaked (as the `vec` member of `PartialVec` is the + // only one which holds allocations -- and it is returned from this + // function. unsafe { - let vec = ptr::read(&self.vec); + let vec_len = self.vec.len(); + let vec_cap = self.vec.capacity(); + let vec_ptr = self.vec.as_mut_ptr() as *mut U; mem::forget(self); - mem::transmute(vec) + Vec::from_raw_parts(vec_len, vec_cap, vec_ptr) } } } @@ -1923,24 +1939,29 @@ impl Iterator for PartialVec { } impl Vec { - /// Converts a `Vec` to a `Vec` where `T` and `U` have the same size. + /// Converts a `Vec` to a `Vec` where `T` and `U` have the same + /// non-zero size. + /// + /// # Failure + /// + /// Fails if `T` and `U` have differing sizes or are zero-sized. /// /// # Example /// /// ```rust /// let v = vec![0u, 1, 2]; /// let w = v.map_inplace(|i| i + 3); - /// assert_eq!(w.as_slice() == &[3, 4, 5]); + /// assert_eq!(w.as_slice(), &[3, 4, 5]); /// /// let big_endian_u16s = vec![0x1122u16, 0x3344]; /// let u8s = big_endian_u16s.map_inplace(|x| [ /// ((x >> 8) & 0xff) as u8, /// (x & 0xff) as u8 /// ]); - /// assert_eq!(u8s.as_slice() == &[[0x11, 0x22], [0x33, 0x44]]); + /// assert_eq!(u8s.as_slice(), &[[0x11, 0x22], [0x33, 0x44]]); /// ``` pub fn map_inplace(self, f: |T| -> U) -> Vec { - let mut pv = PartialVec::new(self); + let mut pv = PartialVec::from_vec(self); loop { let maybe_t = pv.pop(); match maybe_t { @@ -2292,7 +2313,7 @@ mod tests { #[test] fn test_map_inplace() { let v = vec![0u, 1, 2]; - assert_eq!(v.map_inplace(|i: uint| i as int - 1).as_slice, &[-1i, 0, 1]); + assert_eq!(v.map_inplace(|i: uint| i as int - 1).as_slice(), &[-1i, 0, 1]); } #[bench] From 5efa232160ff07de55cc0f62bfafdedb683789db Mon Sep 17 00:00:00 2001 From: Tobias Bucher Date: Fri, 8 Aug 2014 23:52:15 +0200 Subject: [PATCH 4/8] Check that the `min_align_of` the both types in a `PartialVec` matches This is important because the underlying allocator of the `Vec` passes that information to the deallocator which needs the guarantee that it is the same parameters that were also passed to the allocation function. --- src/libcollections/vec.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/libcollections/vec.rs b/src/libcollections/vec.rs index e04eadb084fb0..1e08b3e1d19c3 100644 --- a/src/libcollections/vec.rs +++ b/src/libcollections/vec.rs @@ -1756,6 +1756,8 @@ pub mod raw { // of type `T`. // // (g) The size of `T` and `U` is equal and non-zero. +// +// (h) The `min_align_of` of `T` and `U` is equal. pub struct PartialVec { vec: Vec, @@ -1773,12 +1775,14 @@ impl PartialVec { /// /// Fails if `T` and `U` have differing sizes or are zero-sized. pub fn from_vec(mut vec: Vec) -> PartialVec { - // FIXME: Assert that the types `T` and `U` have the same size. + // FIXME: Assert statically that the types `T` and `U` have the same + // size. // - // These asserts make sure (g) is satisfied. + // These asserts make sure (g) and (h) are satisfied. assert!(mem::size_of::() != 0); assert!(mem::size_of::() != 0); assert!(mem::size_of::() == mem::size_of::()); + assert!(mem::min_align_of::() == mem::min_align_of::()); let start = vec.as_mut_ptr(); From b7e0969a4953f5fe63497aa2c4caed226c94175c Mon Sep 17 00:00:00 2001 From: Tobias Bucher Date: Thu, 11 Sep 2014 02:04:51 +0200 Subject: [PATCH 5/8] Minimize the public interface and rename it to `map_in_place` --- src/libcollections/vec.rs | 40 ++++++++++++++++++++------------------- 1 file changed, 21 insertions(+), 19 deletions(-) diff --git a/src/libcollections/vec.rs b/src/libcollections/vec.rs index 1e08b3e1d19c3..e81c3b5a188b3 100644 --- a/src/libcollections/vec.rs +++ b/src/libcollections/vec.rs @@ -1713,7 +1713,7 @@ pub mod raw { /// An owned, partially type-converted vector. /// /// This struct takes two type parameters `T` and `U` which must be of the -/// same, non-zero size. +/// same, non-zero size having the same minimal alignment. /// /// No allocations are performed by usage, only a deallocation happens in the /// destructor which should only run when unwinding. @@ -1727,12 +1727,12 @@ pub mod raw { /// /// # Example /// -/// ```rust -/// let pv = PartialVec::from_vec(vec![0u, 1]); +/// ```ignore +/// let pv = PartialVec::from_vec(vec![0u32, 1]); /// assert_eq!(pv.pop(), Some(0)); /// assert_eq!(pv.pop(), Some(1)); /// assert_eq!(pv.pop(), None); -/// pv.push(2u); +/// pv.push(2u32); /// pv.push(3); /// assert_eq!(pv.into_vec().as_slice(), &[2, 3]); /// ``` @@ -1759,7 +1759,7 @@ pub mod raw { // // (h) The `min_align_of` of `T` and `U` is equal. -pub struct PartialVec { +struct PartialVec { vec: Vec, start_u: *mut U, @@ -1773,8 +1773,9 @@ impl PartialVec { /// /// # Failure /// - /// Fails if `T` and `U` have differing sizes or are zero-sized. - pub fn from_vec(mut vec: Vec) -> PartialVec { + /// Fails if `T` and `U` have differing sizes, are zero-sized or have + /// differing minimal alignments. + fn from_vec(mut vec: Vec) -> PartialVec { // FIXME: Assert statically that the types `T` and `U` have the same // size. // @@ -1863,7 +1864,7 @@ impl PartialVec { /// /// Fails if not enough `T`s were popped to have enough space for the new /// `U`. - pub fn push(&mut self, value: U) { + fn push(&mut self, value: U) { // The assert assures that still `end_u <= start_t` (d) after // the function. assert!(self.end_u as *const () < self.start_t as *const (), @@ -1884,7 +1885,7 @@ impl PartialVec { /// /// Fails if not all `T`s were popped, also fails if not the same amount of /// `U`s was pushed before calling `unwrap`. - pub fn into_vec(mut self) -> Vec { + fn into_vec(mut self) -> Vec { // If `self.end_u == self.end_t`, we know from (e) that there are no // more `T`s in `vec`, we also know that the whole length of `vec` is // now used by `U`s, thus we can just interpret `vec` as a vector of @@ -1944,27 +1945,28 @@ impl Iterator for PartialVec { impl Vec { /// Converts a `Vec` to a `Vec` where `T` and `U` have the same - /// non-zero size. + /// non-zero size and the same minimal alignment. /// /// # Failure /// - /// Fails if `T` and `U` have differing sizes or are zero-sized. + /// Fails if `T` and `U` have differing sizes, are zero-sized or have + /// differing minimal alignments. /// /// # Example /// - /// ```rust + /// ``` /// let v = vec![0u, 1, 2]; - /// let w = v.map_inplace(|i| i + 3); + /// let w = v.map_in_place(|i| i + 3); /// assert_eq!(w.as_slice(), &[3, 4, 5]); /// /// let big_endian_u16s = vec![0x1122u16, 0x3344]; - /// let u8s = big_endian_u16s.map_inplace(|x| [ + /// let u8s = big_endian_u16s.map_in_place(|x| [ /// ((x >> 8) & 0xff) as u8, /// (x & 0xff) as u8 /// ]); /// assert_eq!(u8s.as_slice(), &[[0x11, 0x22], [0x33, 0x44]]); /// ``` - pub fn map_inplace(self, f: |T| -> U) -> Vec { + pub fn map_in_place(self, f: |T| -> U) -> Vec { let mut pv = PartialVec::from_vec(self); loop { let maybe_t = pv.pop(); @@ -2309,15 +2311,15 @@ mod tests { #[test] #[should_fail] - fn test_map_inplace_incompatible_types_fail() { + fn test_map_inp_lace_incompatible_types_fail() { let v = vec![0u, 1, 2]; - v.map_inplace(|_| ()); + v.map_in_place(|_| ()); } #[test] - fn test_map_inplace() { + fn test_map_in_place() { let v = vec![0u, 1, 2]; - assert_eq!(v.map_inplace(|i: uint| i as int - 1).as_slice(), &[-1i, 0, 1]); + assert_eq!(v.map_in_place(|i: uint| i as int - 1).as_slice(), &[-1i, 0, 1]); } #[bench] From 79427f0bc0fff258eae966aa1db5abc089a88aa0 Mon Sep 17 00:00:00 2001 From: Tobias Bucher Date: Fri, 12 Sep 2014 20:18:26 +0200 Subject: [PATCH 6/8] Remove the unused `Iterator` implementation of the private `PartialVec` --- src/libcollections/vec.rs | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/libcollections/vec.rs b/src/libcollections/vec.rs index e81c3b5a188b3..be286cbda1e46 100644 --- a/src/libcollections/vec.rs +++ b/src/libcollections/vec.rs @@ -1937,12 +1937,6 @@ impl Drop for PartialVec { } } -impl Iterator for PartialVec { - fn next(&mut self) -> Option { - self.pop() - } -} - impl Vec { /// Converts a `Vec` to a `Vec` where `T` and `U` have the same /// non-zero size and the same minimal alignment. From 7ccab3ae8aeb1b0d7002187990aaa56b1ff03d28 Mon Sep 17 00:00:00 2001 From: Tobias Bucher Date: Sat, 13 Sep 2014 01:38:16 +0200 Subject: [PATCH 7/8] Added missing `}` from `map_in_place` rebase --- src/libcollections/vec.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/libcollections/vec.rs b/src/libcollections/vec.rs index be286cbda1e46..e45eeed571a7c 100644 --- a/src/libcollections/vec.rs +++ b/src/libcollections/vec.rs @@ -2302,6 +2302,7 @@ mod tests { assert_eq!(vec.as_ptr(), ptr); assert_eq!(vec.capacity(), 7); assert_eq!(vec.len(), 0); + } #[test] #[should_fail] From 2c7f6eee0c6a3d5b67e523aa5c8dc0bd27cf8c4b Mon Sep 17 00:00:00 2001 From: Tobias Bucher Date: Sun, 14 Sep 2014 21:33:48 +0200 Subject: [PATCH 8/8] Fixed `map_in_place` tests after rustc upgrade This replaces the now obsolete syntax `&[]` with `[].as_slice()`. --- src/libcollections/vec.rs | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/src/libcollections/vec.rs b/src/libcollections/vec.rs index e45eeed571a7c..6fc367474bb7b 100644 --- a/src/libcollections/vec.rs +++ b/src/libcollections/vec.rs @@ -1951,14 +1951,13 @@ impl Vec { /// ``` /// let v = vec![0u, 1, 2]; /// let w = v.map_in_place(|i| i + 3); - /// assert_eq!(w.as_slice(), &[3, 4, 5]); + /// assert_eq!(w.as_slice(), [3, 4, 5].as_slice()); /// - /// let big_endian_u16s = vec![0x1122u16, 0x3344]; - /// let u8s = big_endian_u16s.map_in_place(|x| [ - /// ((x >> 8) & 0xff) as u8, - /// (x & 0xff) as u8 - /// ]); - /// assert_eq!(u8s.as_slice(), &[[0x11, 0x22], [0x33, 0x44]]); + /// #[deriving(PartialEq, Show)] + /// struct Newtype(u8); + /// let bytes = vec![0x11, 0x22]; + /// let newtyped_bytes = bytes.map_in_place(|x| Newtype(x)); + /// assert_eq!(newtyped_bytes.as_slice(), [Newtype(0x11), Newtype(0x22)].as_slice()); /// ``` pub fn map_in_place(self, f: |T| -> U) -> Vec { let mut pv = PartialVec::from_vec(self); @@ -2314,7 +2313,7 @@ mod tests { #[test] fn test_map_in_place() { let v = vec![0u, 1, 2]; - assert_eq!(v.map_in_place(|i: uint| i as int - 1).as_slice(), &[-1i, 0, 1]); + assert_eq!(v.map_in_place(|i: uint| i as int - 1).as_slice(), [-1i, 0, 1].as_slice()); } #[bench]