@@ -65,7 +65,7 @@ the rest of the rust manuals.
6565*/
6666
6767use cmp;
68- use num:: { Zero , One , Integer , CheckedAdd , CheckedSub , Saturating } ;
68+ use num:: { Zero , One , Integer , CheckedAdd , CheckedSub , Saturating , ToPrimitive } ;
6969use option:: { Option , Some , None } ;
7070use ops:: { Add , Mul , Sub } ;
7171use cmp:: { Eq , Ord } ;
@@ -1829,7 +1829,8 @@ pub fn range<A: Add<A, A> + Ord + Clone + One>(start: A, stop: A) -> Range<A> {
18291829 Range { state : start, stop : stop, one : One :: one ( ) }
18301830}
18311831
1832- impl < A : Add < A , A > + Ord + Clone > Iterator < A > for Range < A > {
1832+ // FIXME: #10414: Unfortunate type bound
1833+ impl < A : Add < A , A > + Ord + Clone + ToPrimitive > Iterator < A > for Range < A > {
18331834 #[ inline]
18341835 fn next ( & mut self ) -> Option < A > {
18351836 if self . state < self . stop {
@@ -1841,13 +1842,42 @@ impl<A: Add<A, A> + Ord + Clone> Iterator<A> for Range<A> {
18411842 }
18421843 }
18431844
1844- // FIXME: #8606 Implement size_hint() on Range
1845- // Blocked on #8605 Need numeric trait for converting to `Option<uint>`
1845+ #[ inline]
1846+ fn size_hint ( & self ) -> ( uint , Option < uint > ) {
1847+ // This first checks if the elements are representable as i64. If they aren't, try u64 (to
1848+ // handle cases like range(huge, huger)). We don't use uint/int because the difference of
1849+ // the i64/u64 might lie within their range.
1850+ let bound = match self . state . to_i64 ( ) {
1851+ Some ( a) => {
1852+ let sz = self . stop . to_i64 ( ) . map ( |b| b. checked_sub ( & a) ) ;
1853+ match sz {
1854+ Some ( Some ( bound) ) => bound. to_uint ( ) ,
1855+ _ => None ,
1856+ }
1857+ } ,
1858+ None => match self . state . to_u64 ( ) {
1859+ Some ( a) => {
1860+ let sz = self . stop . to_u64 ( ) . map ( |b| b. checked_sub ( & a) ) ;
1861+ match sz {
1862+ Some ( Some ( bound) ) => bound. to_uint ( ) ,
1863+ _ => None
1864+ }
1865+ } ,
1866+ None => None
1867+ }
1868+ } ;
1869+
1870+ match bound {
1871+ Some ( b) => ( b, Some ( b) ) ,
1872+ // Standard fallback for unbounded/unrepresentable bounds
1873+ None => ( 0 , None )
1874+ }
1875+ }
18461876}
18471877
18481878/// `Integer` is required to ensure the range will be the same regardless of
18491879/// the direction it is consumed.
1850- impl < A : Integer + Ord + Clone > DoubleEndedIterator < A > for Range < A > {
1880+ impl < A : Integer + Ord + Clone + ToPrimitive > DoubleEndedIterator < A > for Range < A > {
18511881 #[ inline]
18521882 fn next_back ( & mut self ) -> Option < A > {
18531883 if self . stop > self . state {
@@ -1868,11 +1898,12 @@ pub struct RangeInclusive<A> {
18681898
18691899/// Return an iterator over the range [start, stop]
18701900#[ inline]
1871- pub fn range_inclusive < A : Add < A , A > + Ord + Clone + One > ( start : A , stop : A ) -> RangeInclusive < A > {
1901+ pub fn range_inclusive < A : Add < A , A > + Ord + Clone + One + ToPrimitive > ( start : A , stop : A )
1902+ -> RangeInclusive < A > {
18721903 RangeInclusive { range : range ( start, stop) , done : false }
18731904}
18741905
1875- impl < A : Add < A , A > + Eq + Ord + Clone > Iterator < A > for RangeInclusive < A > {
1906+ impl < A : Add < A , A > + Eq + Ord + Clone + ToPrimitive > Iterator < A > for RangeInclusive < A > {
18761907 #[ inline]
18771908 fn next ( & mut self ) -> Option < A > {
18781909 match self . range . next ( ) {
@@ -1904,7 +1935,8 @@ impl<A: Add<A, A> + Eq + Ord + Clone> Iterator<A> for RangeInclusive<A> {
19041935 }
19051936}
19061937
1907- impl < A : Sub < A , A > + Integer + Ord + Clone > DoubleEndedIterator < A > for RangeInclusive < A > {
1938+ impl < A : Sub < A , A > + Integer + Ord + Clone + ToPrimitive > DoubleEndedIterator < A >
1939+ for RangeInclusive < A > {
19081940 #[ inline]
19091941 fn next_back ( & mut self ) -> Option < A > {
19101942 if self . range . stop > self . range . state {
@@ -2184,6 +2216,7 @@ mod tests {
21842216
21852217 use cmp;
21862218 use uint;
2219+ use num;
21872220
21882221 #[ test]
21892222 fn test_counter_from_iter ( ) {
@@ -2801,12 +2834,51 @@ mod tests {
28012834
28022835 #[ test]
28032836 fn test_range ( ) {
2837+ /// A mock type to check Range when ToPrimitive returns None
2838+ struct Foo ;
2839+
2840+ impl ToPrimitive for Foo {
2841+ fn to_i64 ( & self ) -> Option < i64 > { None }
2842+ fn to_u64 ( & self ) -> Option < u64 > { None }
2843+ }
2844+
2845+ impl Add < Foo , Foo > for Foo {
2846+ fn add ( & self , _: & Foo ) -> Foo {
2847+ Foo
2848+ }
2849+ }
2850+
2851+ impl Ord for Foo {
2852+ fn lt ( & self , _: & Foo ) -> bool {
2853+ false
2854+ }
2855+ }
2856+
2857+ impl Clone for Foo {
2858+ fn clone ( & self ) -> Foo {
2859+ Foo
2860+ }
2861+ }
2862+
2863+ impl num:: One for Foo {
2864+ fn one ( ) -> Foo {
2865+ Foo
2866+ }
2867+ }
2868+
28042869 assert_eq ! ( range( 0 i, 5 ) . collect:: <~[ int] >( ) , ~[ 0 i, 1 , 2 , 3 , 4 ] ) ;
2870+ assert_eq ! ( range( -10 i, -1 ) . collect:: <~[ int] >( ) , ~[ -10 , -9 , -8 , -7 , -6 , -5 , -4 , -3 , -2 ] ) ;
28052871 assert_eq ! ( range( 0 i, 5 ) . invert( ) . collect:: <~[ int] >( ) , ~[ 4 , 3 , 2 , 1 , 0 ] ) ;
28062872 assert_eq ! ( range( 200 , -5 ) . collect:: <~[ int] >( ) , ~[ ] ) ;
28072873 assert_eq ! ( range( 200 , -5 ) . invert( ) . collect:: <~[ int] >( ) , ~[ ] ) ;
28082874 assert_eq ! ( range( 200 , 200 ) . collect:: <~[ int] >( ) , ~[ ] ) ;
28092875 assert_eq ! ( range( 200 , 200 ) . invert( ) . collect:: <~[ int] >( ) , ~[ ] ) ;
2876+
2877+ assert_eq ! ( range( 0 i, 100 ) . size_hint( ) , ( 100 , Some ( 100 ) ) ) ;
2878+ // this test is only meaningful when sizeof uint < sizeof u64
2879+ assert_eq ! ( range( uint:: max_value - 1 , uint:: max_value) . size_hint( ) , ( 1 , Some ( 1 ) ) ) ;
2880+ assert_eq ! ( range( -10 i, -1 ) . size_hint( ) , ( 9 , Some ( 9 ) ) ) ;
2881+ assert_eq ! ( range( Foo , Foo ) . size_hint( ) , ( 0 , None ) ) ;
28102882 }
28112883
28122884 #[ test]
0 commit comments