From e48914067504d668dbc968f18a71ef5be10446cf Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 12 Jul 2013 00:53:03 -0700 Subject: [PATCH 1/2] Remove the global 'vec::to_owned' function --- src/libextra/flatpipes.rs | 2 +- src/libextra/getopts.rs | 2 +- src/libextra/md4.rs | 2 +- src/libextra/num/bigint.rs | 2 +- src/libextra/stats.rs | 7 +++---- src/librustc/metadata/decoder.rs | 2 +- src/librustc/metadata/encoder.rs | 2 +- src/librustc/middle/check_match.rs | 22 +++++++++++----------- src/librustc/middle/trans/adt.rs | 3 +-- src/librustc/middle/ty.rs | 2 +- src/libstd/rand.rs | 2 +- src/libstd/vec.rs | 5 ----- src/libsyntax/attr.rs | 3 +-- src/libsyntax/ext/asm.rs | 4 +--- src/libsyntax/ext/base.rs | 3 +-- src/libsyntax/ext/log_syntax.rs | 3 +-- src/libsyntax/ext/quote.rs | 4 +--- src/libsyntax/ext/trace_macros.rs | 4 +--- src/libsyntax/ext/tt/macro_rules.rs | 5 ++--- 19 files changed, 31 insertions(+), 48 deletions(-) diff --git a/src/libextra/flatpipes.rs b/src/libextra/flatpipes.rs index de0a988f94c8e..9ce7362ef71e5 100644 --- a/src/libextra/flatpipes.rs +++ b/src/libextra/flatpipes.rs @@ -446,7 +446,7 @@ pub mod flatteners { T: Decodable>( buf: &[u8]) -> T { - let buf = vec::to_owned(buf); + let buf = buf.to_owned(); let buf_reader = @BufReader::new(buf); let reader = buf_reader as @Reader; let mut deser: D = FromReader::from_reader(reader); diff --git a/src/libextra/getopts.rs b/src/libextra/getopts.rs index c481fb8f5440d..f8119143c6156 100644 --- a/src/libextra/getopts.rs +++ b/src/libextra/getopts.rs @@ -343,7 +343,7 @@ pub fn getopts(args: &[~str], opts: &[Opt]) -> Result { } i += 1; } - return Ok(Matches {opts: vec::to_owned(opts), + return Ok(Matches {opts: opts.to_owned(), vals: vals, free: free}); } diff --git a/src/libextra/md4.rs b/src/libextra/md4.rs index 6b08fea580f92..2c60be4451974 100644 --- a/src/libextra/md4.rs +++ b/src/libextra/md4.rs @@ -28,7 +28,7 @@ pub fn md4(msg: &[u8]) -> Quad { let orig_len: u64 = (msg.len() * 8u) as u64; // pad message - let mut msg = vec::append(vec::to_owned(msg), [0x80u8]); + let mut msg = vec::append(msg.to_owned(), [0x80u8]); let mut bitlen = orig_len + 8u64; while (bitlen + 64u64) % 512u64 > 0u64 { msg.push(0u8); diff --git a/src/libextra/num/bigint.rs b/src/libextra/num/bigint.rs index 13b55a4609b9c..4bc77f313df41 100644 --- a/src/libextra/num/bigint.rs +++ b/src/libextra/num/bigint.rs @@ -567,7 +567,7 @@ impl BigUint { /// Creates and initializes an BigUint. pub fn from_slice(slice: &[BigDigit]) -> BigUint { - return BigUint::new(vec::to_owned(slice)); + return BigUint::new(slice.to_owned()); } /// Creates and initializes an BigUint. diff --git a/src/libextra/stats.rs b/src/libextra/stats.rs index b6a2deb166331..f488c03ce75ab 100644 --- a/src/libextra/stats.rs +++ b/src/libextra/stats.rs @@ -12,7 +12,6 @@ use sort; use std::cmp; use std::io; use std::num; -use std::vec; // NB: this can probably be rewritten in terms of num::Num // to be less f64-specific. @@ -200,13 +199,13 @@ impl<'self> Stats for &'self [f64] { } fn percentile(self, pct: f64) -> f64 { - let mut tmp = vec::to_owned(self); + let mut tmp = self.to_owned(); sort::tim_sort(tmp); percentile_of_sorted(tmp, pct) } fn quartiles(self) -> (f64,f64,f64) { - let mut tmp = vec::to_owned(self); + let mut tmp = self.to_owned(); sort::tim_sort(tmp); let a = percentile_of_sorted(tmp, 25.0); let b = percentile_of_sorted(tmp, 50.0); @@ -251,7 +250,7 @@ priv fn percentile_of_sorted(sorted_samples: &[f64], /// /// See: http://en.wikipedia.org/wiki/Winsorising pub fn winsorize(samples: &mut [f64], pct: f64) { - let mut tmp = vec::to_owned(samples); + let mut tmp = samples.to_owned(); sort::tim_sort(tmp); let lo = percentile_of_sorted(tmp, pct); let hi = percentile_of_sorted(tmp, 100.0-pct); diff --git a/src/librustc/metadata/decoder.rs b/src/librustc/metadata/decoder.rs index 1e508d0813184..65b01c6af10ff 100644 --- a/src/librustc/metadata/decoder.rs +++ b/src/librustc/metadata/decoder.rs @@ -714,7 +714,7 @@ pub fn maybe_get_item_ast(cdata: cmd, tcx: ty::ctxt, let item_doc = lookup_item(id, cdata.data); let path = { let item_path = item_path(item_doc); - vec::to_owned(item_path.init()) + item_path.init().to_owned() }; match decode_inlined_item(cdata, tcx, copy path, item_doc) { Some(ref ii) => csearch::found((/*bad*/copy *ii)), diff --git a/src/librustc/metadata/encoder.rs b/src/librustc/metadata/encoder.rs index a9f3200af1284..742d549e202e8 100644 --- a/src/librustc/metadata/encoder.rs +++ b/src/librustc/metadata/encoder.rs @@ -1659,7 +1659,7 @@ pub fn encode_metadata(parms: EncodeParams, crate: &crate) -> ~[u8] { let writer_bytes: &mut ~[u8] = wr.bytes; - vec::to_owned(metadata_encoding_version) + + metadata_encoding_version.to_owned() + flate::deflate_bytes(*writer_bytes) } diff --git a/src/librustc/middle/check_match.rs b/src/librustc/middle/check_match.rs index 3d6f8a3615f82..b1095e53075e5 100644 --- a/src/librustc/middle/check_match.rs +++ b/src/librustc/middle/check_match.rs @@ -484,7 +484,7 @@ pub fn specialize(cx: &MatchCheckCtxt, match cx.tcx.def_map.find(&pat_id) { Some(&def_variant(_, id)) => { if variant(id) == *ctor_id { - Some(vec::to_owned(r.tail())) + Some(r.tail().to_owned()) } else { None } @@ -522,7 +522,7 @@ pub fn specialize(cx: &MatchCheckCtxt, _ => fail!("type error") }; if match_ { - Some(vec::to_owned(r.tail())) + Some(r.tail().to_owned()) } else { None } @@ -569,7 +569,7 @@ pub fn specialize(cx: &MatchCheckCtxt, _ => fail!("type error") }; if match_ { - Some(vec::to_owned(r.tail())) + Some(r.tail().to_owned()) } else { None } @@ -579,7 +579,7 @@ pub fn specialize(cx: &MatchCheckCtxt, Some(args) => args, None => vec::from_elem(arity, wild()) }; - Some(vec::append(args, vec::to_owned(r.tail()))) + Some(vec::append(args, r.tail())) } def_variant(_, _) => None, @@ -591,7 +591,7 @@ pub fn specialize(cx: &MatchCheckCtxt, Some(args) => new_args = args, None => new_args = vec::from_elem(arity, wild()) } - Some(vec::append(new_args, vec::to_owned(r.tail()))) + Some(vec::append(new_args, r.tail())) } _ => None } @@ -609,7 +609,7 @@ pub fn specialize(cx: &MatchCheckCtxt, _ => wild() } }); - Some(vec::append(args, vec::to_owned(r.tail()))) + Some(vec::append(args, r.tail())) } else { None } @@ -640,7 +640,7 @@ pub fn specialize(cx: &MatchCheckCtxt, _ => wild() } }).collect(); - Some(vec::append(args, vec::to_owned(r.tail()))) + Some(vec::append(args, r.tail())) } } } @@ -676,14 +676,14 @@ pub fn specialize(cx: &MatchCheckCtxt, single => true, _ => fail!("type error") }; - if match_ { Some(vec::to_owned(r.tail())) } else { None } + if match_ { Some(r.tail().to_owned()) } else { None } } pat_range(lo, hi) => { let (c_lo, c_hi) = match *ctor_id { val(ref v) => ((/*bad*/copy *v), (/*bad*/copy *v)), range(ref lo, ref hi) => ((/*bad*/copy *lo), (/*bad*/copy *hi)), - single => return Some(vec::to_owned(r.tail())), + single => return Some(r.tail().to_owned()), _ => fail!("type error") }; let v_lo = eval_const_expr(cx.tcx, lo); @@ -693,7 +693,7 @@ pub fn specialize(cx: &MatchCheckCtxt, let m2 = compare_const_vals(&c_hi, &v_hi); match (m1, m2) { (Some(val1), Some(val2)) if val1 >= 0 && val2 <= 0 => { - Some(vec::to_owned(r.tail())) + Some(r.tail().to_owned()) }, (Some(_), Some(_)) => None, _ => { @@ -734,7 +734,7 @@ pub fn specialize(cx: &MatchCheckCtxt, } pub fn default(cx: &MatchCheckCtxt, r: &[@pat]) -> Option<~[@pat]> { - if is_wild(cx, r[0]) { Some(vec::to_owned(r.tail())) } + if is_wild(cx, r[0]) { Some(r.tail().to_owned()) } else { None } } diff --git a/src/librustc/middle/trans/adt.rs b/src/librustc/middle/trans/adt.rs index dc8f6b1d05b51..0a2d24ee5fffe 100644 --- a/src/librustc/middle/trans/adt.rs +++ b/src/librustc/middle/trans/adt.rs @@ -47,7 +47,6 @@ use std::container::Map; use std::libc::c_ulonglong; use std::option::{Option, Some, None}; -use std::vec; use lib::llvm::{ValueRef, True, IntEQ, IntNE}; use middle::trans::_match; @@ -219,7 +218,7 @@ fn mk_struct(cx: &mut CrateContext, tys: &[ty::t], packed: bool) -> Struct { size: machine::llsize_of_alloc(cx, llty_rec) /*bad*/as u64, align: machine::llalign_of_min(cx, llty_rec) /*bad*/as u64, packed: packed, - fields: vec::to_owned(tys) + fields: tys.to_owned(), } } diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index e9b3fb0dc1ed1..46257244d57e0 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -3782,7 +3782,7 @@ pub fn item_path(cx: ctxt, id: ast::def_id) -> ast_map::path { } ast_map::node_variant(ref variant, _, path) => { - vec::append_one(vec::to_owned(path.init()), + vec::append_one(path.init().to_owned(), ast_map::path_name((*variant).node.name)) } diff --git a/src/libstd/rand.rs b/src/libstd/rand.rs index 666bf54fa3bdc..fbe126a7d9d16 100644 --- a/src/libstd/rand.rs +++ b/src/libstd/rand.rs @@ -591,7 +591,7 @@ impl RngUtil for R { /// Shuffle a vec fn shuffle(&mut self, values: &[T]) -> ~[T] { - let mut m = vec::to_owned(values); + let mut m = values.to_owned(); self.shuffle_mut(m); m } diff --git a/src/libstd/vec.rs b/src/libstd/vec.rs index 89c4b39c4293e..6937c9f9e7ac6 100644 --- a/src/libstd/vec.rs +++ b/src/libstd/vec.rs @@ -91,11 +91,6 @@ pub fn from_elem(n_elts: uint, t: T) -> ~[T] { } } -/// Creates a new unique vector with the same contents as the slice -pub fn to_owned(t: &[T]) -> ~[T] { - from_fn(t.len(), |i| copy t[i]) -} - /// Creates a new vector with a capacity of `capacity` #[cfg(stage0)] pub fn with_capacity(capacity: uint) -> ~[T] { diff --git a/src/libsyntax/attr.rs b/src/libsyntax/attr.rs index e4532c476d75f..055d5540f8d26 100644 --- a/src/libsyntax/attr.rs +++ b/src/libsyntax/attr.rs @@ -20,7 +20,6 @@ use diagnostic::span_handler; use parse::comments::{doc_comment_style, strip_doc_comment_decoration}; use std::hashmap::HashSet; -use std::vec; /* Constructors */ pub fn mk_name_value_item_str(name: @str, value: @str) @@ -256,7 +255,7 @@ pub fn last_meta_item_list_by_name(items: ~[@ast::meta_item], name: &str) pub fn sort_meta_items(items: &[@ast::meta_item]) -> ~[@ast::meta_item] { // This is sort of stupid here, converting to a vec of mutables and back - let mut v = vec::to_owned(items); + let mut v = items.to_owned(); do extra::sort::quick_sort(v) |ma, mb| { get_meta_item_name(*ma) <= get_meta_item_name(*mb) } diff --git a/src/libsyntax/ext/asm.rs b/src/libsyntax/ext/asm.rs index 532757346d0ae..bf7cccdc9efc0 100644 --- a/src/libsyntax/ext/asm.rs +++ b/src/libsyntax/ext/asm.rs @@ -19,8 +19,6 @@ use ext::base::*; use parse; use parse::token; -use std::vec; - enum State { Asm, Outputs, @@ -43,7 +41,7 @@ pub fn expand_asm(cx: @ExtCtxt, sp: span, tts: &[ast::token_tree]) -> base::MacResult { let p = parse::new_parser_from_tts(cx.parse_sess(), cx.cfg(), - vec::to_owned(tts)); + tts.to_owned()); let mut asm = @""; let mut outputs = ~[]; diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index 5686887491615..c9bd2986a4252 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -18,7 +18,6 @@ use parse; use parse::token; use parse::token::{ident_to_str, intern, str_to_ident}; -use std::vec; use std::hashmap::HashMap; // new-style macro! tt code: @@ -362,7 +361,7 @@ pub fn get_exprs_from_tts(cx: @ExtCtxt, tts: &[ast::token_tree]) -> ~[@ast::expr] { let p = parse::new_parser_from_tts(cx.parse_sess(), cx.cfg(), - vec::to_owned(tts)); + tts.to_owned()); let mut es = ~[]; while *p.token != token::EOF { if es.len() != 0 { diff --git a/src/libsyntax/ext/log_syntax.rs b/src/libsyntax/ext/log_syntax.rs index 9e6776363a82d..409873d347ba2 100644 --- a/src/libsyntax/ext/log_syntax.rs +++ b/src/libsyntax/ext/log_syntax.rs @@ -15,7 +15,6 @@ use ext::base; use print; use parse::token::{get_ident_interner}; -use std::vec; use std::io; pub fn expand_syntax_ext(cx: @ExtCtxt, @@ -26,7 +25,7 @@ pub fn expand_syntax_ext(cx: @ExtCtxt, cx.print_backtrace(); io::stdout().write_line( print::pprust::tt_to_str( - &ast::tt_delim(vec::to_owned(tt)), + &ast::tt_delim(tt.to_owned()), get_ident_interner())); //trivial expression diff --git a/src/libsyntax/ext/quote.rs b/src/libsyntax/ext/quote.rs index c550e3382a233..3e0e9c93fd00e 100644 --- a/src/libsyntax/ext/quote.rs +++ b/src/libsyntax/ext/quote.rs @@ -17,8 +17,6 @@ use parse::token::*; use parse::token; use parse; -use std::vec; - /** * * Quasiquoting works via token trees. @@ -653,7 +651,7 @@ fn expand_tts(cx: @ExtCtxt, let p = parse::new_parser_from_tts( cx.parse_sess(), cx.cfg(), - vec::to_owned(tts) + tts.to_owned() ); *p.quote_depth += 1u; let tts = p.parse_all_token_trees(); diff --git a/src/libsyntax/ext/trace_macros.rs b/src/libsyntax/ext/trace_macros.rs index 299706b2d40bd..ba3b8f22e69b6 100644 --- a/src/libsyntax/ext/trace_macros.rs +++ b/src/libsyntax/ext/trace_macros.rs @@ -16,8 +16,6 @@ use parse::lexer::{new_tt_reader, reader}; use parse::parser::Parser; use parse::token::keywords; -use std::vec; - pub fn expand_trace_macros(cx: @ExtCtxt, sp: span, tt: &[ast::token_tree]) @@ -27,7 +25,7 @@ pub fn expand_trace_macros(cx: @ExtCtxt, let tt_rdr = new_tt_reader( copy cx.parse_sess().span_diagnostic, None, - vec::to_owned(tt) + tt.to_owned() ); let rdr = tt_rdr as @reader; let rust_parser = Parser( diff --git a/src/libsyntax/ext/tt/macro_rules.rs b/src/libsyntax/ext/tt/macro_rules.rs index 6de504c66fd88..a2e3d7bfeca24 100644 --- a/src/libsyntax/ext/tt/macro_rules.rs +++ b/src/libsyntax/ext/tt/macro_rules.rs @@ -23,7 +23,6 @@ use parse::token::{get_ident_interner, special_idents, gensym_ident, ident_to_st use parse::token::{FAT_ARROW, SEMI, nt_matchers, nt_tt}; use print; -use std::vec; use std::io; pub fn add_new_extension(cx: @ExtCtxt, @@ -82,7 +81,7 @@ pub fn add_new_extension(cx: @ExtCtxt, io::println(fmt!("%s! { %s }", cx.str_of(name), print::pprust::tt_to_str( - &ast::tt_delim(vec::to_owned(arg)), + &ast::tt_delim(arg.to_owned()), get_ident_interner()))); } @@ -99,7 +98,7 @@ pub fn add_new_extension(cx: @ExtCtxt, let arg_rdr = new_tt_reader( s_d, None, - vec::to_owned(arg) + arg.to_owned() ) as @reader; match parse(cx.parse_sess(), cx.cfg(), arg_rdr, *mtcs) { success(named_matches) => { From f7b56f908d6327ccce05927c0e1466504fac8d6a Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 12 Jul 2013 00:59:39 -0700 Subject: [PATCH 2/2] Account for possible 0-sized elements in vector iterators Closes #7733 --- src/libstd/vec.rs | 81 +++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 68 insertions(+), 13 deletions(-) diff --git a/src/libstd/vec.rs b/src/libstd/vec.rs index 6937c9f9e7ac6..166ec933dbf71 100644 --- a/src/libstd/vec.rs +++ b/src/libstd/vec.rs @@ -30,7 +30,6 @@ use ptr::RawPtr; use rt::global_heap::malloc_raw; use rt::global_heap::realloc_raw; use sys; -use sys::size_of; use uint; use unstable::intrinsics; #[cfg(stage0)] @@ -109,7 +108,7 @@ pub fn with_capacity(capacity: uint) -> ~[T] { vec } else { let alloc = capacity * sys::nonzero_size_of::(); - let ptr = malloc_raw(alloc + size_of::()) as *mut raw::VecRepr; + let ptr = malloc_raw(alloc + sys::size_of::()) as *mut raw::VecRepr; (*ptr).unboxed.alloc = alloc; (*ptr).unboxed.fill = 0; cast::transmute(ptr) @@ -751,7 +750,9 @@ impl<'self,T> ImmutableVector<'self, T> for &'self [T] { fn iter(self) -> VecIterator<'self, T> { unsafe { let p = vec::raw::to_ptr(self); - VecIterator{ptr: p, end: p.offset(self.len()), + VecIterator{ptr: p, + end: cast::transmute(p as uint + self.len() * + sys::nonzero_size_of::()), lifetime: cast::transmute(p)} } } @@ -1148,7 +1149,7 @@ impl OwnedVector for ~[T] { ::at_vec::raw::reserve_raw(td, ptr, n); } else { let alloc = n * sys::nonzero_size_of::(); - *ptr = realloc_raw(*ptr as *mut c_void, alloc + size_of::()) + *ptr = realloc_raw(*ptr as *mut c_void, alloc + sys::size_of::()) as *mut raw::VecRepr; (**ptr).unboxed.alloc = alloc; } @@ -1177,7 +1178,7 @@ impl OwnedVector for ~[T] { ::at_vec::raw::reserve_raw(td, ptr, n); } else { let alloc = n * sys::nonzero_size_of::(); - let size = alloc + size_of::(); + let size = alloc + sys::size_of::(); if alloc / sys::nonzero_size_of::() != n || size < alloc { fail!("vector size is too large: %u", n); } @@ -1711,7 +1712,9 @@ impl<'self,T> MutableVector<'self, T> for &'self mut [T] { fn mut_iter(self) -> VecMutIterator<'self, T> { unsafe { let p = vec::raw::to_mut_ptr(self); - VecMutIterator{ptr: p, end: p.offset(self.len()), + VecMutIterator{ptr: p, + end: cast::transmute(p as uint + self.len() * + sys::nonzero_size_of::()), lifetime: cast::transmute(p)} } } @@ -2088,7 +2091,11 @@ macro_rules! iterator { None } else { let old = self.ptr; - self.ptr = self.ptr.offset(1); + // purposefully don't use 'ptr.offset' because for + // vectors with 0-size elements this would return the + // same pointer. + self.ptr = cast::transmute(self.ptr as uint + + sys::nonzero_size_of::()); Some(cast::transmute(old)) } } @@ -2097,7 +2104,7 @@ macro_rules! iterator { #[inline] fn size_hint(&self) -> (uint, Option) { let diff = (self.end as uint) - (self.ptr as uint); - let exact = diff / size_of::<$elem>(); + let exact = diff / sys::nonzero_size_of::<$elem>(); (exact, Some(exact)) } } @@ -2114,7 +2121,9 @@ macro_rules! double_ended_iterator { if self.end == self.ptr { None } else { - self.end = self.end.offset(-1); + // See above for why 'ptr.offset' isn't used + self.end = cast::transmute(self.end as uint - + sys::nonzero_size_of::()); Some(cast::transmute(self.end)) } } @@ -2671,19 +2680,19 @@ mod tests { let mut results: ~[~[int]]; results = ~[]; - for each_permutation([]) |v| { results.push(to_owned(v)); } + for each_permutation([]) |v| { results.push(v.to_owned()); } assert_eq!(results, ~[~[]]); results = ~[]; - for each_permutation([7]) |v| { results.push(to_owned(v)); } + for each_permutation([7]) |v| { results.push(v.to_owned()); } assert_eq!(results, ~[~[7]]); results = ~[]; - for each_permutation([1,1]) |v| { results.push(to_owned(v)); } + for each_permutation([1,1]) |v| { results.push(v.to_owned()); } assert_eq!(results, ~[~[1,1],~[1,1]]); results = ~[]; - for each_permutation([5,2,0]) |v| { results.push(to_owned(v)); } + for each_permutation([5,2,0]) |v| { results.push(v.to_owned()); } assert!(results == ~[~[5,2,0],~[5,0,2],~[2,5,0],~[2,0,5],~[0,5,2],~[0,2,5]]); } @@ -3370,4 +3379,50 @@ mod tests { assert_eq!(values, [2, 3, 5, 6, 7]); } + + #[deriving(Eq)] + struct Foo; + + #[test] + fn test_iter_zero_sized() { + let mut v = ~[Foo, Foo, Foo]; + assert_eq!(v.len(), 3); + let mut cnt = 0; + + for v.iter().advance |f| { + assert!(*f == Foo); + cnt += 1; + } + assert_eq!(cnt, 3); + + for v.slice(1, 3).iter().advance |f| { + assert!(*f == Foo); + cnt += 1; + } + assert_eq!(cnt, 5); + + for v.mut_iter().advance |f| { + assert!(*f == Foo); + cnt += 1; + } + assert_eq!(cnt, 8); + + for v.consume_iter().advance |f| { + assert!(f == Foo); + cnt += 1; + } + assert_eq!(cnt, 11); + + let xs = ~[Foo, Foo, Foo]; + assert_eq!(fmt!("%?", xs.slice(0, 2).to_owned()), ~"~[{}, {}]"); + + let xs: [Foo, ..3] = [Foo, Foo, Foo]; + assert_eq!(fmt!("%?", xs.slice(0, 2).to_owned()), ~"~[{}, {}]"); + cnt = 0; + for xs.iter().advance |f| { + assert!(*f == Foo); + cnt += 1; + } + assert!(cnt == 3); + } }