@@ -1710,6 +1710,252 @@ pub mod raw {
1710
1710
}
1711
1711
}
1712
1712
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
+
1713
1959
#[ cfg( test) ]
1714
1960
mod tests {
1715
1961
extern crate test;
@@ -2039,6 +2285,18 @@ mod tests {
2039
2285
assert_eq ! ( vec. as_ptr( ) , ptr) ;
2040
2286
assert_eq ! ( vec. capacity( ) , 7 ) ;
2041
2287
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 ] ) ;
2042
2300
}
2043
2301
2044
2302
#[ bench]
0 commit comments