@@ -1710,6 +1710,252 @@ pub mod raw {
17101710 }
17111711}
17121712
1713+ // TODO: Find some way to statically assert that `T` and `U` have the same
1714+ // size.
1715+ //
1716+ /// An owned, partially type-converted vector.
1717+ ///
1718+ /// No allocations are performed by usage, only a deallocation happens in the
1719+ /// destructor which should only run when unwinding.
1720+ ///
1721+ /// It can be used to convert a vector of `T`s into a vector of `U`s, by
1722+ /// converting the individual elements one-by-one.
1723+ ///
1724+ /// You may call the `push` method as often as you get a `Some(t)` from `pop`.
1725+ /// After pushing the same number of `U`s as you got `T`s, you can `unwrap` the
1726+ /// vector.
1727+ ///
1728+ /// # Example
1729+ ///
1730+ /// ```rust
1731+ /// let pv = PartialVec::new(vec![0u, 1]);
1732+ /// assert_eq!(pv.pop(), Some(0));
1733+ /// assert_eq!(pv.pop(), Some(1));
1734+ /// assert_eq!(pv.pop(), None);
1735+ /// pv.push(2u);
1736+ /// pv.push(3);
1737+ /// assert_eq!(pv.unwrap(), vec![2, 3]);
1738+ /// ```
1739+ //
1740+ // Upheld invariants:
1741+ //
1742+ // (a) `vec` isn't modified except when the `PartialVec` goes out of scope, the
1743+ // only thing it is used for is keeping the memory which the `PartialVec`
1744+ // uses for the inplace conversion.
1745+ //
1746+ // (b) `start_u` points to the start of the vector.
1747+ //
1748+ // (c) `end_u` points to one element beyond the vector.
1749+ //
1750+ // (d) `start_u` <= `end_u` <= `start_t` <= `end_t`.
1751+ //
1752+ // (e) From `start_u` (incl.) to `end_u` (excl.) there are sequential instances
1753+ // of type `U`.
1754+ //
1755+ // (f) From `start_t` (incl.) to `end_t` (excl.) there are sequential instances
1756+ // of type `T`.
1757+
1758+ pub struct PartialVec < T , U > {
1759+ vec : Vec < T > ,
1760+
1761+ start_u : * mut U ,
1762+ end_u : * mut U ,
1763+ start_t : * mut T ,
1764+ end_t : * mut T ,
1765+ }
1766+
1767+ impl < T , U > PartialVec < T , U > {
1768+ /// Creates a `PartialVec` from a `Vec`.
1769+ pub fn new ( mut vec : Vec < T > ) -> PartialVec < T , U > {
1770+ // TODO: do this statically
1771+ assert ! ( mem:: size_of:: <T >( ) != 0 ) ;
1772+ assert ! ( mem:: size_of:: <U >( ) != 0 ) ;
1773+ assert ! ( mem:: size_of:: <T >( ) == mem:: size_of:: <U >( ) ) ;
1774+
1775+ let start = vec. as_mut_ptr ( ) ;
1776+
1777+ // This `as int` cast is safe, because the size of the elements of the
1778+ // vector is not 0, and:
1779+ //
1780+ // 1) If the size of the elements in the vector is 1, the `int` may
1781+ // overflow, but it has the correct bit pattern so that the
1782+ // `.offset()` function will work.
1783+ //
1784+ // Example:
1785+ // Address space 0x0-0xF.
1786+ // `u8` array at: 0x1.
1787+ // Size of `u8` array: 0x8.
1788+ // Calculated `offset`: -0x8.
1789+ // After `array.offset(offset)`: 0x9.
1790+ // (0x1 + 0x8 = 0x1 - 0x8)
1791+ //
1792+ // 2) If the size of the elements in the vector is >1, the `uint` ->
1793+ // `int` conversion can't overflow.
1794+ let offset = vec. len ( ) as int ;
1795+
1796+ let start_u = start as * mut U ;
1797+ let end_u = start as * mut U ;
1798+ let start_t = start;
1799+ let end_t = unsafe { start_t. offset ( offset) } ;
1800+
1801+ // (b) is satisfied, `start_u` points to the start of `vec`.
1802+
1803+ // (c) is also satisfied, `end_t` points to the end of `vec`.
1804+
1805+ // `start_u == end_u == start_t <= end_t`, so also `start_u <= end_u <=
1806+ // start_t <= end_t`, thus (b).
1807+
1808+ // As `start_u == end_u`, it is represented correctly that there are no
1809+ // instances of `U` in `vec`, thus (e) is satisfied.
1810+
1811+ // At start, there are only elements of type `T` in `vec`, so (f) is
1812+ // satisfied, as `start_t` points to the start of `vec` and `end_t` to
1813+ // the end of it.
1814+
1815+ // This points inside the vector, as the vector has length `offset`.
1816+
1817+ PartialVec {
1818+ // (a) is satisfied, `vec` isn't modified in the function.
1819+ vec : vec,
1820+ start_u : start_u,
1821+ end_u : end_u,
1822+ start_t : start_t,
1823+ end_t : end_t,
1824+ }
1825+ }
1826+
1827+ /// Pops a `T` from the `PartialVec`.
1828+ ///
1829+ /// Returns `Some(t)` if there are more `T`s in the vector, otherwise
1830+ /// `None`.
1831+ fn pop ( & mut self ) -> Option < T > {
1832+ // The `if` ensures that there are more `T`s in `vec`.
1833+ if self . start_t < self . end_t {
1834+ let result;
1835+ unsafe {
1836+ // (f) is satisfied before, so in this if branch there actually
1837+ // is a `T` at `start_t`. After shifting the pointer by one,
1838+ // (f) is again satisfied.
1839+ result = ptr:: read ( self . start_t as * const T ) ;
1840+ self . start_t = self . start_t . offset ( 1 ) ;
1841+ }
1842+ Some ( result)
1843+ } else {
1844+ None
1845+ }
1846+ }
1847+
1848+ /// Pushes a new `U` to the `PartialVec`.
1849+ ///
1850+ /// # Failure
1851+ ///
1852+ /// Fails if not enough `T`s were popped to have enough space for the new
1853+ /// `U`.
1854+ pub fn push ( & mut self , value : U ) {
1855+ // The assert assures that still `end_u <= start_t` (d) after
1856+ // the function.
1857+ assert ! ( self . end_u as * const ( ) < self . start_t as * const ( ) ,
1858+ "writing more elements to PartialVec than reading from it" )
1859+ unsafe {
1860+ // (e) is satisfied before, and after writing one `U`
1861+ // to `end_u` and shifting it by one, it's again
1862+ // satisfied.
1863+ ptr:: write ( self . end_u , value) ;
1864+ self . end_u = self . end_u . offset ( 1 ) ;
1865+ }
1866+ }
1867+
1868+ /// Unwraps the new `Vec` of `U`s after having pushed enough `U`s and
1869+ /// popped all `T`s.
1870+ ///
1871+ /// # Failure
1872+ ///
1873+ /// Fails if not all `T`s were popped, also fails if not the same amount of
1874+ /// `U`s was pushed before calling `unwrap`.
1875+ pub fn unwrap ( self ) -> Vec < U > {
1876+ // If `self.end_u == self.end_t`, we know from (e) that there are no
1877+ // more `T`s in `vec`, we also know that the whole length of `vec` is
1878+ // now used by `U`s, thus we can just transmute `vec` from a vector of
1879+ // `T`s to a vector of `U`s safely.
1880+
1881+ assert ! ( self . end_u as * const ( ) == self . end_t as * const ( ) ,
1882+ "trying to unwrap a PartialVec before completing the writes to it" ) ;
1883+
1884+ // Extract `vec` and prevent the destructor of `PartialVec` from
1885+ // running.
1886+ unsafe {
1887+ let vec = ptr:: read ( & self . vec ) ;
1888+ mem:: forget ( self ) ;
1889+ mem:: transmute ( vec)
1890+ }
1891+ }
1892+ }
1893+
1894+ #[ unsafe_destructor]
1895+ impl < T , U > Drop for PartialVec < T , U > {
1896+ fn drop ( & mut self ) {
1897+ unsafe {
1898+ // As per (a) `vec` hasn't been modified until now. As it has a
1899+ // length currently, this would run destructors of `T`s which might
1900+ // not be there. So at first, set `vec`s length to `0`. This must
1901+ // be done at first to remain memory-safe as the destructors of `U`
1902+ // or `T` might cause unwinding where `vec`s destructor would be
1903+ // executed.
1904+ self . vec . set_len ( 0 ) ;
1905+
1906+ // As per (e) and (f) we have instances of `U`s and `T`s in `vec`.
1907+ // Destruct them.
1908+ while self . start_u < self . end_u {
1909+ let _ = ptr:: read ( self . start_u as * const U ) ; // Run a `U` destructor.
1910+ self . start_u = self . start_u . offset ( 1 ) ;
1911+ }
1912+ while self . start_t < self . end_t {
1913+ let _ = ptr:: read ( self . start_t as * const T ) ; // Run a `T` destructor.
1914+ self . start_t = self . start_t . offset ( 1 ) ;
1915+ }
1916+ // After this destructor ran, the destructor of `vec` will run,
1917+ // deallocating the underlying memory.
1918+ }
1919+ }
1920+ }
1921+
1922+ impl < T , U > Iterator < T > for PartialVec < T , U > {
1923+ fn next ( & mut self ) -> Option < T > {
1924+ self . pop ( )
1925+ }
1926+ }
1927+
1928+ impl < T > Vec < T > {
1929+ /// Converts a `Vec<T>` to a `Vec<U>` where `T` and `U` have the same size.
1930+ ///
1931+ /// # Example
1932+ ///
1933+ /// ```rust
1934+ /// let v = vec![0u, 1, 2];
1935+ /// let w = v.map_inplace(|i| i + 3);
1936+ /// assert_eq!(w.as_slice() == &[3, 4, 5]);
1937+ ///
1938+ /// let big_endian_u16s = vec![0x1122u16, 0x3344];
1939+ /// let u8s = big_endian_u16s.map_inplace(|x| [
1940+ /// ((x >> 8) & 0xff) as u8,
1941+ /// (x & 0xff) as u8
1942+ /// ]);
1943+ /// assert_eq!(u8s.as_slice() == &[[0x11, 0x22], [0x33, 0x44]]);
1944+ /// ```
1945+ pub fn map_inplace < U > ( self , f: |T | -> U ) -> Vec < U > {
1946+ let mut pv = PartialVec :: new ( self ) ;
1947+ loop {
1948+ // TODO: need this extra assignment for borrowck to pass
1949+ let maybe_t = pv. pop ( ) ;
1950+ match maybe_t {
1951+ Some ( t) => pv. push ( f ( t) ) ,
1952+ None => return pv. unwrap ( ) ,
1953+ } ;
1954+ }
1955+ }
1956+ }
1957+
1958+
17131959#[ cfg( test) ]
17141960mod tests {
17151961 extern crate test;
@@ -2039,6 +2285,18 @@ mod tests {
20392285 assert_eq ! ( vec. as_ptr( ) , ptr) ;
20402286 assert_eq ! ( vec. capacity( ) , 7 ) ;
20412287 assert_eq ! ( vec. len( ) , 0 ) ;
2288+
2289+ #[ test]
2290+ #[ should_fail]
2291+ fn test_map_inplace_incompatible_types_fail ( ) {
2292+ let v = vec ! [ 0 u, 1 , 2 ] ;
2293+ v. map_inplace ( |_| ( ) ) ;
2294+ }
2295+
2296+ #[ test]
2297+ fn test_map_inplace ( ) {
2298+ let v = vec ! [ 0 u, 1 , 2 ] ;
2299+ assert_eq ! ( v. map_inplace( |i: uint| i as int - 1 ) . as_slice, & [ -1 i, 0 , 1 ] ) ;
20422300 }
20432301
20442302 #[ bench]
0 commit comments