1
Fork 0

Auto merge of #21919 - alexcrichton:rollup, r=alexcrichton

This commit is contained in:
bors 2015-02-04 06:40:12 +00:00
commit d6c15d9b2d
98 changed files with 5887 additions and 453 deletions

View file

@ -2432,6 +2432,8 @@ The currently implemented features of the reference compiler are:
* `simd` - Allows use of the `#[simd]` attribute, which is overly simple and
not the SIMD interface we want to expose in the long term.
* `staged_api` - Allows usage of stability markers and `#![staged_api]` in a crate
* `struct_inherit` - Allows using struct inheritance, which is barely
implemented and will probably be removed. Don't use this.
@ -2459,6 +2461,11 @@ The currently implemented features of the reference compiler are:
which is considered wildly unsafe and will be
obsoleted by language improvements.
* `unmarked_api` - Allows use of items within a `#![staged_api]` crate
which have not been marked with a stability marker.
Such items should not be allowed by the compiler to exist,
so if you need this there probably is a compiler bug.
* `associated_types` - Allows type aliases in traits. Experimental.
If a feature is promoted to a language feature, then all existing programs will

View file

@ -45,22 +45,18 @@
#![stable(feature = "rust1", since = "1.0.0")]
use core::prelude::*;
use core::any::Any;
use core::clone::Clone;
use core::cmp::{PartialEq, PartialOrd, Eq, Ord, Ordering};
use core::cmp::Ordering;
use core::default::Default;
use core::error::{Error, FromError};
use core::fmt;
use core::hash::{self, Hash};
use core::iter::Iterator;
use core::marker::Sized;
use core::mem;
use core::ops::{Deref, DerefMut};
use core::option::Option;
use core::ptr::Unique;
use core::raw::TraitObject;
use core::result::Result::{Ok, Err};
use core::result::Result;
/// A value that represents the heap. This is the default place that the `box` keyword allocates
/// into when no place is supplied.
@ -296,18 +292,20 @@ impl<T: ?Sized> DerefMut for Box<T> {
fn deref_mut(&mut self) -> &mut T { &mut **self }
}
impl<'a, T> Iterator for Box<Iterator<Item=T> + 'a> {
type Item = T;
fn next(&mut self) -> Option<T> {
(**self).next()
}
fn size_hint(&self) -> (usize, Option<usize>) {
(**self).size_hint()
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<I: Iterator + ?Sized> Iterator for Box<I> {
type Item = I::Item;
fn next(&mut self) -> Option<I::Item> { (**self).next() }
fn size_hint(&self) -> (usize, Option<usize>) { (**self).size_hint() }
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<I: DoubleEndedIterator + ?Sized> DoubleEndedIterator for Box<I> {
fn next_back(&mut self) -> Option<I::Item> { (**self).next_back() }
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<I: ExactSizeIterator + ?Sized> ExactSizeIterator for Box<I> {}
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, E: Error + 'a> FromError<E> for Box<Error + 'a> {
fn from_error(err: E) -> Box<Error + 'a> {
Box::new(err)

View file

@ -13,6 +13,8 @@
#![allow(missing_docs)]
pub use self::Entry::*;
use core::prelude::*;
use core::cmp::Ordering;
@ -66,6 +68,32 @@ pub struct VecMap<V> {
v: Vec<Option<V>>,
}
/// A view into a single entry in a map, which may either be vacant or occupied.
#[unstable(feature = "collections",
reason = "precise API still under development")]
pub enum Entry<'a, V:'a> {
/// A vacant Entry
Vacant(VacantEntry<'a, V>),
/// An occupied Entry
Occupied(OccupiedEntry<'a, V>),
}
/// A vacant Entry.
#[unstable(feature = "collections",
reason = "precise API still under development")]
pub struct VacantEntry<'a, V:'a> {
map: &'a mut VecMap<V>,
index: usize,
}
/// An occupied Entry.
#[unstable(feature = "collections",
reason = "precise API still under development")]
pub struct OccupiedEntry<'a, V:'a> {
map: &'a mut VecMap<V>,
index: usize,
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<V> Default for VecMap<V> {
#[stable(feature = "rust1", since = "1.0.0")]
@ -485,6 +513,119 @@ impl<V> VecMap<V> {
let result = &mut self.v[*key];
result.take()
}
/// Gets the given key's corresponding entry in the map for in-place manipulation.
///
/// # Examples
///
/// ```
/// use std::collections::VecMap;
/// use std::collections::vec_map::Entry;
///
/// let mut count: VecMap<u32> = VecMap::new();
///
/// // count the number of occurrences of numbers in the vec
/// for x in vec![1, 2, 1, 2, 3, 4, 1, 2, 4].iter() {
/// match count.entry(*x) {
/// Entry::Vacant(view) => {
/// view.insert(1);
/// },
/// Entry::Occupied(mut view) => {
/// let v = view.get_mut();
/// *v += 1;
/// },
/// }
/// }
///
/// assert_eq!(count[1], 3);
/// ```
#[unstable(feature = "collections",
reason = "precise API still under development")]
pub fn entry(&mut self, key: usize) -> Entry<V> {
// FIXME(Gankro): this is basically the dumbest implementation of
// entry possible, because weird non-lexical borrows issues make it
// completely insane to do any other way. That said, Entry is a border-line
// useless construct on VecMap, so it's hardly a big loss.
if self.contains_key(&key) {
Occupied(OccupiedEntry {
map: self,
index: key,
})
} else {
Vacant(VacantEntry {
map: self,
index: key,
})
}
}
}
impl<'a, V> Entry<'a, V> {
#[unstable(feature = "collections",
reason = "matches collection reform v2 specification, waiting for dust to settle")]
/// Returns a mutable reference to the entry if occupied, or the VacantEntry if vacant
pub fn get(self) -> Result<&'a mut V, VacantEntry<'a, V>> {
match self {
Occupied(entry) => Ok(entry.into_mut()),
Vacant(entry) => Err(entry),
}
}
}
impl<'a, V> VacantEntry<'a, V> {
/// Sets the value of the entry with the VacantEntry's key,
/// and returns a mutable reference to it.
#[unstable(feature = "collections",
reason = "matches collection reform v2 specification, waiting for dust to settle")]
pub fn insert(self, value: V) -> &'a mut V {
let index = self.index;
self.map.insert(index, value);
&mut self.map[index]
}
}
impl<'a, V> OccupiedEntry<'a, V> {
/// Gets a reference to the value in the entry.
#[unstable(feature = "collections",
reason = "matches collection reform v2 specification, waiting for dust to settle")]
pub fn get(&self) -> &V {
let index = self.index;
&self.map[index]
}
/// Gets a mutable reference to the value in the entry.
#[unstable(feature = "collections",
reason = "matches collection reform v2 specification, waiting for dust to settle")]
pub fn get_mut(&mut self) -> &mut V {
let index = self.index;
&mut self.map[index]
}
/// Converts the entry into a mutable reference to its value.
#[unstable(feature = "collections",
reason = "matches collection reform v2 specification, waiting for dust to settle")]
pub fn into_mut(self) -> &'a mut V {
let index = self.index;
&mut self.map[index]
}
/// Sets the value of the entry with the OccupiedEntry's key,
/// and returns the entry's old value.
#[unstable(feature = "collections",
reason = "matches collection reform v2 specification, waiting for dust to settle")]
pub fn insert(&mut self, value: V) -> V {
let index = self.index;
self.map.insert(index, value).unwrap()
}
/// Takes the value of the entry out of the map, and returns it.
#[unstable(feature = "collections",
reason = "matches collection reform v2 specification, waiting for dust to settle")]
pub fn remove(self) -> V {
let index = self.index;
self.map.remove(&index).unwrap()
}
}
#[stable(feature = "rust1", since = "1.0.0")]
@ -783,7 +924,7 @@ mod test_map {
use prelude::*;
use core::hash::{hash, SipHasher};
use super::VecMap;
use super::{VecMap, Occupied, Vacant};
#[test]
fn test_get_mut() {
@ -1135,6 +1276,57 @@ mod test_map {
map[4];
}
#[test]
fn test_entry(){
let xs = [(1, 10), (2, 20), (3, 30), (4, 40), (5, 50), (6, 60)];
let mut map: VecMap<i32> = xs.iter().map(|&x| x).collect();
// Existing key (insert)
match map.entry(1) {
Vacant(_) => unreachable!(),
Occupied(mut view) => {
assert_eq!(view.get(), &10);
assert_eq!(view.insert(100), 10);
}
}
assert_eq!(map.get(&1).unwrap(), &100);
assert_eq!(map.len(), 6);
// Existing key (update)
match map.entry(2) {
Vacant(_) => unreachable!(),
Occupied(mut view) => {
let v = view.get_mut();
*v *= 10;
}
}
assert_eq!(map.get(&2).unwrap(), &200);
assert_eq!(map.len(), 6);
// Existing key (take)
match map.entry(3) {
Vacant(_) => unreachable!(),
Occupied(view) => {
assert_eq!(view.remove(), 30);
}
}
assert_eq!(map.get(&3), None);
assert_eq!(map.len(), 5);
// Inexistent key (insert)
match map.entry(10) {
Occupied(_) => unreachable!(),
Vacant(view) => {
assert_eq!(*view.insert(1000), 1000);
}
}
assert_eq!(map.get(&10).unwrap(), &1000);
assert_eq!(map.len(), 6);
}
}
#[cfg(test)]

View file

@ -51,7 +51,7 @@
//! use std::error::FromError;
//! use std::old_io::{File, IoError};
//! use std::os::{MemoryMap, MapError};
//! use std::path::Path;
//! use std::old_path::Path;
//!
//! enum MyError {
//! Io(IoError),

View file

@ -264,6 +264,7 @@ pub trait Show {
#[lang = "debug_trait"]
pub trait Debug {
/// Formats the value using the given formatter.
#[stable(feature = "rust1", since = "1.0.0")]
fn fmt(&self, &mut Formatter) -> Result;
}
@ -290,6 +291,7 @@ pub trait String {
#[stable(feature = "rust1", since = "1.0.0")]
pub trait Display {
/// Formats the value using the given formatter.
#[stable(feature = "rust1", since = "1.0.0")]
fn fmt(&self, &mut Formatter) -> Result;
}

View file

@ -101,16 +101,11 @@ pub trait Iterator {
fn size_hint(&self) -> (usize, Option<usize>) { (0, None) }
}
impl<'a, T> Iterator for &'a mut (Iterator<Item=T> + 'a) {
type Item = T;
fn next(&mut self) -> Option<T> {
(**self).next()
}
fn size_hint(&self) -> (usize, Option<usize>) {
(**self).size_hint()
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, I: Iterator + ?Sized> Iterator for &'a mut I {
type Item = I::Item;
fn next(&mut self) -> Option<I::Item> { (**self).next() }
fn size_hint(&self) -> (usize, Option<usize>) { (**self).size_hint() }
}
/// Conversion from an `Iterator`
@ -119,6 +114,7 @@ impl<'a, T> Iterator for &'a mut (Iterator<Item=T> + 'a) {
built from an iterator over elements of type `{A}`"]
pub trait FromIterator<A> {
/// Build a container with elements from an external iterator.
#[stable(feature = "rust1", since = "1.0.0")]
fn from_iter<T: Iterator<Item=A>>(iterator: T) -> Self;
}
@ -548,9 +544,7 @@ pub trait IteratorExt: Iterator + Sized {
/// assert!(it.next() == Some(5));
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
fn by_ref<'r>(&'r mut self) -> ByRef<'r, Self> {
ByRef{iter: self}
}
fn by_ref(&mut self) -> &mut Self { self }
/// Loops through the entire iterator, collecting all of the elements into
/// a container implementing `FromIterator`.
@ -723,11 +717,12 @@ pub trait IteratorExt: Iterator + Sized {
P: FnMut(Self::Item) -> bool,
Self: ExactSizeIterator + DoubleEndedIterator
{
let len = self.len();
for i in (0..len).rev() {
if predicate(self.next_back().expect("rposition: incorrect ExactSizeIterator")) {
let mut i = self.len() - 1;
while let Some(v) = self.next_back() {
if predicate(v) {
return Some(i);
}
i -= 1;
}
None
}
@ -1017,15 +1012,22 @@ impl<I> IteratorExt for I where I: Iterator {}
/// A range iterator able to yield elements from both ends
///
/// A `DoubleEndedIterator` can be thought of as a deque in that `next()` and `next_back()` exhaust
/// elements from the *same* range, and do not work independently of each other.
/// A `DoubleEndedIterator` can be thought of as a deque in that `next()` and
/// `next_back()` exhaust elements from the *same* range, and do not work
/// independently of each other.
#[stable(feature = "rust1", since = "1.0.0")]
pub trait DoubleEndedIterator: Iterator {
/// Yield an element from the end of the range, returning `None` if the range is empty.
/// Yield an element from the end of the range, returning `None` if the
/// range is empty.
#[stable(feature = "rust1", since = "1.0.0")]
fn next_back(&mut self) -> Option<Self::Item>;
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, I: DoubleEndedIterator + ?Sized> DoubleEndedIterator for &'a mut I {
fn next_back(&mut self) -> Option<I::Item> { (**self).next_back() }
}
/// An object implementing random access indexing by `usize`
///
/// A `RandomAccessIterator` should be either infinite or a `DoubleEndedIterator`.
@ -1065,6 +1067,9 @@ pub trait ExactSizeIterator: Iterator {
}
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, I: ExactSizeIterator + ?Sized> ExactSizeIterator for &'a mut I {}
// All adaptors that preserve the size of the wrapped iterator are fine
// Adaptors that may overflow in `size_hint` are not, i.e. `Chain`.
#[stable(feature = "rust1", since = "1.0.0")]
@ -1117,32 +1122,6 @@ impl<I> RandomAccessIterator for Rev<I> where I: DoubleEndedIterator + RandomAcc
}
}
/// A mutable reference to an iterator
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
#[stable(feature = "rust1", since = "1.0.0")]
pub struct ByRef<'a, I:'a> {
iter: &'a mut I,
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, I> Iterator for ByRef<'a, I> where I: 'a + Iterator {
type Item = <I as Iterator>::Item;
#[inline]
fn next(&mut self) -> Option<<I as Iterator>::Item> { self.iter.next() }
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) { self.iter.size_hint() }
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, I> DoubleEndedIterator for ByRef<'a, I> where I: 'a + DoubleEndedIterator {
#[inline]
fn next_back(&mut self) -> Option<<I as Iterator>::Item> { self.iter.next_back() }
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, I> ExactSizeIterator for ByRef<'a, I> where I: 'a + ExactSizeIterator {}
/// A trait for iterators over elements which can be added together
#[unstable(feature = "core",
reason = "needs to be re-evaluated as part of numerics reform")]
@ -1821,6 +1800,7 @@ impl<I: Iterator> Peekable<I> {
/// Return a reference to the next element of the iterator with out
/// advancing it, or None if the iterator is exhausted.
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn peek(&mut self) -> Option<&I::Item> {
if self.peeked.is_none() {
self.peeked = self.iter.next();

View file

@ -17,7 +17,7 @@ use std::cmp::Ordering;
use std::default::Default;
use std::fmt;
use std::iter::FromIterator;
use std::path::BytesContainer;
use std::old_path::BytesContainer;
use std::slice;
// Note 1: It is not clear whether the flexibility of providing both

View file

@ -45,7 +45,7 @@ impl<'a, 'v> Visitor<'v> for CheckLoopVisitor<'a> {
ast::ExprLoop(ref b, _) => {
self.with_context(Loop, |v| v.visit_block(&**b));
}
ast::ExprClosure(_, _, _, ref b) => {
ast::ExprClosure(_, _, ref b) => {
self.with_context(Closure, |v| v.visit_block(&**b));
}
ast::ExprBreak(_) => self.require_loop("break", e.span),

View file

@ -959,7 +959,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
self.propagate_through_expr(&**e, succ)
}
ast::ExprClosure(_, _, _, ref blk) => {
ast::ExprClosure(_, _, ref blk) => {
debug!("{} is an ExprClosure",
expr_to_string(expr));

View file

@ -739,7 +739,7 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> {
};
match fn_expr.node {
ast::ExprClosure(_, _, _, ref body) => body.id,
ast::ExprClosure(_, _, ref body) => body.id,
_ => unreachable!()
}
};

View file

@ -14,6 +14,7 @@
use session::Session;
use lint;
use middle::ty;
use middle::privacy::PublicItems;
use metadata::csearch;
use syntax::parse::token::InternedString;
use syntax::codemap::{Span, DUMMY_SP};
@ -44,15 +45,16 @@ pub struct Index {
// A private tree-walker for producing an Index.
struct Annotator<'a> {
sess: &'a Session,
index: Index,
parent: Option<Stability>
index: &'a mut Index,
parent: Option<Stability>,
export_map: &'a PublicItems,
}
impl<'a> Annotator<'a> {
// Determine the stability for a node based on its attributes and inherited
// stability. The stability is recorded in the index and used as the parent.
fn annotate<F>(&mut self, id: NodeId, use_parent: bool,
attrs: &Vec<Attribute>, item_sp: Span, f: F) where
attrs: &Vec<Attribute>, item_sp: Span, f: F, required: bool) where
F: FnOnce(&mut Annotator),
{
match attr::find_stability(self.sess.diagnostic(), attrs.as_slice(), item_sp) {
@ -70,7 +72,14 @@ impl<'a> Annotator<'a> {
}
None => {
if use_parent {
self.parent.clone().map(|stab| self.index.local.insert(id, stab));
if let Some(stab) = self.parent.clone() {
self.index.local.insert(id, stab);
} else if self.index.staged_api && required
&& self.export_map.contains(&id)
&& !self.sess.opts.test {
self.sess.span_err(item_sp,
"This node does not have a stability attribute");
}
}
f(self);
}
@ -93,11 +102,19 @@ impl<'a, 'v> Visitor<'v> for Annotator<'a> {
_ => true,
};
self.annotate(i.id, use_parent, &i.attrs, i.span, |v| visit::walk_item(v, i));
// In case of a `pub use <mod>;`, we should not error since the stability
// is inherited from the module itself
let required = match i.node {
ast::ItemUse(_) => i.vis != ast::Public,
_ => true
};
self.annotate(i.id, use_parent, &i.attrs, i.span,
|v| visit::walk_item(v, i), required);
if let ast::ItemStruct(ref sd, _) = i.node {
sd.ctor_id.map(|id| {
self.annotate(id, true, &i.attrs, i.span, |_| {})
self.annotate(id, true, &i.attrs, i.span, |_| {}, true)
});
}
}
@ -106,7 +123,7 @@ impl<'a, 'v> Visitor<'v> for Annotator<'a> {
_: &'v Block, sp: Span, _: NodeId) {
if let FkMethod(_, _, meth) = fk {
// Methods are not already annotated, so we annotate it
self.annotate(meth.id, true, &meth.attrs, sp, |_| {});
self.annotate(meth.id, true, &meth.attrs, sp, |_| {}, true);
}
// Items defined in a function body have no reason to have
// a stability attribute, so we don't recurse.
@ -126,27 +143,41 @@ impl<'a, 'v> Visitor<'v> for Annotator<'a> {
TypeTraitItem(ref typedef) => (typedef.ty_param.id, &typedef.attrs,
typedef.ty_param.span),
};
self.annotate(id, true, attrs, sp, |v| visit::walk_trait_item(v, t));
self.annotate(id, true, attrs, sp, |v| visit::walk_trait_item(v, t), true);
}
fn visit_variant(&mut self, var: &Variant, g: &'v Generics) {
self.annotate(var.node.id, true, &var.node.attrs, var.span,
|v| visit::walk_variant(v, var, g))
|v| visit::walk_variant(v, var, g), true)
}
fn visit_struct_field(&mut self, s: &StructField) {
self.annotate(s.node.id, true, &s.node.attrs, s.span,
|v| visit::walk_struct_field(v, s));
|v| visit::walk_struct_field(v, s), true);
}
fn visit_foreign_item(&mut self, i: &ast::ForeignItem) {
self.annotate(i.id, true, &i.attrs, i.span, |_| {});
self.annotate(i.id, true, &i.attrs, i.span, |_| {}, true);
}
}
impl Index {
/// Construct the stability index for a crate being compiled.
pub fn build(sess: &Session, krate: &Crate) -> Index {
pub fn build(&mut self, sess: &Session, krate: &Crate, export_map: &PublicItems) {
if !self.staged_api {
return;
}
let mut annotator = Annotator {
sess: sess,
index: self,
parent: None,
export_map: export_map,
};
annotator.annotate(ast::CRATE_NODE_ID, true, &krate.attrs, krate.span,
|v| visit::walk_crate(v, krate), true);
}
pub fn new(krate: &Crate) -> Index {
let mut staged_api = false;
for attr in &krate.attrs {
if attr.name().get() == "staged_api" {
@ -159,22 +190,11 @@ impl Index {
}
}
}
let index = Index {
Index {
staged_api: staged_api,
local: NodeMap(),
extern_cache: DefIdMap()
};
if !staged_api {
return index;
}
let mut annotator = Annotator {
sess: sess,
index: index,
parent: None
};
annotator.annotate(ast::CRATE_NODE_ID, true, &krate.attrs, krate.span,
|v| visit::walk_crate(v, krate));
annotator.index
}
}
@ -234,10 +254,19 @@ impl<'a, 'tcx> Checker<'a, 'tcx> {
None => {
// This is an 'unmarked' API, which should not exist
// in the standard library.
self.tcx.sess.span_err(span, "use of unmarked library feature");
self.tcx.sess.span_note(span, "this is either a bug in the library you are \
using or a bug in the compiler - there is \
no way to use this feature");
if self.tcx.sess.features.borrow().unmarked_api {
self.tcx.sess.span_warn(span, "use of unmarked library feature");
self.tcx.sess.span_note(span, "this is either a bug in the library you are \
using and a bug in the compiler - please \
report it in both places");
} else {
self.tcx.sess.span_err(span, "use of unmarked library feature");
self.tcx.sess.span_note(span, "this is either a bug in the library you are \
using and a bug in the compiler - please \
report it in both places");
self.tcx.sess.span_note(span, "use #![feature(unmarked_api)] in the \
crate attributes to override this");
}
}
}
}

View file

@ -80,37 +80,23 @@ pub fn poly_project_and_unify_type<'cx,'tcx>(
obligation.repr(selcx.tcx()));
let infcx = selcx.infcx();
let result = infcx.try(|snapshot| {
infcx.try(|snapshot| {
let (skol_predicate, skol_map) =
infcx.skolemize_late_bound_regions(&obligation.predicate, snapshot);
let skol_obligation = obligation.with(skol_predicate);
match project_and_unify_type(selcx, &skol_obligation) {
Ok(Some(obligations)) => {
Ok(result) => {
match infcx.leak_check(&skol_map, snapshot) {
Ok(()) => Ok(infcx.plug_leaks(skol_map, snapshot, &obligations)),
Err(e) => Err(Some(MismatchedProjectionTypes { err: e })),
Ok(()) => Ok(infcx.plug_leaks(skol_map, snapshot, &result)),
Err(e) => Err(MismatchedProjectionTypes { err: e }),
}
}
Ok(None) => {
// Signal ambiguity using Err just so that infcx.try()
// rolls back the snapshot. We adapt below.
Err(None)
}
Err(e) => {
Err(Some(e))
Err(e)
}
}
});
// Above, we use Err(None) to signal ambiguity so that the
// snapshot will be rolled back. But here, we want to translate to
// Ok(None). Kind of weird.
match result {
Ok(obligations) => Ok(Some(obligations)),
Err(None) => Ok(None),
Err(Some(e)) => Err(e),
}
})
}
/// Evaluates constraints of the form:
@ -132,7 +118,10 @@ fn project_and_unify_type<'cx,'tcx>(
obligation.cause.clone(),
obligation.recursion_depth) {
Some(n) => n,
None => { return Ok(None); }
None => {
consider_unification_despite_ambiguity(selcx, obligation);
return Ok(None);
}
};
debug!("project_and_unify_type: normalized_ty={} obligations={}",
@ -147,6 +136,50 @@ fn project_and_unify_type<'cx,'tcx>(
}
}
fn consider_unification_despite_ambiguity<'cx,'tcx>(selcx: &mut SelectionContext<'cx,'tcx>,
obligation: &ProjectionObligation<'tcx>) {
debug!("consider_unification_despite_ambiguity(obligation={})",
obligation.repr(selcx.tcx()));
let def_id = obligation.predicate.projection_ty.trait_ref.def_id;
match selcx.tcx().lang_items.fn_trait_kind(def_id) {
Some(_) => { }
None => { return; }
}
let infcx = selcx.infcx();
let self_ty = obligation.predicate.projection_ty.trait_ref.self_ty();
let self_ty = infcx.shallow_resolve(self_ty);
debug!("consider_unification_despite_ambiguity: self_ty.sty={:?}",
self_ty.sty);
match self_ty.sty {
ty::ty_closure(closure_def_id, _, substs) => {
let closure_typer = selcx.closure_typer();
let closure_type = closure_typer.closure_type(closure_def_id, substs);
let ty::Binder((_, ret_type)) =
util::closure_trait_ref_and_return_type(infcx.tcx,
def_id,
self_ty,
&closure_type.sig,
util::TupleArgumentsFlag::No);
let (ret_type, _) =
infcx.replace_late_bound_regions_with_fresh_var(
obligation.cause.span,
infer::AssocTypeProjection(obligation.predicate.projection_ty.item_name),
&ty::Binder(ret_type));
debug!("consider_unification_despite_ambiguity: ret_type={:?}",
ret_type.repr(selcx.tcx()));
let origin = infer::RelateOutputImplTypes(obligation.cause.span);
let obligation_ty = obligation.predicate.ty;
match infer::mk_eqty(infcx, true, origin, obligation_ty, ret_type) {
Ok(()) => { }
Err(_) => { /* ignore errors */ }
}
}
_ => { }
}
}
/// Normalizes any associated type projections in `value`, replacing
/// them with a fully resolved type where possible. The return value
/// combines the normalized result and any additional obligations that

View file

@ -233,9 +233,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
// is `Vec<Foo>:Iterable<Bar>`, but the impl specifies
// `impl<T> Iterable<T> for Vec<T>`, than an error would result.
/// Evaluates whether the obligation can be satisfied. Returns an indication of whether the
/// obligation can be satisfied and, if so, by what means. Never affects surrounding typing
/// environment.
/// Attempts to satisfy the obligation. If successful, this will affect the surrounding
/// type environment by performing unification.
pub fn select(&mut self, obligation: &TraitObligation<'tcx>)
-> SelectionResult<'tcx, Selection<'tcx>> {
debug!("select({})", obligation.repr(self.tcx()));
@ -243,11 +242,68 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
let stack = self.push_stack(None, obligation);
match try!(self.candidate_from_obligation(&stack)) {
None => Ok(None),
None => {
self.consider_unification_despite_ambiguity(obligation);
Ok(None)
}
Some(candidate) => Ok(Some(try!(self.confirm_candidate(obligation, candidate)))),
}
}
/// In the particular case of unboxed closure obligations, we can
/// sometimes do some amount of unification for the
/// argument/return types even though we can't yet fully match obligation.
/// The particular case we are interesting in is an obligation of the form:
///
/// C : FnFoo<A>
///
/// where `C` is an unboxed closure type and `FnFoo` is one of the
/// `Fn` traits. Because we know that users cannot write impls for closure types
/// themselves, the only way that `C : FnFoo` can fail to match is under two
/// conditions:
///
/// 1. The closure kind for `C` is not yet known, because inference isn't complete.
/// 2. The closure kind for `C` *is* known, but doesn't match what is needed.
/// For example, `C` may be a `FnOnce` closure, but a `Fn` closure is needed.
///
/// In either case, we always know what argument types are
/// expected by `C`, no matter what kind of `Fn` trait it
/// eventually matches. So we can go ahead and unify the argument
/// types, even though the end result is ambiguous.
///
/// Note that this is safe *even if* the trait would never be
/// matched (case 2 above). After all, in that case, an error will
/// result, so it kind of doesn't matter what we do --- unifying
/// the argument types can only be helpful to the user, because
/// once they patch up the kind of closure that is expected, the
/// argment types won't really change.
fn consider_unification_despite_ambiguity(&mut self, obligation: &TraitObligation<'tcx>) {
// Is this a `C : FnFoo(...)` trait reference for some trait binding `FnFoo`?
match self.tcx().lang_items.fn_trait_kind(obligation.predicate.0.def_id()) {
Some(_) => { }
None => { return; }
}
// Is the self-type a closure type? We ignore bindings here
// because if it is a closure type, it must be a closure type from
// within this current fn, and hence none of the higher-ranked
// lifetimes can appear inside the self-type.
let self_ty = self.infcx.shallow_resolve(obligation.self_ty());
let (closure_def_id, substs) = match self_ty.sty {
ty::ty_closure(id, _, ref substs) => (id, substs.clone()),
_ => { return; }
};
assert!(!substs.has_escaping_regions());
let closure_trait_ref = self.closure_trait_ref(obligation, closure_def_id, substs);
match self.confirm_poly_trait_refs(obligation.cause.clone(),
obligation.predicate.to_poly_trait_ref(),
closure_trait_ref) {
Ok(()) => { }
Err(_) => { /* Silently ignore errors. */ }
}
}
///////////////////////////////////////////////////////////////////////////
// EVALUATION
//
@ -1003,7 +1059,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
candidates: &mut SelectionCandidateSet<'tcx>)
-> Result<(),SelectionError<'tcx>>
{
let kind = match self.fn_family_trait_kind(obligation.predicate.0.def_id()) {
let kind = match self.tcx().lang_items.fn_trait_kind(obligation.predicate.0.def_id()) {
Some(k) => k,
None => { return Ok(()); }
};
@ -2303,22 +2359,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
impl_obligations
}
fn fn_family_trait_kind(&self,
trait_def_id: ast::DefId)
-> Option<ty::ClosureKind>
{
let tcx = self.tcx();
if Some(trait_def_id) == tcx.lang_items.fn_trait() {
Some(ty::FnClosureKind)
} else if Some(trait_def_id) == tcx.lang_items.fn_mut_trait() {
Some(ty::FnMutClosureKind)
} else if Some(trait_def_id) == tcx.lang_items.fn_once_trait() {
Some(ty::FnOnceClosureKind)
} else {
None
}
}
#[allow(unused_comparisons)]
fn derived_cause(&self,
obligation: &TraitObligation<'tcx>,

View file

@ -306,7 +306,7 @@ impl Target {
use std::env;
use std::ffi::OsString;
use std::old_io::File;
use std::path::Path;
use std::old_path::Path;
use serialize::json;
fn load_file(path: &Path) -> Result<Target, String> {

View file

@ -324,7 +324,7 @@ pub fn closure_to_block(closure_id: ast::NodeId,
tcx: &ty::ctxt) -> ast::NodeId {
match tcx.map.get(closure_id) {
ast_map::NodeExpr(expr) => match expr.node {
ast::ExprClosure(_, _, _, ref block) => {
ast::ExprClosure(_, _, ref block) => {
block.id
}
_ => {

View file

@ -594,9 +594,6 @@ pub fn phase_3_run_analysis_passes<'tcx>(sess: Session,
time(time_passes, "loop checking", (), |_|
middle::check_loop::check_crate(&sess, krate));
let stability_index = time(time_passes, "stability index", (), |_|
stability::Index::build(&sess, krate));
time(time_passes, "static item recursion checking", (), |_|
middle::check_static_recursion::check_crate(&sess, krate, &def_map, &ast_map));
@ -608,7 +605,7 @@ pub fn phase_3_run_analysis_passes<'tcx>(sess: Session,
freevars,
region_map,
lang_items,
stability_index);
stability::Index::new(krate));
// passes are timed inside typeck
typeck::check_crate(&ty_cx, trait_map);
@ -628,6 +625,10 @@ pub fn phase_3_run_analysis_passes<'tcx>(sess: Session,
time(time_passes, "privacy checking", maps, |(a, b)|
rustc_privacy::check_crate(&ty_cx, &export_map, a, b));
// Do not move this check past lint
time(time_passes, "stability index", (), |_|
ty_cx.stability.borrow_mut().build(&ty_cx.sess, krate, &public_items));
time(time_passes, "intrinsic checking", (), |_|
middle::intrinsicck::check_crate(&ty_cx));

View file

@ -125,7 +125,6 @@ fn test_env<F>(source_string: &str,
resolve::resolve_crate(&sess, &ast_map, &lang_items, krate, resolve::MakeGlobMap::No);
let named_region_map = resolve_lifetime::krate(&sess, krate, &def_map);
let region_map = region::resolve_crate(&sess, krate);
let stability_index = stability::Index::build(&sess, krate);
let tcx = ty::mk_ctxt(sess,
&arenas,
def_map,
@ -134,7 +133,7 @@ fn test_env<F>(source_string: &str,
freevars,
region_map,
lang_items,
stability_index);
stability::Index::new(krate));
let infcx = infer::new_infer_ctxt(&tcx);
body(Env { infcx: &infcx });
infcx.resolve_regions_and_report_errors(ast::CRATE_NODE_ID);

View file

@ -4521,7 +4521,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
visit::walk_expr(self, expr);
}
ExprClosure(_, _, ref fn_decl, ref block) => {
ExprClosure(_, ref fn_decl, ref block) => {
self.resolve_function(ClosureRibKind(expr.id),
Some(&**fn_decl), NoTypeParameters,
&**block);

View file

@ -1394,7 +1394,7 @@ impl<'l, 'tcx, 'v> Visitor<'v> for DxrVisitor<'l, 'tcx> {
type, found {:?}", ty)[]),
}
},
ast::ExprClosure(_, _, ref decl, ref body) => {
ast::ExprClosure(_, ref decl, ref body) => {
if generated_code(body.span) {
return
}

View file

@ -1340,7 +1340,7 @@ fn build_cfg(tcx: &ty::ctxt, id: ast::NodeId) -> (ast::NodeId, Option<cfg::CFG>)
}
Some(ast_map::NodeExpr(e)) => {
match e.node {
ast::ExprClosure(_, _, _, ref blk) => {
ast::ExprClosure(_, _, ref blk) => {
blk
}
_ => tcx.sess.bug("unexpected expr variant in has_nested_returns")

View file

@ -1283,7 +1283,7 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
}
ast_map::NodeExpr(ref expr) => {
match expr.node {
ast::ExprClosure(_, _, ref fn_decl, ref top_level_block) => {
ast::ExprClosure(_, ref fn_decl, ref top_level_block) => {
let name = format!("fn{}", token::gensym("fn"));
let name = token::str_to_ident(&name[]);
(name, &**fn_decl,
@ -1590,7 +1590,7 @@ fn compile_unit_metadata(cx: &CrateContext) -> DIDescriptor {
Some(ref p) if p.is_relative() => {
// prepend "./" if necessary
let dotdot = b"..";
let prefix: &[u8] = &[dotdot[0], ::std::path::SEP_BYTE];
let prefix: &[u8] = &[dotdot[0], ::std::old_path::SEP_BYTE];
let mut path_bytes = p.as_vec().to_vec();
if &path_bytes[..2] != prefix &&
@ -3595,7 +3595,7 @@ fn create_scope_map(cx: &CrateContext,
})
}
ast::ExprClosure(_, _, ref decl, ref block) => {
ast::ExprClosure(_, ref decl, ref block) => {
with_new_scope(cx,
block.span,
scope_stack,

View file

@ -1095,7 +1095,7 @@ fn trans_rvalue_dps_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
ast::ExprVec(..) | ast::ExprRepeat(..) => {
tvec::trans_fixed_vstore(bcx, expr, dest)
}
ast::ExprClosure(_, _, ref decl, ref body) => {
ast::ExprClosure(_, ref decl, ref body) => {
closure::trans_closure_expr(bcx, &**decl, &**body, expr.id, dest)
}
ast::ExprCall(ref f, ref args) => {

View file

@ -25,7 +25,6 @@ use util::ppaux::Repr;
pub fn check_expr_closure<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>,
expr: &ast::Expr,
_capture: ast::CaptureClause,
opt_kind: Option<ast::ClosureKind>,
decl: &'tcx ast::FnDecl,
body: &'tcx ast::Block,
expected: Expectation<'tcx>) {
@ -33,38 +32,14 @@ pub fn check_expr_closure<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>,
expr.repr(fcx.tcx()),
expected.repr(fcx.tcx()));
let expected_sig_and_kind = expected.to_option(fcx).and_then(|ty| {
deduce_expectations_from_expected_type(fcx, ty)
});
match opt_kind {
None => {
// If users didn't specify what sort of closure they want,
// examine the expected type. For now, if we see explicit
// evidence than an unboxed closure is desired, we'll use
// that. Otherwise, we leave it unspecified, to be filled
// in by upvar inference.
match expected_sig_and_kind {
None => { // don't have information about the kind, request explicit annotation
check_closure(fcx, expr, None, decl, body, None);
},
Some((sig, kind)) => {
check_closure(fcx, expr, Some(kind), decl, body, Some(sig));
}
}
}
Some(kind) => {
let kind = match kind {
ast::FnClosureKind => ty::FnClosureKind,
ast::FnMutClosureKind => ty::FnMutClosureKind,
ast::FnOnceClosureKind => ty::FnOnceClosureKind,
};
let expected_sig = expected_sig_and_kind.map(|t| t.0);
check_closure(fcx, expr, Some(kind), decl, body, expected_sig);
}
}
// It's always helpful for inference if we know the kind of
// closure sooner rather than later, so first examine the expected
// type, and see if can glean a closure kind from there.
let (expected_sig,expected_kind) = match expected.to_option(fcx) {
Some(ty) => deduce_expectations_from_expected_type(fcx, ty),
None => (None, None)
};
check_closure(fcx, expr, expected_kind, decl, body, expected_sig)
}
fn check_closure<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>,
@ -133,21 +108,30 @@ fn check_closure<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>,
fn deduce_expectations_from_expected_type<'a,'tcx>(
fcx: &FnCtxt<'a,'tcx>,
expected_ty: Ty<'tcx>)
-> Option<(ty::FnSig<'tcx>,ty::ClosureKind)>
-> (Option<ty::FnSig<'tcx>>,Option<ty::ClosureKind>)
{
debug!("deduce_expectations_from_expected_type(expected_ty={})",
expected_ty.repr(fcx.tcx()));
match expected_ty.sty {
ty::ty_trait(ref object_type) => {
let proj_bounds = object_type.projection_bounds_with_self_ty(fcx.tcx(),
fcx.tcx().types.err);
proj_bounds.iter()
.filter_map(|pb| deduce_expectations_from_projection(fcx, pb))
.next()
let expectations =
proj_bounds.iter()
.filter_map(|pb| deduce_expectations_from_projection(fcx, pb))
.next();
match expectations {
Some((sig, kind)) => (Some(sig), Some(kind)),
None => (None, None)
}
}
ty::ty_infer(ty::TyVar(vid)) => {
deduce_expectations_from_obligations(fcx, vid)
}
_ => {
None
(None, None)
}
}
}
@ -155,33 +139,61 @@ fn deduce_expectations_from_expected_type<'a,'tcx>(
fn deduce_expectations_from_obligations<'a,'tcx>(
fcx: &FnCtxt<'a,'tcx>,
expected_vid: ty::TyVid)
-> Option<(ty::FnSig<'tcx>, ty::ClosureKind)>
-> (Option<ty::FnSig<'tcx>>, Option<ty::ClosureKind>)
{
let fulfillment_cx = fcx.inh.fulfillment_cx.borrow();
// Here `expected_ty` is known to be a type inference variable.
fulfillment_cx.pending_obligations()
.iter()
.filter_map(|obligation| {
match obligation.predicate {
ty::Predicate::Projection(ref proj_predicate) => {
let trait_ref = proj_predicate.to_poly_trait_ref();
let self_ty = fcx.infcx().shallow_resolve(trait_ref.self_ty());
match self_ty.sty {
ty::ty_infer(ty::TyVar(v)) if expected_vid == v => {
deduce_expectations_from_projection(fcx, proj_predicate)
}
_ => {
None
}
}
}
_ => {
None
}
}
})
.next()
let expected_sig_and_kind =
fulfillment_cx
.pending_obligations()
.iter()
.filter_map(|obligation| {
debug!("deduce_expectations_from_obligations: obligation.predicate={}",
obligation.predicate.repr(fcx.tcx()));
match obligation.predicate {
// Given a Projection predicate, we can potentially infer
// the complete signature.
ty::Predicate::Projection(ref proj_predicate) => {
let trait_ref = proj_predicate.to_poly_trait_ref();
self_type_matches_expected_vid(fcx, trait_ref, expected_vid)
.and_then(|_| deduce_expectations_from_projection(fcx, proj_predicate))
}
_ => {
None
}
}
})
.next();
match expected_sig_and_kind {
Some((sig, kind)) => { return (Some(sig), Some(kind)); }
None => { }
}
// Even if we can't infer the full signature, we may be able to
// infer the kind. This can occur if there is a trait-reference
// like `F : Fn<A>`.
let expected_kind =
fulfillment_cx
.pending_obligations()
.iter()
.filter_map(|obligation| {
let opt_trait_ref = match obligation.predicate {
ty::Predicate::Projection(ref data) => Some(data.to_poly_trait_ref()),
ty::Predicate::Trait(ref data) => Some(data.to_poly_trait_ref()),
ty::Predicate::Equate(..) => None,
ty::Predicate::RegionOutlives(..) => None,
ty::Predicate::TypeOutlives(..) => None,
};
opt_trait_ref
.and_then(|trait_ref| self_type_matches_expected_vid(fcx, trait_ref, expected_vid))
.and_then(|trait_ref| fcx.tcx().lang_items.fn_trait_kind(trait_ref.def_id()))
})
.next();
(None, expected_kind)
}
/// Given a projection like "<F as Fn(X)>::Result == Y", we can deduce
@ -229,3 +241,20 @@ fn deduce_expectations_from_projection<'a,'tcx>(
return Some((fn_sig, kind));
}
fn self_type_matches_expected_vid<'a,'tcx>(
fcx: &FnCtxt<'a,'tcx>,
trait_ref: ty::PolyTraitRef<'tcx>,
expected_vid: ty::TyVid)
-> Option<ty::PolyTraitRef<'tcx>>
{
let self_ty = fcx.infcx().shallow_resolve(trait_ref.self_ty());
debug!("self_type_matches_expected_vid(trait_ref={}, self_ty={})",
trait_ref.repr(fcx.tcx()),
self_ty.repr(fcx.tcx()));
match self_ty.sty {
ty::ty_infer(ty::TyVar(v)) if expected_vid == v => Some(trait_ref),
_ => None,
}
}

View file

@ -3736,8 +3736,8 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>,
ast::ExprMatch(ref discrim, ref arms, match_src) => {
_match::check_match(fcx, expr, &**discrim, arms.as_slice(), expected, match_src);
}
ast::ExprClosure(capture, opt_kind, ref decl, ref body) => {
closure::check_expr_closure(fcx, expr, capture, opt_kind, &**decl, &**body, expected);
ast::ExprClosure(capture, ref decl, ref body) => {
closure::check_expr_closure(fcx, expr, capture, &**decl, &**body, expected);
}
ast::ExprBlock(ref b) => {
check_block_with_expected(fcx, &**b, expected);

View file

@ -638,7 +638,7 @@ fn visit_expr(rcx: &mut Rcx, expr: &ast::Expr) {
visit::walk_expr(rcx, expr);
}
ast::ExprClosure(_, _, _, ref body) => {
ast::ExprClosure(_, _, ref body) => {
check_expr_fn_block(rcx, expr, &**body);
}

View file

@ -83,7 +83,7 @@ struct SeedBorrowKind<'a,'tcx:'a> {
impl<'a, 'tcx, 'v> Visitor<'v> for SeedBorrowKind<'a, 'tcx> {
fn visit_expr(&mut self, expr: &ast::Expr) {
match expr.node {
ast::ExprClosure(cc, _, _, ref body) => {
ast::ExprClosure(cc, _, ref body) => {
self.check_closure(expr, cc, &**body);
}

View file

@ -118,7 +118,7 @@ impl<'cx, 'tcx, 'v> Visitor<'v> for WritebackCx<'cx, 'tcx> {
MethodCall::expr(e.id));
match e.node {
ast::ExprClosure(_, _, ref decl, _) => {
ast::ExprClosure(_, ref decl, _) => {
for input in &decl.inputs {
let _ = self.visit_node_id(ResolvingExpr(e.span),
input.id);

View file

@ -49,7 +49,7 @@ use rustc::middle::stability;
use std::rc::Rc;
use std::u32;
use std::str::Str as StrTrait; // Conflicts with Str variant
use std::path::Path as FsPath; // Conflicts with Path struct
use std::old_path::Path as FsPath; // Conflicts with Path struct
use core::DocContext;
use doctree;

View file

@ -14,7 +14,7 @@
Core encoding and decoding interfaces.
*/
use std::path;
use std::old_path;
use std::rc::Rc;
use std::cell::{Cell, RefCell};
use std::sync::Arc;
@ -538,29 +538,29 @@ macro_rules! tuple {
tuple! { T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, }
impl Encodable for path::posix::Path {
impl Encodable for old_path::posix::Path {
fn encode<S: Encoder>(&self, e: &mut S) -> Result<(), S::Error> {
self.as_vec().encode(e)
}
}
impl Decodable for path::posix::Path {
fn decode<D: Decoder>(d: &mut D) -> Result<path::posix::Path, D::Error> {
impl Decodable for old_path::posix::Path {
fn decode<D: Decoder>(d: &mut D) -> Result<old_path::posix::Path, D::Error> {
let bytes: Vec<u8> = try!(Decodable::decode(d));
Ok(path::posix::Path::new(bytes))
Ok(old_path::posix::Path::new(bytes))
}
}
impl Encodable for path::windows::Path {
impl Encodable for old_path::windows::Path {
fn encode<S: Encoder>(&self, e: &mut S) -> Result<(), S::Error> {
self.as_vec().encode(e)
}
}
impl Decodable for path::windows::Path {
fn decode<D: Decoder>(d: &mut D) -> Result<path::windows::Path, D::Error> {
impl Decodable for old_path::windows::Path {
fn decode<D: Decoder>(d: &mut D) -> Result<old_path::windows::Path, D::Error> {
let bytes: Vec<u8> = try!(Decodable::decode(d));
Ok(path::windows::Path::new(bytes))
Ok(old_path::windows::Path::new(bytes))
}
}

View file

@ -57,7 +57,7 @@ pub fn current_dir() -> IoResult<Path> {
///
/// ```rust
/// use std::env;
/// use std::path::Path;
/// use std::old_path::Path;
///
/// let root = Path::new("/");
/// assert!(env::set_current_dir(&root).is_ok());

View file

@ -24,6 +24,7 @@ pub use self::os_str::OsStr;
mod c_str;
mod os_str;
// FIXME (#21670): these should be defined in the os_str module
/// Freely convertible to an `&OsStr` slice.
pub trait AsOsStr {
/// Convert to an `&OsStr` slice.

View file

@ -41,7 +41,7 @@ use string::{String, CowString};
use ops;
use cmp;
use hash::{Hash, Hasher, Writer};
use path::{Path, GenericPath};
use old_path::{Path, GenericPath};
use sys::os_str::{Buf, Slice};
use sys_common::{AsInner, IntoInner, FromInner};

676
src/libstd/io/buffered.rs Normal file
View file

@ -0,0 +1,676 @@
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//
// ignore-lexer-test FIXME #15883
//! Buffering wrappers for I/O traits
use prelude::v1::*;
use io::prelude::*;
use cmp;
use error::Error as StdError;
use error::FromError;
use fmt;
use io::{self, Cursor, DEFAULT_BUF_SIZE, Error, ErrorKind};
use ptr;
/// Wraps a `Read` and buffers input from it
///
/// It can be excessively inefficient to work directly with a `Read` instance.
/// For example, every call to `read` on `TcpStream` results in a system call.
/// A `BufReader` performs large, infrequent reads on the underlying `Read`
/// and maintains an in-memory buffer of the results.
pub struct BufReader<R> {
inner: R,
buf: Cursor<Vec<u8>>,
}
impl<R: Read> BufReader<R> {
/// Creates a new `BufReader` with a default buffer capacity
pub fn new(inner: R) -> BufReader<R> {
BufReader::with_capacity(DEFAULT_BUF_SIZE, inner)
}
/// Creates a new `BufReader` with the specified buffer capacity
pub fn with_capacity(cap: usize, inner: R) -> BufReader<R> {
BufReader {
inner: inner,
buf: Cursor::new(Vec::with_capacity(cap)),
}
}
/// Gets a reference to the underlying reader.
pub fn get_ref<'a>(&self) -> &R { &self.inner }
/// Gets a mutable reference to the underlying reader.
///
/// # Warning
///
/// It is inadvisable to directly read from the underlying reader.
pub fn get_mut(&mut self) -> &mut R { &mut self.inner }
/// Unwraps this `BufReader`, returning the underlying reader.
///
/// Note that any leftover data in the internal buffer is lost.
pub fn into_inner(self) -> R { self.inner }
}
impl<R: Read> Read for BufReader<R> {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
// If we don't have any buffered data and we're doing a massive read
// (larger than our internal buffer), bypass our internal buffer
// entirely.
if self.buf.get_ref().len() == self.buf.position() as usize &&
buf.len() >= self.buf.get_ref().capacity() {
return self.inner.read(buf);
}
try!(self.fill_buf());
self.buf.read(buf)
}
}
impl<R: Read> BufRead for BufReader<R> {
fn fill_buf(&mut self) -> io::Result<&[u8]> {
// If we've reached the end of our internal buffer then we need to fetch
// some more data from the underlying reader.
if self.buf.position() as usize == self.buf.get_ref().len() {
self.buf.set_position(0);
let v = self.buf.get_mut();
v.truncate(0);
let inner = &mut self.inner;
try!(super::with_end_to_cap(v, |b| inner.read(b)));
}
self.buf.fill_buf()
}
fn consume(&mut self, amt: uint) {
self.buf.consume(amt)
}
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<R> fmt::Debug for BufReader<R> where R: fmt::Debug {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
write!(fmt, "BufReader {{ reader: {:?}, buffer: {}/{} }}",
self.inner, self.buf.position(), self.buf.get_ref().len())
}
}
/// Wraps a Writer and buffers output to it
///
/// It can be excessively inefficient to work directly with a `Write`. For
/// example, every call to `write` on `TcpStream` results in a system call. A
/// `BufWriter` keeps an in memory buffer of data and writes it to the
/// underlying `Write` in large, infrequent batches.
///
/// This writer will be flushed when it is dropped.
pub struct BufWriter<W> {
inner: Option<W>,
buf: Vec<u8>,
}
/// An error returned by `into_inner` which indicates whether a flush error
/// happened or not.
#[derive(Debug)]
pub struct IntoInnerError<W>(W, Error);
impl<W: Write> BufWriter<W> {
/// Creates a new `BufWriter` with a default buffer capacity
pub fn new(inner: W) -> BufWriter<W> {
BufWriter::with_capacity(DEFAULT_BUF_SIZE, inner)
}
/// Creates a new `BufWriter` with the specified buffer capacity
pub fn with_capacity(cap: usize, inner: W) -> BufWriter<W> {
BufWriter {
inner: Some(inner),
buf: Vec::with_capacity(cap),
}
}
fn flush_buf(&mut self) -> io::Result<()> {
let mut written = 0;
let len = self.buf.len();
let mut ret = Ok(());
while written < len {
match self.inner.as_mut().unwrap().write(&self.buf[written..]) {
Ok(0) => {
ret = Err(Error::new(ErrorKind::WriteZero,
"failed to flush", None));
break;
}
Ok(n) => written += n,
Err(e) => { ret = Err(e); break }
}
}
if written > 0 {
// NB: would be better expressed as .remove(0..n) if it existed
unsafe {
ptr::copy_memory(self.buf.as_mut_ptr(),
self.buf.as_ptr().offset(written as isize),
len - written);
}
}
self.buf.truncate(len - written);
ret
}
/// Gets a reference to the underlying writer.
pub fn get_ref(&self) -> &W { self.inner.as_ref().unwrap() }
/// Gets a mutable reference to the underlying write.
///
/// # Warning
///
/// It is inadvisable to directly read from the underlying writer.
pub fn get_mut(&mut self) -> &mut W { self.inner.as_mut().unwrap() }
/// Unwraps this `BufWriter`, returning the underlying writer.
///
/// The buffer is flushed before returning the writer.
pub fn into_inner(mut self) -> Result<W, IntoInnerError<BufWriter<W>>> {
match self.flush_buf() {
Err(e) => Err(IntoInnerError(self, e)),
Ok(()) => Ok(self.inner.take().unwrap())
}
}
}
impl<W: Write> Write for BufWriter<W> {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
if self.buf.len() + buf.len() > self.buf.capacity() {
try!(self.flush_buf());
}
if buf.len() >= self.buf.capacity() {
self.inner.as_mut().unwrap().write(buf)
} else {
let amt = cmp::min(buf.len(), self.buf.capacity());
Write::write(&mut self.buf, &buf[..amt])
}
}
fn flush(&mut self) -> io::Result<()> {
self.flush_buf().and_then(|()| self.get_mut().flush())
}
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<W> fmt::Debug for BufWriter<W> where W: fmt::Debug {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
write!(fmt, "BufWriter {{ writer: {:?}, buffer: {}/{} }}",
self.inner.as_ref().unwrap(), self.buf.len(), self.buf.capacity())
}
}
#[unsafe_destructor]
impl<W: Write> Drop for BufWriter<W> {
fn drop(&mut self) {
if self.inner.is_some() {
// dtors should not panic, so we ignore a failed flush
let _r = self.flush_buf();
}
}
}
impl<W> IntoInnerError<W> {
/// Returns the error which caused the call to `into_inner` to fail.
///
/// This error was returned when attempting to flush the internal buffer.
pub fn error(&self) -> &Error { &self.1 }
/// Returns the underlying `BufWriter` instance which generated the error.
///
/// The returned object can be used to retry a flush or re-inspect the
/// buffer.
pub fn into_inner(self) -> W { self.0 }
}
impl<W> FromError<IntoInnerError<W>> for Error {
fn from_error(iie: IntoInnerError<W>) -> Error { iie.1 }
}
impl<W> StdError for IntoInnerError<W> {
fn description(&self) -> &str { self.error().description() }
}
impl<W> fmt::Display for IntoInnerError<W> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.error().fmt(f)
}
}
/// Wraps a Writer and buffers output to it, flushing whenever a newline
/// (`0x0a`, `'\n'`) is detected.
///
/// This writer will be flushed when it is dropped.
pub struct LineWriter<W> {
inner: BufWriter<W>,
}
impl<W: Write> LineWriter<W> {
/// Creates a new `LineWriter`
pub fn new(inner: W) -> LineWriter<W> {
// Lines typically aren't that long, don't use a giant buffer
LineWriter { inner: BufWriter::with_capacity(1024, inner) }
}
/// Gets a reference to the underlying writer.
///
/// This type does not expose the ability to get a mutable reference to the
/// underlying reader because that could possibly corrupt the buffer.
pub fn get_ref<'a>(&'a self) -> &'a W { self.inner.get_ref() }
/// Unwraps this `LineWriter`, returning the underlying writer.
///
/// The internal buffer is flushed before returning the writer.
pub fn into_inner(self) -> Result<W, IntoInnerError<LineWriter<W>>> {
self.inner.into_inner().map_err(|IntoInnerError(buf, e)| {
IntoInnerError(LineWriter { inner: buf }, e)
})
}
}
impl<W: Write> Write for LineWriter<W> {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
match buf.rposition_elem(&b'\n') {
Some(i) => {
let n = try!(self.inner.write(&buf[..i + 1]));
if n != i + 1 { return Ok(n) }
try!(self.inner.flush());
self.inner.write(&buf[i + 1..]).map(|i| n + i)
}
None => self.inner.write(buf),
}
}
fn flush(&mut self) -> io::Result<()> { self.inner.flush() }
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<W> fmt::Debug for LineWriter<W> where W: fmt::Debug {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
write!(fmt, "LineWriter {{ writer: {:?}, buffer: {}/{} }}",
self.inner.inner, self.inner.buf.len(),
self.inner.buf.capacity())
}
}
struct InternalBufWriter<W>(BufWriter<W>);
impl<W> InternalBufWriter<W> {
fn get_mut(&mut self) -> &mut BufWriter<W> {
let InternalBufWriter(ref mut w) = *self;
return w;
}
}
impl<W: Read> Read for InternalBufWriter<W> {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
self.get_mut().inner.as_mut().unwrap().read(buf)
}
}
/// Wraps a Stream and buffers input and output to and from it.
///
/// It can be excessively inefficient to work directly with a `Stream`. For
/// example, every call to `read` or `write` on `TcpStream` results in a system
/// call. A `BufStream` keeps in memory buffers of data, making large,
/// infrequent calls to `read` and `write` on the underlying `Stream`.
///
/// The output half will be flushed when this stream is dropped.
pub struct BufStream<S> {
inner: BufReader<InternalBufWriter<S>>
}
impl<S: Read + Write> BufStream<S> {
/// Creates a new buffered stream with explicitly listed capacities for the
/// reader/writer buffer.
pub fn with_capacities(reader_cap: usize, writer_cap: usize, inner: S)
-> BufStream<S> {
let writer = BufWriter::with_capacity(writer_cap, inner);
let internal_writer = InternalBufWriter(writer);
let reader = BufReader::with_capacity(reader_cap, internal_writer);
BufStream { inner: reader }
}
/// Creates a new buffered stream with the default reader/writer buffer
/// capacities.
pub fn new(inner: S) -> BufStream<S> {
BufStream::with_capacities(DEFAULT_BUF_SIZE, DEFAULT_BUF_SIZE, inner)
}
/// Gets a reference to the underlying stream.
pub fn get_ref(&self) -> &S {
let InternalBufWriter(ref w) = self.inner.inner;
w.get_ref()
}
/// Gets a mutable reference to the underlying stream.
///
/// # Warning
///
/// It is inadvisable to read directly from or write directly to the
/// underlying stream.
pub fn get_mut(&mut self) -> &mut S {
let InternalBufWriter(ref mut w) = self.inner.inner;
w.get_mut()
}
/// Unwraps this `BufStream`, returning the underlying stream.
///
/// The internal buffer is flushed before returning the stream. Any leftover
/// data in the read buffer is lost.
pub fn into_inner(self) -> Result<S, IntoInnerError<BufStream<S>>> {
let BufReader { inner: InternalBufWriter(w), buf } = self.inner;
w.into_inner().map_err(|IntoInnerError(w, e)| {
IntoInnerError(BufStream {
inner: BufReader { inner: InternalBufWriter(w), buf: buf },
}, e)
})
}
}
impl<S: Read + Write> BufRead for BufStream<S> {
fn fill_buf(&mut self) -> io::Result<&[u8]> { self.inner.fill_buf() }
fn consume(&mut self, amt: uint) { self.inner.consume(amt) }
}
impl<S: Read + Write> Read for BufStream<S> {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
self.inner.read(buf)
}
}
impl<S: Read + Write> Write for BufStream<S> {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
self.inner.inner.get_mut().write(buf)
}
fn flush(&mut self) -> io::Result<()> {
self.inner.inner.get_mut().flush()
}
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<S> fmt::Debug for BufStream<S> where S: fmt::Debug {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
let reader = &self.inner;
let writer = &self.inner.inner.0;
write!(fmt, "BufStream {{ stream: {:?}, write_buffer: {}/{}, read_buffer: {}/{} }}",
writer.inner,
writer.buf.len(), writer.buf.capacity(),
reader.buf.position(), reader.buf.get_ref().len())
}
}
#[cfg(test)]
mod tests {
use prelude::v1::*;
use io::prelude::*;
use io::{self, BufReader, BufWriter, BufStream, Cursor, LineWriter};
use test;
/// A dummy reader intended at testing short-reads propagation.
pub struct ShortReader {
lengths: Vec<usize>,
}
impl Read for ShortReader {
fn read(&mut self, _: &mut [u8]) -> io::Result<usize> {
if self.lengths.is_empty() {
Ok(0)
} else {
Ok(self.lengths.remove(0))
}
}
}
#[test]
fn test_buffered_reader() {
let inner: &[u8] = &[5, 6, 7, 0, 1, 2, 3, 4];
let mut reader = BufReader::with_capacity(2, inner);
let mut buf = [0, 0, 0];
let nread = reader.read(&mut buf);
assert_eq!(Ok(3), nread);
let b: &[_] = &[5, 6, 7];
assert_eq!(buf, b);
let mut buf = [0, 0];
let nread = reader.read(&mut buf);
assert_eq!(Ok(2), nread);
let b: &[_] = &[0, 1];
assert_eq!(buf, b);
let mut buf = [0];
let nread = reader.read(&mut buf);
assert_eq!(Ok(1), nread);
let b: &[_] = &[2];
assert_eq!(buf, b);
let mut buf = [0, 0, 0];
let nread = reader.read(&mut buf);
assert_eq!(Ok(1), nread);
let b: &[_] = &[3, 0, 0];
assert_eq!(buf, b);
let nread = reader.read(&mut buf);
assert_eq!(Ok(1), nread);
let b: &[_] = &[4, 0, 0];
assert_eq!(buf, b);
assert_eq!(reader.read(&mut buf), Ok(0));
}
#[test]
fn test_buffered_writer() {
let inner = Vec::new();
let mut writer = BufWriter::with_capacity(2, inner);
writer.write(&[0, 1]).unwrap();
assert_eq!(*writer.get_ref(), [0, 1]);
writer.write(&[2]).unwrap();
assert_eq!(*writer.get_ref(), [0, 1]);
writer.write(&[3]).unwrap();
assert_eq!(*writer.get_ref(), [0, 1]);
writer.flush().unwrap();
assert_eq!(*writer.get_ref(), [0, 1, 2, 3]);
writer.write(&[4]).unwrap();
writer.write(&[5]).unwrap();
assert_eq!(*writer.get_ref(), [0, 1, 2, 3]);
writer.write(&[6]).unwrap();
assert_eq!(*writer.get_ref(), [0, 1, 2, 3, 4, 5]);
writer.write(&[7, 8]).unwrap();
assert_eq!(*writer.get_ref(), [0, 1, 2, 3, 4, 5, 6, 7, 8]);
writer.write(&[9, 10, 11]).unwrap();
let a: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11];
assert_eq!(*writer.get_ref(), [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]);
writer.flush().unwrap();
assert_eq!(*writer.get_ref(), [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]);
}
#[test]
fn test_buffered_writer_inner_flushes() {
let mut w = BufWriter::with_capacity(3, Vec::new());
w.write(&[0, 1]).unwrap();
assert_eq!(*w.get_ref(), []);
let w = w.into_inner().unwrap();
assert_eq!(w, [0, 1]);
}
// This is just here to make sure that we don't infinite loop in the
// newtype struct autoderef weirdness
#[test]
fn test_buffered_stream() {
struct S;
impl Write for S {
fn write(&mut self, b: &[u8]) -> io::Result<usize> { Ok(b.len()) }
fn flush(&mut self) -> io::Result<()> { Ok(()) }
}
impl Read for S {
fn read(&mut self, _: &mut [u8]) -> io::Result<usize> { Ok(0) }
}
let mut stream = BufStream::new(S);
assert_eq!(stream.read(&mut [0; 10]), Ok(0));
stream.write(&[0; 10]).unwrap();
stream.flush().unwrap();
}
#[test]
fn test_read_until() {
let inner: &[u8] = &[0, 1, 2, 1, 0];
let mut reader = BufReader::with_capacity(2, inner);
let mut v = Vec::new();
reader.read_until(0, &mut v).unwrap();
assert_eq!(v, [0]);
v.truncate(0);
reader.read_until(2, &mut v).unwrap();
assert_eq!(v, [1, 2]);
v.truncate(0);
reader.read_until(1, &mut v).unwrap();
assert_eq!(v, [1]);
v.truncate(0);
reader.read_until(8, &mut v).unwrap();
assert_eq!(v, [0]);
v.truncate(0);
reader.read_until(9, &mut v).unwrap();
assert_eq!(v, []);
}
#[test]
fn test_line_buffer() {
let mut writer = LineWriter::new(Vec::new());
writer.write(&[0]).unwrap();
assert_eq!(*writer.get_ref(), []);
writer.write(&[1]).unwrap();
assert_eq!(*writer.get_ref(), []);
writer.flush().unwrap();
assert_eq!(*writer.get_ref(), [0, 1]);
writer.write(&[0, b'\n', 1, b'\n', 2]).unwrap();
assert_eq!(*writer.get_ref(), [0, 1, 0, b'\n', 1, b'\n']);
writer.flush().unwrap();
assert_eq!(*writer.get_ref(), [0, 1, 0, b'\n', 1, b'\n', 2]);
writer.write(&[3, b'\n']).unwrap();
assert_eq!(*writer.get_ref(), [0, 1, 0, b'\n', 1, b'\n', 2, 3, b'\n']);
}
#[test]
fn test_read_line() {
let in_buf = b"a\nb\nc";
let mut reader = BufReader::with_capacity(2, in_buf);
let mut s = String::new();
reader.read_line(&mut s).unwrap();
assert_eq!(s, "a\n");
s.truncate(0);
reader.read_line(&mut s).unwrap();
assert_eq!(s, "b\n");
s.truncate(0);
reader.read_line(&mut s).unwrap();
assert_eq!(s, "c");
s.truncate(0);
reader.read_line(&mut s).unwrap();
assert_eq!(s, "");
}
#[test]
fn test_lines() {
let in_buf = b"a\nb\nc";
let mut reader = BufReader::with_capacity(2, in_buf);
let mut it = reader.lines();
assert_eq!(it.next(), Some(Ok("a".to_string())));
assert_eq!(it.next(), Some(Ok("b".to_string())));
assert_eq!(it.next(), Some(Ok("c".to_string())));
assert_eq!(it.next(), None);
}
#[test]
fn test_short_reads() {
let inner = ShortReader{lengths: vec![0, 1, 2, 0, 1, 0]};
let mut reader = BufReader::new(inner);
let mut buf = [0, 0];
assert_eq!(reader.read(&mut buf), Ok(0));
assert_eq!(reader.read(&mut buf), Ok(1));
assert_eq!(reader.read(&mut buf), Ok(2));
assert_eq!(reader.read(&mut buf), Ok(0));
assert_eq!(reader.read(&mut buf), Ok(1));
assert_eq!(reader.read(&mut buf), Ok(0));
assert_eq!(reader.read(&mut buf), Ok(0));
}
#[test]
fn read_char_buffered() {
let buf = [195u8, 159u8];
let mut reader = BufReader::with_capacity(1, &buf[]);
assert_eq!(reader.chars().next(), Some(Ok('ß')));
}
#[test]
fn test_chars() {
let buf = [195u8, 159u8, b'a'];
let mut reader = BufReader::with_capacity(1, &buf[]);
let mut it = reader.chars();
assert_eq!(it.next(), Some(Ok('ß')));
assert_eq!(it.next(), Some(Ok('a')));
assert_eq!(it.next(), None);
}
#[test]
#[should_fail]
fn dont_panic_in_drop_on_panicked_flush() {
struct FailFlushWriter;
impl Write for FailFlushWriter {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> { Ok(buf.len()) }
fn flush(&mut self) -> io::Result<()> {
Err(io::Error::last_os_error())
}
}
let writer = FailFlushWriter;
let _writer = BufWriter::new(writer);
// If writer panics *again* due to the flush error then the process will
// abort.
panic!();
}
#[bench]
fn bench_buffered_reader(b: &mut test::Bencher) {
b.iter(|| {
BufReader::new(io::empty())
});
}
#[bench]
fn bench_buffered_writer(b: &mut test::Bencher) {
b.iter(|| {
BufWriter::new(io::sink())
});
}
#[bench]
fn bench_buffered_stream(b: &mut test::Bencher) {
let mut buf = Cursor::new(Vec::new());
b.iter(|| {
BufStream::new(&mut buf);
});
}
}

408
src/libstd/io/cursor.rs Normal file
View file

@ -0,0 +1,408 @@
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![allow(missing_copy_implementations)]
use prelude::v1::*;
use io::prelude::*;
use cmp;
use io::{self, SeekFrom, Error, ErrorKind};
use iter::repeat;
use num::Int;
use slice;
/// A `Cursor` is a type which wraps another I/O object to provide a `Seek`
/// implementation.
///
/// Cursors are currently typically used with memory buffer objects in order to
/// allow `Seek` plus `Read` and `Write` implementations. For example, common
/// cursor types include:
///
/// * `Cursor<Vec<u8>>`
/// * `Cursor<&[u8]>`
///
/// Implementations of the I/O traits for `Cursor<T>` are not currently generic
/// over `T` itself. Instead, specific implementations are provided for various
/// in-memory buffer types like `Vec<u8>` and `&[u8]`.
pub struct Cursor<T> {
inner: T,
pos: u64,
}
impl<T> Cursor<T> {
/// Create a new cursor wrapping the provided underlying I/O object.
pub fn new(inner: T) -> Cursor<T> {
Cursor { pos: 0, inner: inner }
}
/// Consume this cursor, returning the underlying value.
pub fn into_inner(self) -> T { self.inner }
/// Get a reference to the underlying value in this cursor.
pub fn get_ref(&self) -> &T { &self.inner }
/// Get a mutable reference to the underlying value in this cursor.
///
/// Care should be taken to avoid modifying the internal I/O state of the
/// underlying value as it may corrupt this cursor's position.
pub fn get_mut(&mut self) -> &mut T { &mut self.inner }
/// Returns the current value of this cursor
pub fn position(&self) -> u64 { self.pos }
/// Sets the value of this cursor
pub fn set_position(&mut self, pos: u64) { self.pos = pos; }
}
macro_rules! seek {
() => {
fn seek(&mut self, style: SeekFrom) -> io::Result<u64> {
let pos = match style {
SeekFrom::Start(n) => { self.pos = n; return Ok(n) }
SeekFrom::End(n) => self.inner.len() as i64 + n,
SeekFrom::Current(n) => self.pos as i64 + n,
};
if pos < 0 {
Err(Error::new(ErrorKind::InvalidInput,
"invalid seek to a negative position",
None))
} else {
self.pos = pos as u64;
Ok(self.pos)
}
}
}
}
impl<'a> io::Seek for Cursor<&'a [u8]> { seek!(); }
impl<'a> io::Seek for Cursor<&'a mut [u8]> { seek!(); }
impl io::Seek for Cursor<Vec<u8>> { seek!(); }
macro_rules! read {
() => {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
let n = try!(Read::read(&mut try!(self.fill_buf()), buf));
self.pos += n as u64;
Ok(n)
}
}
}
impl<'a> Read for Cursor<&'a [u8]> { read!(); }
impl<'a> Read for Cursor<&'a mut [u8]> { read!(); }
impl Read for Cursor<Vec<u8>> { read!(); }
macro_rules! buffer {
() => {
fn fill_buf(&mut self) -> io::Result<&[u8]> {
let amt = cmp::min(self.pos, self.inner.len() as u64);
Ok(&self.inner[(amt as usize)..])
}
fn consume(&mut self, amt: usize) { self.pos += amt as u64; }
}
}
impl<'a> BufRead for Cursor<&'a [u8]> { buffer!(); }
impl<'a> BufRead for Cursor<&'a mut [u8]> { buffer!(); }
impl<'a> BufRead for Cursor<Vec<u8>> { buffer!(); }
impl<'a> Write for Cursor<&'a mut [u8]> {
fn write(&mut self, data: &[u8]) -> io::Result<usize> {
let pos = cmp::min(self.pos, self.inner.len() as u64);
let amt = try!((&mut self.inner[(pos as usize)..]).write(data));
self.pos += amt as u64;
Ok(amt)
}
fn flush(&mut self) -> io::Result<()> { Ok(()) }
}
impl Write for Cursor<Vec<u8>> {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
// Make sure the internal buffer is as least as big as where we
// currently are
let pos = self.position();
let amt = pos.saturating_sub(self.inner.len() as u64);
self.inner.extend(repeat(0).take(amt as usize));
// Figure out what bytes will be used to overwrite what's currently
// there (left), and what will be appended on the end (right)
let space = self.inner.len() - pos as usize;
let (left, right) = buf.split_at(cmp::min(space, buf.len()));
slice::bytes::copy_memory(&mut self.inner[(pos as usize)..], left);
self.inner.push_all(right);
// Bump us forward
self.set_position(pos + buf.len() as u64);
Ok(buf.len())
}
fn flush(&mut self) -> io::Result<()> { Ok(()) }
}
#[cfg(test)]
mod tests {
use core::prelude::*;
use io::prelude::*;
use io::{Cursor, SeekFrom};
use vec::Vec;
#[test]
fn test_vec_writer() {
let mut writer = Vec::new();
assert_eq!(writer.write(&[0]), Ok(1));
assert_eq!(writer.write(&[1, 2, 3]), Ok(3));
assert_eq!(writer.write(&[4, 5, 6, 7]), Ok(4));
let b: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7];
assert_eq!(writer, b);
}
#[test]
fn test_mem_writer() {
let mut writer = Cursor::new(Vec::new());
assert_eq!(writer.write(&[0]), Ok(1));
assert_eq!(writer.write(&[1, 2, 3]), Ok(3));
assert_eq!(writer.write(&[4, 5, 6, 7]), Ok(4));
let b: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7];
assert_eq!(&writer.get_ref()[], b);
}
#[test]
fn test_buf_writer() {
let mut buf = [0 as u8; 9];
{
let mut writer = Cursor::new(&mut buf[]);
assert_eq!(writer.position(), 0);
assert_eq!(writer.write(&[0]), Ok(1));
assert_eq!(writer.position(), 1);
assert_eq!(writer.write(&[1, 2, 3]), Ok(3));
assert_eq!(writer.write(&[4, 5, 6, 7]), Ok(4));
assert_eq!(writer.position(), 8);
assert_eq!(writer.write(&[]), Ok(0));
assert_eq!(writer.position(), 8);
assert_eq!(writer.write(&[8, 9]), Ok(1));
assert_eq!(writer.write(&[10]), Ok(0));
}
let b: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7, 8];
assert_eq!(buf, b);
}
#[test]
fn test_buf_writer_seek() {
let mut buf = [0 as u8; 8];
{
let mut writer = Cursor::new(&mut buf[]);
assert_eq!(writer.position(), 0);
assert_eq!(writer.write(&[1]), Ok(1));
assert_eq!(writer.position(), 1);
assert_eq!(writer.seek(SeekFrom::Start(2)), Ok(2));
assert_eq!(writer.position(), 2);
assert_eq!(writer.write(&[2]), Ok(1));
assert_eq!(writer.position(), 3);
assert_eq!(writer.seek(SeekFrom::Current(-2)), Ok(1));
assert_eq!(writer.position(), 1);
assert_eq!(writer.write(&[3]), Ok(1));
assert_eq!(writer.position(), 2);
assert_eq!(writer.seek(SeekFrom::End(-1)), Ok(7));
assert_eq!(writer.position(), 7);
assert_eq!(writer.write(&[4]), Ok(1));
assert_eq!(writer.position(), 8);
}
let b: &[_] = &[1, 3, 2, 0, 0, 0, 0, 4];
assert_eq!(buf, b);
}
#[test]
fn test_buf_writer_error() {
let mut buf = [0 as u8; 2];
let mut writer = Cursor::new(&mut buf[]);
assert_eq!(writer.write(&[0]), Ok(1));
assert_eq!(writer.write(&[0, 0]), Ok(1));
assert_eq!(writer.write(&[0, 0]), Ok(0));
}
#[test]
fn test_mem_reader() {
let mut reader = Cursor::new(vec!(0u8, 1, 2, 3, 4, 5, 6, 7));
let mut buf = [];
assert_eq!(reader.read(&mut buf), Ok(0));
assert_eq!(reader.position(), 0);
let mut buf = [0];
assert_eq!(reader.read(&mut buf), Ok(1));
assert_eq!(reader.position(), 1);
let b: &[_] = &[0];
assert_eq!(buf, b);
let mut buf = [0; 4];
assert_eq!(reader.read(&mut buf), Ok(4));
assert_eq!(reader.position(), 5);
let b: &[_] = &[1, 2, 3, 4];
assert_eq!(buf, b);
assert_eq!(reader.read(&mut buf), Ok(3));
let b: &[_] = &[5, 6, 7];
assert_eq!(&buf[..3], b);
assert_eq!(reader.read(&mut buf), Ok(0));
}
#[test]
fn read_to_end() {
let mut reader = Cursor::new(vec!(0u8, 1, 2, 3, 4, 5, 6, 7));
let mut v = Vec::new();
reader.read_to_end(&mut v).ok().unwrap();
assert_eq!(v, [0, 1, 2, 3, 4, 5, 6, 7]);
}
#[test]
fn test_slice_reader() {
let in_buf = vec![0u8, 1, 2, 3, 4, 5, 6, 7];
let mut reader = &mut in_buf.as_slice();
let mut buf = [];
assert_eq!(reader.read(&mut buf), Ok(0));
let mut buf = [0];
assert_eq!(reader.read(&mut buf), Ok(1));
assert_eq!(reader.len(), 7);
let b: &[_] = &[0];
assert_eq!(buf.as_slice(), b);
let mut buf = [0; 4];
assert_eq!(reader.read(&mut buf), Ok(4));
assert_eq!(reader.len(), 3);
let b: &[_] = &[1, 2, 3, 4];
assert_eq!(buf.as_slice(), b);
assert_eq!(reader.read(&mut buf), Ok(3));
let b: &[_] = &[5, 6, 7];
assert_eq!(&buf[..3], b);
assert_eq!(reader.read(&mut buf), Ok(0));
}
#[test]
fn test_buf_reader() {
let in_buf = vec![0u8, 1, 2, 3, 4, 5, 6, 7];
let mut reader = Cursor::new(in_buf.as_slice());
let mut buf = [];
assert_eq!(reader.read(&mut buf), Ok(0));
assert_eq!(reader.position(), 0);
let mut buf = [0];
assert_eq!(reader.read(&mut buf), Ok(1));
assert_eq!(reader.position(), 1);
let b: &[_] = &[0];
assert_eq!(buf, b);
let mut buf = [0; 4];
assert_eq!(reader.read(&mut buf), Ok(4));
assert_eq!(reader.position(), 5);
let b: &[_] = &[1, 2, 3, 4];
assert_eq!(buf, b);
assert_eq!(reader.read(&mut buf), Ok(3));
let b: &[_] = &[5, 6, 7];
assert_eq!(&buf[..3], b);
assert_eq!(reader.read(&mut buf), Ok(0));
}
#[test]
fn test_read_char() {
let b = b"Vi\xE1\xBB\x87t";
let mut c = Cursor::new(b).chars();
assert_eq!(c.next(), Some(Ok('V')));
assert_eq!(c.next(), Some(Ok('i')));
assert_eq!(c.next(), Some(Ok('ệ')));
assert_eq!(c.next(), Some(Ok('t')));
assert_eq!(c.next(), None);
}
#[test]
fn test_read_bad_char() {
let b = b"\x80";
let mut c = Cursor::new(b).chars();
assert!(c.next().unwrap().is_err());
}
#[test]
fn seek_past_end() {
let buf = [0xff];
let mut r = Cursor::new(&buf[]);
assert_eq!(r.seek(SeekFrom::Start(10)), Ok(10));
assert_eq!(r.read(&mut [0]), Ok(0));
let mut r = Cursor::new(vec!(10u8));
assert_eq!(r.seek(SeekFrom::Start(10)), Ok(10));
assert_eq!(r.read(&mut [0]), Ok(0));
let mut buf = [0];
let mut r = Cursor::new(&mut buf[]);
assert_eq!(r.seek(SeekFrom::Start(10)), Ok(10));
assert_eq!(r.write(&[3]), Ok(0));
}
#[test]
fn seek_before_0() {
let buf = [0xff_u8];
let mut r = Cursor::new(&buf[]);
assert!(r.seek(SeekFrom::End(-2)).is_err());
let mut r = Cursor::new(vec!(10u8));
assert!(r.seek(SeekFrom::End(-2)).is_err());
let mut buf = [0];
let mut r = Cursor::new(&mut buf[]);
assert!(r.seek(SeekFrom::End(-2)).is_err());
}
#[test]
fn test_seekable_mem_writer() {
let mut writer = Cursor::new(Vec::<u8>::new());
assert_eq!(writer.position(), 0);
assert_eq!(writer.write(&[0]), Ok(1));
assert_eq!(writer.position(), 1);
assert_eq!(writer.write(&[1, 2, 3]), Ok(3));
assert_eq!(writer.write(&[4, 5, 6, 7]), Ok(4));
assert_eq!(writer.position(), 8);
let b: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7];
assert_eq!(&writer.get_ref()[], b);
assert_eq!(writer.seek(SeekFrom::Start(0)), Ok(0));
assert_eq!(writer.position(), 0);
assert_eq!(writer.write(&[3, 4]), Ok(2));
let b: &[_] = &[3, 4, 2, 3, 4, 5, 6, 7];
assert_eq!(&writer.get_ref()[], b);
assert_eq!(writer.seek(SeekFrom::Current(1)), Ok(3));
assert_eq!(writer.write(&[0, 1]), Ok(2));
let b: &[_] = &[3, 4, 2, 0, 1, 5, 6, 7];
assert_eq!(&writer.get_ref()[], b);
assert_eq!(writer.seek(SeekFrom::End(-1)), Ok(7));
assert_eq!(writer.write(&[1, 2]), Ok(2));
let b: &[_] = &[3, 4, 2, 0, 1, 5, 6, 1, 2];
assert_eq!(&writer.get_ref()[], b);
assert_eq!(writer.seek(SeekFrom::End(1)), Ok(10));
assert_eq!(writer.write(&[1]), Ok(1));
let b: &[_] = &[3, 4, 2, 0, 1, 5, 6, 1, 2, 0, 1];
assert_eq!(&writer.get_ref()[], b);
}
#[test]
fn vec_seek_past_end() {
let mut r = Cursor::new(Vec::new());
assert_eq!(r.seek(SeekFrom::Start(10)), Ok(10));
assert_eq!(r.write(&[3]), Ok(1));
}
#[test]
fn vec_seek_before_0() {
let mut r = Cursor::new(Vec::new());
assert!(r.seek(SeekFrom::End(-2)).is_err());
}
}

183
src/libstd/io/error.rs Normal file
View file

@ -0,0 +1,183 @@
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use boxed::Box;
use clone::Clone;
use error::Error as StdError;
use fmt;
use option::Option::{self, Some, None};
use result;
use string::String;
use sys;
/// A type for results generated by I/O related functions where the `Err` type
/// is hard-wired to `io::Error`.
///
/// This typedef is generally used to avoid writing out `io::Error` directly and
/// is otherwise a direct mapping to `std::result::Result`.
pub type Result<T> = result::Result<T, Error>;
/// The error type for I/O operations of the `Read`, `Write`, `Seek`, and
/// associated traits.
///
/// Errors mostly originate from the underlying OS, but custom instances of
/// `Error` can be created with crafted error messages and a particular value of
/// `ErrorKind`.
#[derive(PartialEq, Eq, Clone, Debug)]
pub struct Error {
repr: Repr,
}
#[derive(PartialEq, Eq, Clone, Debug)]
enum Repr {
Os(i32),
Custom(Box<Custom>),
}
#[derive(PartialEq, Eq, Clone, Debug)]
struct Custom {
kind: ErrorKind,
desc: &'static str,
detail: Option<String>
}
/// A list specifying general categories of I/O error.
#[derive(Copy, PartialEq, Eq, Clone, Debug)]
pub enum ErrorKind {
/// The file was not found.
FileNotFound,
/// The file permissions disallowed access to this file.
PermissionDenied,
/// The connection was refused by the remote server.
ConnectionRefused,
/// The connection was reset by the remote server.
ConnectionReset,
/// The connection was aborted (terminated) by the remote server.
ConnectionAborted,
/// The network operation failed because it was not connected yet.
NotConnected,
/// The operation failed because a pipe was closed.
BrokenPipe,
/// A file already existed with that name.
PathAlreadyExists,
/// No file exists at that location.
PathDoesntExist,
/// The path did not specify the type of file that this operation required.
/// For example, attempting to copy a directory with the `fs::copy()`
/// operation will fail with this error.
MismatchedFileTypeForOperation,
/// The operation temporarily failed (for example, because a signal was
/// received), and retrying may succeed.
ResourceUnavailable,
/// A parameter was incorrect in a way that caused an I/O error not part of
/// this list.
InvalidInput,
/// The I/O operation's timeout expired, causing it to be canceled.
TimedOut,
/// An error returned when an operation could not be completed because a
/// call to `write` returned `Ok(0)`.
///
/// This typically means that an operation could only succeed if it wrote a
/// particular number of bytes but only a smaller number of bytes could be
/// written.
WriteZero,
/// This operation was interrupted
Interrupted,
/// Any I/O error not part of this list.
Other,
}
impl Error {
/// Creates a new custom error from a specified kind/description/detail.
pub fn new(kind: ErrorKind,
description: &'static str,
detail: Option<String>) -> Error {
Error {
repr: Repr::Custom(Box::new(Custom {
kind: kind,
desc: description,
detail: detail,
}))
}
}
/// Returns an error representing the last OS error which occurred.
///
/// This function reads the value of `errno` for the target platform (e.g.
/// `GetLastError` on Windows) and will return a corresponding instance of
/// `Error` for the error code.
pub fn last_os_error() -> Error {
Error::from_os_error(sys::os::errno() as i32)
}
/// Creates a new instance of an `Error` from a particular OS error code.
pub fn from_os_error(code: i32) -> Error {
Error { repr: Repr::Os(code) }
}
/// Return the corresponding `ErrorKind` for this error.
pub fn kind(&self) -> ErrorKind {
match self.repr {
Repr::Os(code) => sys::decode_error_kind(code),
Repr::Custom(ref c) => c.kind,
}
}
/// Returns a short description for this error message
pub fn description(&self) -> &str {
match self.repr {
Repr::Os(..) => "os error",
Repr::Custom(ref c) => c.desc,
}
}
/// Returns a detailed error message for this error (if one is available)
pub fn detail(&self) -> Option<String> {
match self.repr {
Repr::Os(code) => Some(sys::os::error_string(code)),
Repr::Custom(ref s) => s.detail.clone(),
}
}
}
impl fmt::Display for Error {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
match self.repr {
Repr::Os(code) => {
let detail = sys::os::error_string(code);
write!(fmt, "{} (os error {})", detail, code)
}
Repr::Custom(ref c) => {
match **c {
Custom {
kind: ErrorKind::Other,
desc: "unknown error",
detail: Some(ref detail)
} => {
write!(fmt, "{}", detail)
}
Custom { detail: None, desc, .. } =>
write!(fmt, "{}", desc),
Custom { detail: Some(ref detail), desc, .. } =>
write!(fmt, "{} ({})", desc, detail)
}
}
}
}
}
impl StdError for Error {
fn description(&self) -> &str {
match self.repr {
Repr::Os(..) => "os error",
Repr::Custom(ref c) => c.desc,
}
}
}

88
src/libstd/io/impls.rs Normal file
View file

@ -0,0 +1,88 @@
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use core::prelude::*;
use boxed::Box;
use cmp;
use io::{self, SeekFrom, Read, Write, Seek, BufRead};
use mem;
use slice;
use vec::Vec;
// =============================================================================
// Forwarding implementations
impl<'a, R: Read + ?Sized> Read for &'a mut R {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { (**self).read(buf) }
}
impl<'a, W: Write + ?Sized> Write for &'a mut W {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> { (**self).write(buf) }
fn flush(&mut self) -> io::Result<()> { (**self).flush() }
}
impl<'a, S: Seek + ?Sized> Seek for &'a mut S {
fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> { (**self).seek(pos) }
}
impl<'a, B: BufRead + ?Sized> BufRead for &'a mut B {
fn fill_buf(&mut self) -> io::Result<&[u8]> { (**self).fill_buf() }
fn consume(&mut self, amt: usize) { (**self).consume(amt) }
}
impl<R: Read + ?Sized> Read for Box<R> {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { (**self).read(buf) }
}
impl<W: Write + ?Sized> Write for Box<W> {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> { (**self).write(buf) }
fn flush(&mut self) -> io::Result<()> { (**self).flush() }
}
impl<S: Seek + ?Sized> Seek for Box<S> {
fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> { (**self).seek(pos) }
}
impl<B: BufRead + ?Sized> BufRead for Box<B> {
fn fill_buf(&mut self) -> io::Result<&[u8]> { (**self).fill_buf() }
fn consume(&mut self, amt: usize) { (**self).consume(amt) }
}
// =============================================================================
// In-memory buffer implementations
impl<'a> Read for &'a [u8] {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
let amt = cmp::min(buf.len(), self.len());
let (a, b) = self.split_at(amt);
slice::bytes::copy_memory(buf, a);
*self = b;
Ok(amt)
}
}
impl<'a> BufRead for &'a [u8] {
fn fill_buf(&mut self) -> io::Result<&[u8]> { Ok(*self) }
fn consume(&mut self, amt: usize) { *self = &self[amt..]; }
}
impl<'a> Write for &'a mut [u8] {
fn write(&mut self, data: &[u8]) -> io::Result<usize> {
let amt = cmp::min(data.len(), self.len());
let (a, b) = mem::replace(self, &mut []).split_at_mut(amt);
slice::bytes::copy_memory(a, &data[..amt]);
*self = b;
Ok(amt)
}
fn flush(&mut self) -> io::Result<()> { Ok(()) }
}
impl Write for Vec<u8> {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
self.push_all(buf);
Ok(buf.len())
}
fn flush(&mut self) -> io::Result<()> { Ok(()) }
}

948
src/libstd/io/mod.rs Normal file
View file

@ -0,0 +1,948 @@
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//! Traits, helpers, and type definitions for core I/O functionality.
//!
//! > **NOTE**: This module is very much a work in progress and is under active
//! > development. At this time it is still recommended to use the `old_io`
//! > module while the details of this module shake out.
#![unstable(feature = "io",
reason = "this new I/O module is still under active deveopment and \
APIs are subject to tweaks fairly regularly")]
use cmp;
use unicode::str as core_str;
use error::Error as StdError;
use fmt;
use iter::Iterator;
use marker::Sized;
use mem;
use ops::{Drop, FnOnce};
use option::Option::{self, Some, None};
use ptr::PtrExt;
use result::Result::{Ok, Err};
use result;
use slice::{self, SliceExt};
use string::String;
use str::{self, StrExt};
use vec::Vec;
pub use self::buffered::{BufReader, BufWriter, BufStream, LineWriter};
pub use self::buffered::IntoInnerError;
pub use self::cursor::Cursor;
pub use self::error::{Result, Error, ErrorKind};
pub use self::util::{copy, sink, Sink, empty, Empty, repeat, Repeat};
pub mod prelude;
mod buffered;
mod cursor;
mod error;
mod impls;
mod util;
const DEFAULT_BUF_SIZE: usize = 64 * 1024;
// Acquires a slice of the vector `v` from its length to its capacity
// (uninitialized data), reads into it, and then updates the length.
//
// This function is leveraged to efficiently read some bytes into a destination
// vector without extra copying and taking advantage of the space that's already
// in `v`.
//
// The buffer we're passing down, however, is pointing at uninitialized data
// (the end of a `Vec`), and many operations will be *much* faster if we don't
// have to zero it out. In order to prevent LLVM from generating an `undef`
// value when reads happen from this uninitialized memory, we force LLVM to
// think it's initialized by sending it through a black box. This should prevent
// actual undefined behavior after optimizations.
fn with_end_to_cap<F>(v: &mut Vec<u8>, f: F) -> Result<usize>
where F: FnOnce(&mut [u8]) -> Result<usize>
{
unsafe {
let n = try!(f({
let base = v.as_mut_ptr().offset(v.len() as isize);
black_box(slice::from_raw_mut_buf(mem::copy_lifetime(v, &base),
v.capacity() - v.len()))
}));
// If the closure (typically a `read` implementation) reported that it
// read a larger number of bytes than the vector actually has, we need
// to be sure to clamp the vector to at most its capacity.
let new_len = cmp::min(v.capacity(), v.len() + n);
v.set_len(new_len);
return Ok(n);
}
// Semi-hack used to prevent LLVM from retaining any assumptions about
// `dummy` over this function call
unsafe fn black_box<T>(mut dummy: T) -> T {
asm!("" :: "r"(&mut dummy) : "memory");
dummy
}
}
// A few methods below (read_to_string, read_line) will append data into a
// `String` buffer, but we need to be pretty careful when doing this. The
// implementation will just call `.as_mut_vec()` and then delegate to a
// byte-oriented reading method, but we must ensure that when returning we never
// leave `buf` in a state such that it contains invalid UTF-8 in its bounds.
//
// To this end, we use an RAII guard (to protect against panics) which updates
// the length of the string when it is dropped. This guard initially truncates
// the string to the prior length and only afer we've validated that the
// new contents are valid UTF-8 do we allow it to set a longer length.
//
// The unsafety in this function is twofold:
//
// 1. We're looking at the raw bytes of `buf`, so we take on the burden of UTF-8
// checks.
// 2. We're passing a raw buffer to the function `f`, and it is expected that
// the function only *appends* bytes to the buffer. We'll get undefined
// behavior if existing bytes are overwritten to have non-UTF-8 data.
fn append_to_string<F>(buf: &mut String, f: F) -> Result<()>
where F: FnOnce(&mut Vec<u8>) -> Result<()>
{
struct Guard<'a> { s: &'a mut Vec<u8>, len: usize }
#[unsafe_destructor]
impl<'a> Drop for Guard<'a> {
fn drop(&mut self) {
unsafe { self.s.set_len(self.len); }
}
}
unsafe {
let mut g = Guard { len: buf.len(), s: buf.as_mut_vec() };
let ret = f(g.s);
if str::from_utf8(&g.s[g.len..]).is_err() {
ret.and_then(|()| {
Err(Error::new(ErrorKind::InvalidInput,
"stream did not contain valid UTF-8", None))
})
} else {
g.len = g.s.len();
ret
}
}
}
fn read_to_end<R: Read + ?Sized>(r: &mut R, buf: &mut Vec<u8>) -> Result<()> {
loop {
if buf.capacity() == buf.len() {
buf.reserve(DEFAULT_BUF_SIZE);
}
match with_end_to_cap(buf, |b| r.read(b)) {
Ok(0) => return Ok(()),
Ok(_) => {}
Err(ref e) if e.kind() == ErrorKind::Interrupted => {}
Err(e) => return Err(e),
}
}
}
/// A trait for objects which are byte-oriented sources.
///
/// Readers are defined by one method, `read`. Each call to `read` will attempt
/// to pull bytes from this source into a provided buffer.
///
/// Readers are intended to be composable with one another. Many objects
/// throughout the I/O and related libraries take and provide types which
/// implement the `Read` trait.
pub trait Read {
/// Pull some bytes from this source into the specified buffer, returning
/// how many bytes were read.
///
/// This function does not provide any guarantees about whether it blocks
/// waiting for data, but if an object needs to block for a read but cannot
/// it will typically signal this via an `Err` return value.
///
/// If the return value of this method is `Ok(n)`, then it must be
/// guaranteed that `0 <= n <= buf.len()`. A nonzero `n` value indicates
/// that the buffer `buf` has ben filled in with `n` bytes of data from this
/// source. If `n` is `0`, then it can indicate one of two scenarios:
///
/// 1. This reader has reached its "end of file" and will likely no longer
/// be able to produce bytes. Note that this does not mean that the
/// reader will *always* no longer be able to produce bytes.
/// 2. The buffer specified was 0 bytes in length.
///
/// No guarantees are provided about the contents of `buf` when this
/// function is called, implementations cannot rely on any property of the
/// contents of `buf` being true. It is recommended that implementations
/// only write data to `buf` instead of reading its contents.
///
/// # Errors
///
/// If this function encounters any form of I/O or other error, an error
/// variant will be returned. If an error is returned then it must be
/// guaranteed that no bytes were read.
fn read(&mut self, buf: &mut [u8]) -> Result<usize>;
/// Read all bytes until EOF in this source, placing them into `buf`.
///
/// All bytes read from this source will be appended to the specified buffer
/// `buf`. This function will return a call to `read` either:
///
/// 1. Returns `Ok(0)`.
/// 2. Returns an error which is not of the kind `ErrorKind::Interrupted`.
///
/// Until one of these conditions is met the function will continuously
/// invoke `read` to append more data to `buf`.
///
/// # Errors
///
/// If this function encounters an error of the kind
/// `ErrorKind::Interrupted` then the error is ignored and the operation
/// will continue.
///
/// If any other read error is encountered then this function immediately
/// returns. Any bytes which have already been read will be appended to
/// `buf`.
fn read_to_end(&mut self, buf: &mut Vec<u8>) -> Result<()> {
read_to_end(self, buf)
}
/// Read all bytes until EOF in this source, placing them into `buf`.
///
/// # Errors
///
/// If the data in this stream is *not* valid UTF-8 then an error is
/// returned and `buf` is unchanged.
///
/// See `read_to_end` for other error semantics.
fn read_to_string(&mut self, buf: &mut String) -> Result<()> {
// Note that we do *not* call `.read_to_end()` here. We are passing
// `&mut Vec<u8>` (the raw contents of `buf`) into the `read_to_end`
// method to fill it up. An arbitrary implementation could overwrite the
// entire contents of the vector, not just append to it (which is what
// we are expecting).
//
// To prevent extraneously checking the UTF-8-ness of the entire buffer
// we pass it to our hardcoded `read_to_end` implementation which we
// know is guaranteed to only read data into the end of the buffer.
append_to_string(buf, |b| read_to_end(self, b))
}
}
/// Extension methods for all instances of `Read`, typically imported through
/// `std::io::prelude::*`.
pub trait ReadExt: Read + Sized {
/// Create a "by reference" adaptor for this instance of `Read`.
///
/// The returned adaptor also implements `Read` and will simply borrow this
/// current reader.
fn by_ref(&mut self) -> &mut Self { self }
/// Transform this `Read` instance to an `Iterator` over its bytes.
///
/// The returned type implements `Iterator` where the `Item` is `Result<u8,
/// R::Err>`. The yielded item is `Ok` if a byte was successfully read and
/// `Err` otherwise for I/O errors. EOF is mapped to returning `None` from
/// this iterator.
fn bytes(self) -> Bytes<Self> {
Bytes { inner: self }
}
/// Transform this `Read` instance to an `Iterator` over `char`s.
///
/// This adaptor will attempt to interpret this reader as an UTF-8 encoded
/// sequence of characters. The returned iterator will return `None` once
/// EOF is reached for this reader. Otherwise each element yielded will be a
/// `Result<char, E>` where `E` may contain information about what I/O error
/// occurred or where decoding failed.
///
/// Currently this adaptor will discard intermediate data read, and should
/// be avoided if this is not desired.
fn chars(self) -> Chars<Self> {
Chars { inner: self }
}
/// Create an adaptor which will chain this stream with another.
///
/// The returned `Read` instance will first read all bytes from this object
/// until EOF is encountered. Afterwards the output is equivalent to the
/// output of `next`.
fn chain<R: Read>(self, next: R) -> Chain<Self, R> {
Chain { first: self, second: next, done_first: false }
}
/// Create an adaptor which will read at most `limit` bytes from it.
///
/// This function returns a new instance of `Read` which will read at most
/// `limit` bytes, after which it will always return EOF (`Ok(0)`). Any
/// read errors will not count towards the number of bytes read and future
/// calls to `read` may succeed.
fn take(self, limit: u64) -> Take<Self> {
Take { inner: self, limit: limit }
}
/// Creates a reader adaptor which will write all read data into the given
/// output stream.
///
/// Whenever the returned `Read` instance is read it will write the read
/// data to `out`. The current semantics of this implementation imply that
/// a `write` error will not report how much data was initially read.
fn tee<W: Write>(self, out: W) -> Tee<Self, W> {
Tee { reader: self, writer: out }
}
}
impl<T: Read> ReadExt for T {}
/// A trait for objects which are byte-oriented sinks.
///
/// The `write` method will attempt to write some data into the object,
/// returning how many bytes were successfully written.
///
/// The `flush` method is useful for adaptors and explicit buffers themselves
/// for ensuring that all buffered data has been pushed out to the "true sink".
///
/// Writers are intended to be composable with one another. Many objects
/// throughout the I/O and related libraries take and provide types which
/// implement the `Write` trait.
pub trait Write {
/// Write a buffer into this object, returning how many bytes were written.
///
/// This function will attempt to write the entire contents of `buf`, but
/// the entire write may not succeed, or the write may also generate an
/// error. A call to `write` represents *at most one* attempt to write to
/// any wrapped object.
///
/// Calls to `write` are not guaranteed to block waiting for data to be
/// written, and a write which would otherwise block can indicated through
/// an `Err` variant.
///
/// If the return value is `Ok(n)` then it must be guaranteed that
/// `0 <= n <= buf.len()`. A return value of `0` typically means that the
/// underlying object is no longer able to accept bytes and will likely not
/// be able to in the future as well, or that the buffer provided is empty.
///
/// # Errors
///
/// Each call to `write` may generate an I/O error indicating that the
/// operation could not be completed. If an error is returned then no bytes
/// in the buffer were written to this writer.
///
/// It is **not** considered an error if the entire buffer could not be
/// written to this writer.
fn write(&mut self, buf: &[u8]) -> Result<usize>;
/// Flush this output stream, ensuring that all intermediately buffered
/// contents reach their destination.
///
/// # Errors
///
/// It is considered an error if not all bytes could be written due to
/// I/O errors or EOF being reached.
fn flush(&mut self) -> Result<()>;
/// Attempts to write an entire buffer into this write.
///
/// This method will continuously call `write` while there is more data to
/// write. This method will not return until the entire buffer has been
/// successfully written or an error occurs. The first error generated from
/// this method will be returned.
///
/// # Errors
///
/// This function will return the first error that `write` returns.
fn write_all(&mut self, mut buf: &[u8]) -> Result<()> {
while buf.len() > 0 {
match self.write(buf) {
Ok(0) => return Err(Error::new(ErrorKind::WriteZero,
"failed to write whole buffer",
None)),
Ok(n) => buf = &buf[n..],
Err(ref e) if e.kind() == ErrorKind::Interrupted => {}
Err(e) => return Err(e),
}
}
Ok(())
}
/// Writes a formatted string into this writer, returning any error
/// encountered.
///
/// This method is primarily used to interface with the `format_args!`
/// macro, but it is rare that this should explicitly be called. The
/// `write!` macro should be favored to invoke this method instead.
///
/// This function internally uses the `write_all` method on this trait and
/// hence will continuously write data so long as no errors are received.
/// This also means that partial writes are not indicated in this signature.
///
/// # Errors
///
/// This function will return any I/O error reported while formatting.
fn write_fmt(&mut self, fmt: fmt::Arguments) -> Result<()> {
// Create a shim which translates a Writer to a fmt::Writer and saves
// off I/O errors. instead of discarding them
struct Adaptor<'a, T: ?Sized + 'a> {
inner: &'a mut T,
error: Result<()>,
}
impl<'a, T: Write + ?Sized> fmt::Writer for Adaptor<'a, T> {
fn write_str(&mut self, s: &str) -> fmt::Result {
match self.inner.write_all(s.as_bytes()) {
Ok(()) => Ok(()),
Err(e) => {
self.error = Err(e);
Err(fmt::Error)
}
}
}
}
let mut output = Adaptor { inner: self, error: Ok(()) };
match fmt::write(&mut output, fmt) {
Ok(()) => Ok(()),
Err(..) => output.error
}
}
}
/// Extension methods for all instances of `Write`, typically imported through
/// `std::io::prelude::*`.
pub trait WriteExt: Write + Sized {
/// Create a "by reference" adaptor for this instance of `Write`.
///
/// The returned adaptor also implements `Write` and will simply borrow this
/// current writer.
fn by_ref(&mut self) -> &mut Self { self }
/// Creates a new writer which will write all data to both this writer and
/// another writer.
///
/// All data written to the returned writer will both be written to `self`
/// as well as `other`. Note that the error semantics of the current
/// implementation do not precisely track where errors happen. For example
/// an error on the second call to `write` will not report that the first
/// call to `write` succeeded.
fn broadcast<W: Write>(self, other: W) -> Broadcast<Self, W> {
Broadcast { first: self, second: other }
}
}
impl<T: Write> WriteExt for T {}
/// An object implementing `Seek` internally has some form of cursor which can
/// be moved within a stream of bytes.
///
/// The stream typically has a fixed size, allowing seeking relative to either
/// end or the current offset.
pub trait Seek {
/// Seek to an offset, in bytes, in a stream
///
/// A seek beyond the end of a stream is allowed, but seeking before offset
/// 0 is an error.
///
/// Seeking past the end of the stream does not modify the underlying
/// stream, but the next write may cause the previous data to be filled in
/// with a bit pattern.
///
/// This method returns the new position within the stream if the seek
/// operation completed successfully.
///
/// # Errors
///
/// Seeking to a negative offset is considered an error
fn seek(&mut self, pos: SeekFrom) -> Result<u64>;
}
/// Enumeration of possible methods to seek within an I/O object.
#[derive(Copy, PartialEq, Eq, Clone, Debug)]
pub enum SeekFrom {
/// Set the offset to the provided number of bytes.
Start(u64),
/// Set the offset to the size of this object plus the specified number of
/// bytes.
///
/// It is possible to seek beyond the end of an object, but is an error to
/// seek before byte 0.
End(i64),
/// Set the offset to the current position plus the specified number of
/// bytes.
///
/// It is possible to seek beyond the end of an object, but is an error to
/// seek before byte 0.
Current(i64),
}
fn read_until<R: BufRead + ?Sized>(r: &mut R, delim: u8, buf: &mut Vec<u8>)
-> Result<()> {
loop {
let (done, used) = {
let available = match r.fill_buf() {
Ok(n) => n,
Err(ref e) if e.kind() == ErrorKind::Interrupted => continue,
Err(e) => return Err(e)
};
match available.position_elem(&delim) {
Some(i) => {
buf.push_all(&available[..i + 1]);
(true, i + 1)
}
None => {
buf.push_all(available);
(false, available.len())
}
}
};
r.consume(used);
if done || used == 0 {
return Ok(());
}
}
}
/// A Buffer is a type of reader which has some form of internal buffering to
/// allow certain kinds of reading operations to be more optimized than others.
///
/// This type extends the `Read` trait with a few methods that are not
/// possible to reasonably implement with purely a read interface.
pub trait BufRead: Read {
/// Fills the internal buffer of this object, returning the buffer contents.
///
/// None of the contents will be "read" in the sense that later calling
/// `read` may return the same contents.
///
/// The `consume` function must be called with the number of bytes that are
/// consumed from this buffer returned to ensure that the bytes are never
/// returned twice.
///
/// An empty buffer returned indicates that the stream has reached EOF.
///
/// # Errors
///
/// This function will return an I/O error if the underlying reader was
/// read, but returned an error.
fn fill_buf(&mut self) -> Result<&[u8]>;
/// Tells this buffer that `amt` bytes have been consumed from the buffer,
/// so they should no longer be returned in calls to `read`.
fn consume(&mut self, amt: usize);
/// Read all bytes until the delimiter `byte` is reached.
///
/// This function will continue to read (and buffer) bytes from the
/// underlying stream until the delimiter or EOF is found. Once found, all
/// bytes up to, and including, the delimiter (if found) will be appended to
/// `buf`.
///
/// If this buffered reader is currently at EOF, then this function will not
/// place any more bytes into `buf` and will return `Ok(())`.
///
/// # Errors
///
/// This function will ignore all instances of `ErrorKind::Interrupted` and
/// will otherwise return any errors returned by `fill_buf`.
///
/// If an I/O error is encountered then all bytes read so far will be
/// present in `buf` and its length will have been adjusted appropriately.
fn read_until(&mut self, byte: u8, buf: &mut Vec<u8>) -> Result<()> {
read_until(self, byte, buf)
}
/// Read all bytes until a newline byte (the 0xA byte) is reached.
///
/// This function will continue to read (and buffer) bytes from the
/// underlying stream until the newline delimiter (the 0xA byte) or EOF is
/// found. Once found, all bytes up to, and including, the delimiter (if
/// found) will be appended to `buf`.
///
/// If this reader is currently at EOF then this function will not modify
/// `buf` and will return `Ok(())`.
///
/// # Errors
///
/// This function has the same error semantics as `read_until` and will also
/// return an error if the read bytes are not valid UTF-8. If an I/O error
/// is encountered then `buf` may contain some bytes already read in the
/// event that all data read so far was valid UTF-8.
fn read_line(&mut self, buf: &mut String) -> Result<()> {
// Note that we are not calling the `.read_until` method here, but
// rather our hardcoded implementation. For more details as to why, see
// the comments in `read_to_end`.
append_to_string(buf, |b| read_until(self, b'\n', b))
}
}
/// Extension methods for all instances of `BufRead`, typically imported through
/// `std::io::prelude::*`.
pub trait BufReadExt: BufRead + Sized {
/// Returns an iterator over the contents of this reader split on the byte
/// `byte`.
///
/// The iterator returned from this function will return instances of
/// `io::Result<Vec<u8>>`. Each vector returned will *not* have the
/// delimiter byte at the end.
///
/// This function will yield errors whenever `read_until` would have also
/// yielded an error.
fn split(self, byte: u8) -> Split<Self> {
Split { buf: self, delim: byte }
}
/// Returns an iterator over the lines of this reader.
///
/// The iterator returned from this function will yield instances of
/// `io::Result<String>`. Each string returned will *not* have a newline
/// byte (the 0xA byte) at the end.
///
/// This function will yield errors whenever `read_string` would have also
/// yielded an error.
fn lines(self) -> Lines<Self> {
Lines { buf: self }
}
}
impl<T: BufRead> BufReadExt for T {}
/// A `Write` adaptor which will write data to multiple locations.
///
/// For more information, see `WriteExt::broadcast`.
pub struct Broadcast<T, U> {
first: T,
second: U,
}
impl<T: Write, U: Write> Write for Broadcast<T, U> {
fn write(&mut self, data: &[u8]) -> Result<usize> {
let n = try!(self.first.write(data));
// FIXME: what if the write fails? (we wrote something)
try!(self.second.write_all(&data[..n]));
Ok(n)
}
fn flush(&mut self) -> Result<()> {
self.first.flush().and(self.second.flush())
}
}
/// Adaptor to chain together two instances of `Read`.
///
/// For more information, see `ReadExt::chain`.
pub struct Chain<T, U> {
first: T,
second: U,
done_first: bool,
}
impl<T: Read, U: Read> Read for Chain<T, U> {
fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
if !self.done_first {
match try!(self.first.read(buf)) {
0 => { self.done_first = true; }
n => return Ok(n),
}
}
self.second.read(buf)
}
}
/// Reader adaptor which limits the bytes read from an underlying reader.
///
/// For more information, see `ReadExt::take`.
pub struct Take<T> {
inner: T,
limit: u64,
}
impl<T> Take<T> {
/// Returns the number of bytes that can be read before this instance will
/// return EOF.
///
/// # Note
///
/// This instance may reach EOF after reading fewer bytes than indiccated by
/// this method if the underlying `Read` instance reaches EOF.
pub fn limit(&self) -> u64 { self.limit }
}
impl<T: Read> Read for Take<T> {
fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
let max = cmp::min(buf.len() as u64, self.limit) as usize;
let n = try!(self.inner.read(&mut buf[..max]));
self.limit -= n as u64;
Ok(n)
}
}
/// An adaptor which will emit all read data to a specified writer as well.
///
/// For more information see `ReadExt::tee`
pub struct Tee<R, W> {
reader: R,
writer: W,
}
impl<R: Read, W: Write> Read for Tee<R, W> {
fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
let n = try!(self.reader.read(buf));
// FIXME: what if the write fails? (we read something)
try!(self.writer.write_all(&buf[..n]));
Ok(n)
}
}
/// A bridge from implementations of `Read` to an `Iterator` of `u8`.
///
/// See `ReadExt::bytes` for more information.
pub struct Bytes<R> {
inner: R,
}
impl<R: Read> Iterator for Bytes<R> {
type Item = Result<u8>;
fn next(&mut self) -> Option<Result<u8>> {
let mut buf = [0];
match self.inner.read(&mut buf) {
Ok(0) => None,
Ok(..) => Some(Ok(buf[0])),
Err(e) => Some(Err(e)),
}
}
}
/// A bridge from implementations of `Read` to an `Iterator` of `char`.
///
/// See `ReadExt::chars` for more information.
pub struct Chars<R> {
inner: R,
}
/// An enumeration of possible errors that can be generated from the `Chars`
/// adapter.
#[derive(PartialEq, Clone, Debug)]
pub enum CharsError {
/// Variant representing that the underlying stream was read successfully
/// but it did not contain valid utf8 data.
NotUtf8,
/// Variant representing that an I/O error occurred.
Other(Error),
}
impl<R: Read> Iterator for Chars<R> {
type Item = result::Result<char, CharsError>;
fn next(&mut self) -> Option<result::Result<char, CharsError>> {
let mut buf = [0];
let first_byte = match self.inner.read(&mut buf) {
Ok(0) => return None,
Ok(..) => buf[0],
Err(e) => return Some(Err(CharsError::Other(e))),
};
let width = core_str::utf8_char_width(first_byte);
if width == 1 { return Some(Ok(first_byte as char)) }
if width == 0 { return Some(Err(CharsError::NotUtf8)) }
let mut buf = [first_byte, 0, 0, 0];
{
let mut start = 1;
while start < width {
match self.inner.read(&mut buf[start..width]) {
Ok(0) => return Some(Err(CharsError::NotUtf8)),
Ok(n) => start += n,
Err(e) => return Some(Err(CharsError::Other(e))),
}
}
}
Some(match str::from_utf8(&buf[..width]).ok() {
Some(s) => Ok(s.char_at(0)),
None => Err(CharsError::NotUtf8),
})
}
}
impl StdError for CharsError {
fn description(&self) -> &str {
match *self {
CharsError::NotUtf8 => "invalid utf8 encoding",
CharsError::Other(ref e) => e.description(),
}
}
fn cause(&self) -> Option<&StdError> {
match *self {
CharsError::NotUtf8 => None,
CharsError::Other(ref e) => e.cause(),
}
}
}
impl fmt::Display for CharsError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
CharsError::NotUtf8 => {
"byte stream did not contain valid utf8".fmt(f)
}
CharsError::Other(ref e) => e.fmt(f),
}
}
}
/// An iterator over the contents of an instance of `BufRead` split on a
/// particular byte.
///
/// See `BufReadExt::split` for more information.
pub struct Split<B> {
buf: B,
delim: u8,
}
impl<B: BufRead> Iterator for Split<B> {
type Item = Result<Vec<u8>>;
fn next(&mut self) -> Option<Result<Vec<u8>>> {
let mut buf = Vec::new();
match self.buf.read_until(self.delim, &mut buf) {
Ok(()) if buf.len() == 0 => None,
Ok(()) => {
if buf[buf.len() - 1] == self.delim {
buf.pop();
}
Some(Ok(buf))
}
Err(e) => Some(Err(e))
}
}
}
/// An iterator over the lines of an instance of `BufRead` split on a newline
/// byte.
///
/// See `BufReadExt::lines` for more information.
pub struct Lines<B> {
buf: B,
}
impl<B: BufRead> Iterator for Lines<B> {
type Item = Result<String>;
fn next(&mut self) -> Option<Result<String>> {
let mut buf = String::new();
match self.buf.read_line(&mut buf) {
Ok(()) if buf.len() == 0 => None,
Ok(()) => {
if buf.ends_with("\n") {
buf.pop();
}
Some(Ok(buf))
}
Err(e) => Some(Err(e))
}
}
}
#[cfg(test)]
mod tests {
use prelude::v1::*;
use io::prelude::*;
use super::Cursor;
#[test]
fn read_until() {
let mut buf = Cursor::new(b"12");
let mut v = Vec::new();
assert_eq!(buf.read_until(b'3', &mut v), Ok(()));
assert_eq!(v, b"12");
let mut buf = Cursor::new(b"1233");
let mut v = Vec::new();
assert_eq!(buf.read_until(b'3', &mut v), Ok(()));
assert_eq!(v, b"123");
v.truncate(0);
assert_eq!(buf.read_until(b'3', &mut v), Ok(()));
assert_eq!(v, b"3");
v.truncate(0);
assert_eq!(buf.read_until(b'3', &mut v), Ok(()));
assert_eq!(v, []);
}
#[test]
fn split() {
let mut buf = Cursor::new(b"12");
let mut s = buf.split(b'3');
assert_eq!(s.next(), Some(Ok(vec![b'1', b'2'])));
assert_eq!(s.next(), None);
let mut buf = Cursor::new(b"1233");
let mut s = buf.split(b'3');
assert_eq!(s.next(), Some(Ok(vec![b'1', b'2'])));
assert_eq!(s.next(), Some(Ok(vec![])));
assert_eq!(s.next(), None);
}
#[test]
fn read_line() {
let mut buf = Cursor::new(b"12");
let mut v = String::new();
assert_eq!(buf.read_line(&mut v), Ok(()));
assert_eq!(v, "12");
let mut buf = Cursor::new(b"12\n\n");
let mut v = String::new();
assert_eq!(buf.read_line(&mut v), Ok(()));
assert_eq!(v, "12\n");
v.truncate(0);
assert_eq!(buf.read_line(&mut v), Ok(()));
assert_eq!(v, "\n");
v.truncate(0);
assert_eq!(buf.read_line(&mut v), Ok(()));
assert_eq!(v, "");
}
#[test]
fn lines() {
let mut buf = Cursor::new(b"12");
let mut s = buf.lines();
assert_eq!(s.next(), Some(Ok("12".to_string())));
assert_eq!(s.next(), None);
let mut buf = Cursor::new(b"12\n\n");
let mut s = buf.lines();
assert_eq!(s.next(), Some(Ok("12".to_string())));
assert_eq!(s.next(), Some(Ok(String::new())));
assert_eq!(s.next(), None);
}
#[test]
fn read_to_end() {
let mut c = Cursor::new(b"");
let mut v = Vec::new();
assert_eq!(c.read_to_end(&mut v), Ok(()));
assert_eq!(v, []);
let mut c = Cursor::new(b"1");
let mut v = Vec::new();
assert_eq!(c.read_to_end(&mut v), Ok(()));
assert_eq!(v, b"1");
}
#[test]
fn read_to_string() {
let mut c = Cursor::new(b"");
let mut v = String::new();
assert_eq!(c.read_to_string(&mut v), Ok(()));
assert_eq!(v, "");
let mut c = Cursor::new(b"1");
let mut v = String::new();
assert_eq!(c.read_to_string(&mut v), Ok(()));
assert_eq!(v, "1");
let mut c = Cursor::new(b"\xff");
let mut v = String::new();
assert!(c.read_to_string(&mut v).is_err());
}
}

27
src/libstd/io/prelude.rs Normal file
View file

@ -0,0 +1,27 @@
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//! The I/O Prelude
//!
//! The purpose of this module is to alleviate imports of many common I/O traits
//! by adding a glob import to the top of I/O heavy modules:
//!
//! ```
//! use std::io::prelude::*;
//! ```
//!
//! This module contains reexports of many core I/O traits such as `Read`,
//! `Write`, `ReadExt`, and `WriteExt`. Structures and functions are not
//! contained in this module.
pub use super::{Read, ReadExt, Write, WriteExt, BufRead, BufReadExt};
// FIXME: pub use as `Seek` when the name isn't in the actual prelude any more
pub use super::Seek as NewSeek;

153
src/libstd/io/util.rs Normal file
View file

@ -0,0 +1,153 @@
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![allow(missing_copy_implementations)]
use prelude::v1::*;
use io::{self, Read, Write, ErrorKind};
/// Copies the entire contents of a reader into a writer.
///
/// This function will continuously read data from `r` and then write it into
/// `w` in a streaming fashion until `r` returns EOF.
///
/// On success the total number of bytes that were copied from `r` to `w` is
/// returned.
///
/// # Errors
///
/// This function will return an error immediately if any call to `read` or
/// `write` returns an error. All instances of `ErrorKind::Interrupted` are
/// handled by this function and the underlying operation is retried.
pub fn copy<R: Read, W: Write>(r: &mut R, w: &mut W) -> io::Result<u64> {
let mut buf = [0; super::DEFAULT_BUF_SIZE];
let mut written = 0;
loop {
let len = match r.read(&mut buf) {
Ok(0) => return Ok(written),
Ok(len) => len,
Err(ref e) if e.kind() == ErrorKind::Interrupted => continue,
Err(e) => return Err(e),
};
try!(w.write_all(&buf[..len]));
written += len as u64;
}
}
/// A reader which is always at EOF.
pub struct Empty { _priv: () }
/// Creates an instance of an empty reader.
///
/// All reads from the returned reader will return `Ok(0)`.
pub fn empty() -> Empty { Empty { _priv: () } }
impl Read for Empty {
fn read(&mut self, _buf: &mut [u8]) -> io::Result<usize> { Ok(0) }
}
/// A reader which infinitely yields one byte.
pub struct Repeat { byte: u8 }
/// Creates an instance of a reader that infinitely repeats one byte.
///
/// All reads from this reader will succeed by filling the specified buffer with
/// the given byte.
pub fn repeat(byte: u8) -> Repeat { Repeat { byte: byte } }
impl Read for Repeat {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
for slot in buf.iter_mut() {
*slot = self.byte;
}
Ok(buf.len())
}
}
/// A writer which will move data into the void.
pub struct Sink { _priv: () }
/// Creates an instance of a writer which will successfully consume all data.
///
/// All calls to `write` on the returned instance will return `Ok(buf.len())`
/// and the contents of the buffer will not be inspected.
pub fn sink() -> Sink { Sink { _priv: () } }
impl Write for Sink {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> { Ok(buf.len()) }
fn flush(&mut self) -> io::Result<()> { Ok(()) }
}
#[cfg(test)]
mod test {
use prelude::v1::*;
use io::prelude::*;
use io::{sink, empty, repeat};
#[test]
fn sink_sinks() {
let mut s = sink();
assert_eq!(s.write(&[]), Ok(0));
assert_eq!(s.write(&[0]), Ok(1));
assert_eq!(s.write(&[0; 1024]), Ok(1024));
assert_eq!(s.by_ref().write(&[0; 1024]), Ok(1024));
}
#[test]
fn empty_reads() {
let mut e = empty();
assert_eq!(e.read(&mut []), Ok(0));
assert_eq!(e.read(&mut [0]), Ok(0));
assert_eq!(e.read(&mut [0; 1024]), Ok(0));
assert_eq!(e.by_ref().read(&mut [0; 1024]), Ok(0));
}
#[test]
fn repeat_repeats() {
let mut r = repeat(4);
let mut b = [0; 1024];
assert_eq!(r.read(&mut b), Ok(1024));
assert!(b.iter().all(|b| *b == 4));
}
#[test]
fn take_some_bytes() {
assert_eq!(repeat(4).take(100).bytes().count(), 100);
assert_eq!(repeat(4).take(100).bytes().next(), Some(Ok(4)));
assert_eq!(repeat(1).take(10).chain(repeat(2).take(10)).bytes().count(), 20);
}
#[test]
fn tee() {
let mut buf = [0; 10];
{
let mut ptr: &mut [u8] = &mut buf;
assert_eq!(repeat(4).tee(&mut ptr).take(5).read(&mut [0; 10]), Ok(5));
}
assert_eq!(buf, [4, 4, 4, 4, 4, 0, 0, 0, 0, 0]);
}
#[test]
fn broadcast() {
let mut buf1 = [0; 10];
let mut buf2 = [0; 10];
{
let mut ptr1: &mut [u8] = &mut buf1;
let mut ptr2: &mut [u8] = &mut buf2;
assert_eq!((&mut ptr1).broadcast(&mut ptr2)
.write(&[1, 2, 3]), Ok(3));
}
assert_eq!(buf1, buf2);
assert_eq!(buf1, [1, 2, 3, 0, 0, 0, 0, 0, 0, 0]);
}
}

View file

@ -128,9 +128,8 @@
#![deny(missing_docs)]
#[cfg(test)]
#[macro_use]
extern crate log;
#[cfg(test)] extern crate test;
#[cfg(test)] #[macro_use] extern crate log;
#[macro_use]
#[macro_reexport(assert, assert_eq, debug_assert, debug_assert_eq,
@ -248,9 +247,11 @@ pub mod dynamic_lib;
pub mod ffi;
pub mod fmt;
pub mod old_io;
pub mod io;
pub mod os;
pub mod env;
pub mod path;
pub mod old_path;
pub mod rand;
pub mod time;

View file

@ -61,8 +61,8 @@ use old_io;
use iter::{Iterator, Extend};
use option::Option;
use option::Option::{Some, None};
use path::{Path, GenericPath};
use path;
use old_path::{Path, GenericPath};
use old_path;
use result::Result::{Err, Ok};
use slice::SliceExt;
use string::String;
@ -782,7 +782,7 @@ pub trait PathExtensions {
fn is_dir(&self) -> bool;
}
impl PathExtensions for path::Path {
impl PathExtensions for old_path::Path {
fn stat(&self) -> IoResult<FileStat> { stat(self) }
fn lstat(&self) -> IoResult<FileStat> { lstat(self) }
fn exists(&self) -> bool {

View file

@ -23,7 +23,7 @@
use prelude::v1::*;
use ffi::CString;
use path::BytesContainer;
use old_path::BytesContainer;
use old_io::{Listener, Acceptor, IoResult, TimedOut, standard_error};
use sys::pipe::UnixAcceptor as UnixAcceptorImp;
use sys::pipe::UnixListener as UnixListenerImp;

View file

@ -25,7 +25,7 @@ use old_io::{IoResult, IoError};
use old_io;
use libc;
use os;
use path::BytesContainer;
use old_path::BytesContainer;
use sync::mpsc::{channel, Receiver};
use sys::fs::FileDesc;
use sys::process::Process as ProcessImp;

View file

@ -17,7 +17,7 @@ use old_io;
use ops::Drop;
use option::Option::{None, Some};
use option::Option;
use path::{Path, GenericPath};
use old_path::{Path, GenericPath};
use rand::{Rng, thread_rng};
use result::Result::{Ok, Err};
use str::StrExt;

View file

@ -445,7 +445,7 @@ mod tests {
use clone::Clone;
use iter::IteratorExt;
use option::Option::{self, Some, None};
use path::GenericPath;
use old_path::GenericPath;
use slice::{AsSlice, SliceExt};
use str::{self, Str, StrExt};
use string::ToString;

View file

@ -1124,7 +1124,7 @@ mod tests {
use clone::Clone;
use iter::IteratorExt;
use option::Option::{self, Some, None};
use path::GenericPath;
use old_path::GenericPath;
use slice::{AsSlice, SliceExt};
use str::Str;
use string::ToString;

View file

@ -48,7 +48,7 @@ use old_io::{IoResult, IoError};
use ops::{Drop, FnOnce};
use option::Option::{Some, None};
use option::Option;
use path::{Path, GenericPath, BytesContainer};
use old_path::{Path, GenericPath, BytesContainer};
use ptr::PtrExt;
use ptr;
use result::Result::{Err, Ok};
@ -267,7 +267,7 @@ pub fn split_paths<T: BytesContainer>(unparsed: T) -> Vec<Path> {
///
/// ```rust
/// use std::os;
/// use std::path::Path;
/// use std::old_path::Path;
///
/// let key = "PATH";
/// let mut paths = os::getenv_as_bytes(key).map_or(Vec::new(), os::split_paths);
@ -470,7 +470,7 @@ pub fn tmpdir() -> Path {
/// # Example
/// ```rust
/// use std::os;
/// use std::path::Path;
/// use std::old_path::Path;
///
/// // Assume we're in a path like /home/someuser
/// let rel_path = Path::new("..");
@ -500,7 +500,7 @@ pub fn make_absolute(p: &Path) -> IoResult<Path> {
/// # Example
/// ```rust
/// use std::os;
/// use std::path::Path;
/// use std::old_path::Path;
///
/// let root = Path::new("/");
/// assert!(os::change_dir(&root).is_ok());

2577
src/libstd/path.rs Executable file

File diff suppressed because it is too large Load diff

View file

@ -56,7 +56,7 @@
#[doc(no_inline)] pub use vec::Vec;
// NB: remove when path reform lands
#[doc(no_inline)] pub use path::{Path, GenericPath};
#[doc(no_inline)] pub use old_path::{Path, GenericPath};
// NB: remove when I/O reform lands
#[doc(no_inline)] pub use old_io::{Buffer, Writer, Reader, Seek, BufferPrelude};
// NB: remove when range syntax lands

View file

@ -20,7 +20,7 @@ mod imp {
use self::OsRngInner::*;
use old_io::{IoResult, File};
use path::Path;
use old_path::Path;
use rand::Rng;
use rand::reader::ReaderRng;
use result::Result::Ok;

View file

@ -16,7 +16,7 @@ use prelude::v1::*;
use sys::{last_error, retry};
use ffi::CString;
use num::Int;
use path::BytesContainer;
use old_path::BytesContainer;
use collections;
pub mod backtrace;

View file

@ -143,6 +143,7 @@ extern {
pub fn sigdelset(set: *mut sigset_t, signum: libc::c_int) -> libc::c_int;
pub fn sigemptyset(set: *mut sigset_t) -> libc::c_int;
#[cfg(not(target_os = "ios"))]
pub fn getpwuid_r(uid: libc::uid_t,
pwd: *mut passwd,
buf: *mut libc::c_char,

View file

@ -18,10 +18,11 @@
use prelude::v1::*;
use ffi;
use old_io::{self, IoResult, IoError};
use io::ErrorKind;
use libc;
use num::{Int, SignedInt};
use num;
use old_io::{self, IoResult, IoError};
use str;
use sys_common::mkerr_libc;
@ -133,6 +134,35 @@ pub fn decode_error_detailed(errno: i32) -> IoError {
err
}
pub fn decode_error_kind(errno: i32) -> ErrorKind {
match errno as libc::c_int {
libc::ECONNREFUSED => ErrorKind::ConnectionRefused,
libc::ECONNRESET => ErrorKind::ConnectionReset,
libc::EPERM | libc::EACCES => ErrorKind::PermissionDenied,
libc::EPIPE => ErrorKind::BrokenPipe,
libc::ENOTCONN => ErrorKind::NotConnected,
libc::ECONNABORTED => ErrorKind::ConnectionAborted,
libc::EADDRNOTAVAIL => ErrorKind::ConnectionRefused,
libc::EADDRINUSE => ErrorKind::ConnectionRefused,
libc::ENOENT => ErrorKind::FileNotFound,
libc::EISDIR => ErrorKind::InvalidInput,
libc::EINTR => ErrorKind::Interrupted,
libc::EINVAL => ErrorKind::InvalidInput,
libc::ENOTTY => ErrorKind::MismatchedFileTypeForOperation,
libc::ETIMEDOUT => ErrorKind::TimedOut,
libc::ECANCELED => ErrorKind::TimedOut,
libc::consts::os::posix88::EEXIST => ErrorKind::PathAlreadyExists,
// These two constants can have the same value on some systems,
// but different values on others, so we can't use a match
// clause
x if x == libc::EAGAIN || x == libc::EWOULDBLOCK =>
ErrorKind::ResourceUnavailable,
_ => ErrorKind::Other,
}
}
#[inline]
pub fn retry<T, F> (mut f: F) -> T where
T: SignedInt,

View file

@ -307,23 +307,23 @@ pub fn args() -> Args {
let mut res = Vec::new();
unsafe {
let processInfoSel = sel_registerName("processInfo\0".as_ptr());
let argumentsSel = sel_registerName("arguments\0".as_ptr());
let utf8Sel = sel_registerName("UTF8String\0".as_ptr());
let countSel = sel_registerName("count\0".as_ptr());
let objectAtSel = sel_registerName("objectAtIndex:\0".as_ptr());
let process_info_sel = sel_registerName("processInfo\0".as_ptr());
let arguments_sel = sel_registerName("arguments\0".as_ptr());
let utf8_sel = sel_registerName("UTF8String\0".as_ptr());
let count_sel = sel_registerName("count\0".as_ptr());
let object_at_sel = sel_registerName("objectAtIndex:\0".as_ptr());
let klass = objc_getClass("NSProcessInfo\0".as_ptr());
let info = objc_msgSend(klass, processInfoSel);
let args = objc_msgSend(info, argumentsSel);
let info = objc_msgSend(klass, process_info_sel);
let args = objc_msgSend(info, arguments_sel);
let cnt: int = mem::transmute(objc_msgSend(args, countSel));
let cnt: int = mem::transmute(objc_msgSend(args, count_sel));
for i in range(0, cnt) {
let tmp = objc_msgSend(args, objectAtSel, i);
let tmp = objc_msgSend(args, object_at_sel, i);
let utf_c_str: *const libc::c_char =
mem::transmute(objc_msgSend(tmp, utf8Sel));
let bytes = ffi::c_str_to_bytes(&utf_c_str).to_vec();
res.push(OsString::from_vec(bytes))
mem::transmute(objc_msgSend(tmp, utf8_sel));
let bytes = ffi::c_str_to_bytes(&utf_c_str);
res.push(OsString::from_str(str::from_utf8(bytes).unwrap()))
}
}
@ -455,9 +455,11 @@ pub fn home_dir() -> Option<Path> {
Path::new(os.into_vec())
});
#[cfg(target_os = "android")]
#[cfg(any(target_os = "android",
target_os = "ios"))]
unsafe fn fallback() -> Option<OsString> { None }
#[cfg(not(target_os = "android"))]
#[cfg(not(any(target_os = "android",
target_os = "ios")))]
unsafe fn fallback() -> Option<OsString> {
let mut amt = match libc::sysconf(c::_SC_GETPW_R_SIZE_MAX) {
n if n < 0 => 512 as usize,

View file

@ -20,7 +20,7 @@ use str;
use string::{String, CowString};
use mem;
#[derive(Clone)]
#[derive(Clone, Hash)]
pub struct Buf {
pub inner: Vec<u8>
}

View file

@ -20,7 +20,7 @@ use old_io::{self, IoResult, IoError, EndOfFile};
use libc::{self, pid_t, c_void, c_int};
use mem;
use os;
use path::BytesContainer;
use old_path::BytesContainer;
use ptr;
use sync::mpsc::{channel, Sender, Receiver};
use sys::fs::FileDesc;

View file

@ -32,7 +32,7 @@ use libc;
use mem;
use ops::Drop;
use option::Option::{Some};
use path::Path;
use old_path::Path;
use ptr;
use result::Result::{Ok, Err};
use slice::SliceExt;

View file

@ -15,6 +15,7 @@
use prelude::v1::*;
use ffi::OsStr;
use io::ErrorKind;
use libc;
use mem;
use old_io::{self, IoResult, IoError};
@ -143,6 +144,34 @@ pub fn decode_error_detailed(errno: i32) -> IoError {
err
}
pub fn decode_error_kind(errno: i32) -> ErrorKind {
match errno as libc::c_int {
libc::ERROR_ACCESS_DENIED => ErrorKind::PermissionDenied,
libc::ERROR_ALREADY_EXISTS => ErrorKind::PathAlreadyExists,
libc::ERROR_BROKEN_PIPE => ErrorKind::BrokenPipe,
libc::ERROR_FILE_NOT_FOUND => ErrorKind::FileNotFound,
libc::ERROR_INVALID_FUNCTION => ErrorKind::InvalidInput,
libc::ERROR_INVALID_HANDLE => ErrorKind::MismatchedFileTypeForOperation,
libc::ERROR_INVALID_NAME => ErrorKind::InvalidInput,
libc::ERROR_NOTHING_TO_TERMINATE => ErrorKind::InvalidInput,
libc::ERROR_NO_DATA => ErrorKind::BrokenPipe,
libc::ERROR_OPERATION_ABORTED => ErrorKind::TimedOut,
libc::WSAEACCES => ErrorKind::PermissionDenied,
libc::WSAEADDRINUSE => ErrorKind::ConnectionRefused,
libc::WSAEADDRNOTAVAIL => ErrorKind::ConnectionRefused,
libc::WSAECONNABORTED => ErrorKind::ConnectionAborted,
libc::WSAECONNREFUSED => ErrorKind::ConnectionRefused,
libc::WSAECONNRESET => ErrorKind::ConnectionReset,
libc::WSAEINVAL => ErrorKind::InvalidInput,
libc::WSAENOTCONN => ErrorKind::NotConnected,
libc::WSAEWOULDBLOCK => ErrorKind::ResourceUnavailable,
_ => ErrorKind::Other,
}
}
#[inline]
pub fn retry<I, F>(f: F) -> I where F: FnOnce() -> I { f() } // PR rust-lang/rust/#17020

View file

@ -18,7 +18,7 @@ use result::Result;
use option::Option;
use mem;
#[derive(Clone)]
#[derive(Clone, Hash)]
pub struct Buf {
pub inner: Wtf8Buf
}

View file

@ -23,7 +23,7 @@ use old_io::process::{ProcessExit, ExitStatus};
use old_io::{IoResult, IoError};
use old_io;
use os;
use path::BytesContainer;
use old_path::BytesContainer;
use ptr;
use str;
use sync::{StaticMutex, MUTEX_INIT};

View file

@ -45,6 +45,7 @@ pub mod scoped;
// Sure wish we had macro hygiene, no?
#[doc(hidden)]
#[stable(feature = "rust1", since = "1.0.0")]
pub mod __impl {
pub use super::imp::Key as KeyInner;
pub use super::imp::destroy_value;

View file

@ -48,7 +48,6 @@ pub use self::TraitItem::*;
pub use self::Ty_::*;
pub use self::TyParamBound::*;
pub use self::UintTy::*;
pub use self::ClosureKind::*;
pub use self::UnOp::*;
pub use self::UnsafeSource::*;
pub use self::VariantKind::*;
@ -736,7 +735,7 @@ pub enum Expr_ {
// FIXME #6993: change to Option<Name> ... or not, if these are hygienic.
ExprLoop(P<Block>, Option<Ident>),
ExprMatch(P<Expr>, Vec<Arm>, MatchSource),
ExprClosure(CaptureClause, Option<ClosureKind>, P<FnDecl>, P<Block>),
ExprClosure(CaptureClause, P<FnDecl>, P<Block>),
ExprBlock(P<Block>),
ExprAssign(P<Expr>, P<Expr>),
@ -1687,13 +1686,6 @@ impl ForeignItem_ {
}
}
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)]
pub enum ClosureKind {
FnClosureKind,
FnMutClosureKind,
FnOnceClosureKind,
}
/// The data we save and restore about an inlined item or method. This is not
/// part of the AST that we parse from a file, but it becomes part of the tree
/// that we trans.

View file

@ -218,7 +218,7 @@ impl<'a> FnLikeNode<'a> {
}
}
ast_map::NodeExpr(e) => match e.node {
ast::ExprClosure(_, _, ref decl, ref block) =>
ast::ExprClosure(_, ref decl, ref block) =>
closure(ClosureParts::new(&**decl, &**block, e.id, e.span)),
_ => panic!("expr FnLikeNode that is not fn-like"),
},

View file

@ -876,14 +876,14 @@ impl<'a> AstBuilder for ExtCtxt<'a> {
fn lambda_fn_decl(&self, span: Span,
fn_decl: P<ast::FnDecl>, blk: P<ast::Block>) -> P<ast::Expr> {
self.expr(span, ast::ExprClosure(ast::CaptureByRef, None, fn_decl, blk))
self.expr(span, ast::ExprClosure(ast::CaptureByRef, fn_decl, blk))
}
fn lambda(&self, span: Span, ids: Vec<ast::Ident>, blk: P<ast::Block>) -> P<ast::Expr> {
let fn_decl = self.fn_decl(
ids.iter().map(|id| self.arg(span, *id, self.ty_infer(span))).collect(),
self.ty_infer(span));
self.expr(span, ast::ExprClosure(ast::CaptureByRef, None, fn_decl, blk))
self.expr(span, ast::ExprClosure(ast::CaptureByRef, fn_decl, blk))
}
fn lambda0(&self, span: Span, blk: P<ast::Block>) -> P<ast::Expr> {
self.lambda(span, Vec::new(), blk)

View file

@ -66,7 +66,7 @@ fn rand_substructure(cx: &mut ExtCtxt, trait_span: Span, substr: &Substructure)
cx.ident_of("Rand"),
cx.ident_of("rand")
);
let mut rand_call = |&mut: cx: &mut ExtCtxt, span| {
let rand_call = |&: cx: &mut ExtCtxt, span| {
cx.expr_call_global(span,
rand_ident.clone(),
vec!(rng.clone()))

View file

@ -322,11 +322,10 @@ pub fn expand_expr(e: P<ast::Expr>, fld: &mut MacroExpander) -> P<ast::Expr> {
fld.cx.expr_match(span, into_iter_expr, vec![iter_arm])
}
ast::ExprClosure(capture_clause, opt_kind, fn_decl, block) => {
ast::ExprClosure(capture_clause, fn_decl, block) => {
let (rewritten_fn_decl, rewritten_block)
= expand_and_rename_fn_decl_and_block(fn_decl, block, fld);
let new_node = ast::ExprClosure(capture_clause,
opt_kind,
rewritten_fn_decl,
rewritten_block);
P(ast::Expr{id:id, node: new_node, span: fld.new_span(span)})

View file

@ -119,6 +119,9 @@ static KNOWN_FEATURES: &'static [(&'static str, &'static str, Status)] = &[
// Allows use of #[staged_api]
("staged_api", "1.0.0", Active),
// Allows using items which are missing stability attributes
("unmarked_api", "1.0.0", Active)
];
enum Status {
@ -145,6 +148,7 @@ pub struct Features {
pub quote: bool,
pub old_orphan_check: bool,
pub simd_ffi: bool,
pub unmarked_api: bool,
pub lib_features: Vec<(InternedString, Span)>
}
@ -157,6 +161,7 @@ impl Features {
quote: false,
old_orphan_check: false,
simd_ffi: false,
unmarked_api: false,
lib_features: Vec::new()
}
}
@ -566,6 +571,7 @@ fn check_crate_inner<F>(cm: &CodeMap, span_handler: &SpanHandler, krate: &ast::C
quote: cx.has_feature("quote"),
old_orphan_check: cx.has_feature("old_orphan_check"),
simd_ffi: cx.has_feature("simd_ffi"),
unmarked_api: cx.has_feature("unmarked_api"),
lib_features: unknown_features
}
}

View file

@ -1325,9 +1325,8 @@ pub fn noop_fold_expr<T: Folder>(Expr {id, node, span}: Expr, folder: &mut T) ->
arms.move_map(|x| folder.fold_arm(x)),
source)
}
ExprClosure(capture_clause, opt_kind, decl, body) => {
ExprClosure(capture_clause, decl, body) => {
ExprClosure(capture_clause,
opt_kind,
folder.fold_fn_decl(decl),
folder.fold_block(body))
}

View file

@ -27,6 +27,7 @@ pub enum ObsoleteSyntax {
ProcType,
ProcExpr,
ClosureType,
ClosureKind,
}
pub trait ParserObsoleteMethods {
@ -65,6 +66,10 @@ impl<'a> ParserObsoleteMethods for parser::Parser<'a> {
"`|usize| -> bool` closure type syntax",
"use unboxed closures instead, no type annotation needed"
),
ObsoleteSyntax::ClosureKind => (
"`:`, `&mut:`, or `&:` syntax",
"rely on inference instead"
),
ObsoleteSyntax::Sized => (
"`Sized? T` syntax for removing the `Sized` bound",
"write `T: ?Sized` instead"

View file

@ -28,8 +28,6 @@ use ast::{ExprLit, ExprLoop, ExprMac, ExprRange};
use ast::{ExprMethodCall, ExprParen, ExprPath, ExprQPath};
use ast::{ExprRepeat, ExprRet, ExprStruct, ExprTup, ExprUnary};
use ast::{ExprVec, ExprWhile, ExprWhileLet, ExprForLoop, Field, FnDecl};
use ast::{FnClosureKind, FnMutClosureKind};
use ast::{FnOnceClosureKind};
use ast::{ForeignItem, ForeignItemStatic, ForeignItemFn, ForeignMod, FunctionRetTy};
use ast::{Ident, Inherited, ImplItem, Item, Item_, ItemStatic};
use ast::{ItemEnum, ItemFn, ItemForeignMod, ItemImpl, ItemConst};
@ -57,7 +55,7 @@ use ast::{TyFixedLengthVec, TyBareFn};
use ast::{TyTypeof, TyInfer, TypeMethod};
use ast::{TyParam, TyParamBound, TyParen, TyPath, TyPolyTraitRef, TyPtr, TyQPath};
use ast::{TyRptr, TyTup, TyU32, TyVec, UnUniq};
use ast::{TypeImplItem, TypeTraitItem, Typedef, ClosureKind};
use ast::{TypeImplItem, TypeTraitItem, Typedef,};
use ast::{UnnamedField, UnsafeBlock};
use ast::{ViewPath, ViewPathGlob, ViewPathList, ViewPathSimple};
use ast::{Visibility, WhereClause};
@ -1139,29 +1137,36 @@ impl<'a> Parser<'a> {
TyInfer
}
/// Parses an optional closure kind (`&:`, `&mut:`, or `:`).
pub fn parse_optional_closure_kind(&mut self) -> Option<ClosureKind> {
if self.check(&token::BinOp(token::And)) &&
self.look_ahead(1, |t| t.is_keyword(keywords::Mut)) &&
self.look_ahead(2, |t| *t == token::Colon) {
/// Parses an obsolete closure kind (`&:`, `&mut:`, or `:`).
pub fn parse_obsolete_closure_kind(&mut self) {
// let lo = self.span.lo;
if
self.check(&token::BinOp(token::And)) &&
self.look_ahead(1, |t| t.is_keyword(keywords::Mut)) &&
self.look_ahead(2, |t| *t == token::Colon)
{
self.bump();
self.bump();
self.bump();
return Some(FnMutClosureKind)
} else if
self.token == token::BinOp(token::And) &&
self.look_ahead(1, |t| *t == token::Colon)
{
self.bump();
self.bump();
return;
} else if
self.eat(&token::Colon)
{
/* nothing */
} else {
return;
}
if self.token == token::BinOp(token::And) &&
self.look_ahead(1, |t| *t == token::Colon) {
self.bump();
self.bump();
return Some(FnClosureKind)
}
if self.eat(&token::Colon) {
return Some(FnOnceClosureKind)
}
return None
// SNAP 474b324
// Enable these obsolete errors after snapshot:
// let span = mk_sp(lo, self.span.hi);
// self.obsolete(span, ObsoleteSyntax::ClosureKind);
}
pub fn parse_ty_bare_fn_or_ty_closure(&mut self, lifetime_defs: Vec<LifetimeDef>) -> Ty_ {
@ -3047,7 +3052,7 @@ impl<'a> Parser<'a> {
-> P<Expr>
{
let lo = self.span.lo;
let (decl, optional_closure_kind) = self.parse_fn_block_decl();
let decl = self.parse_fn_block_decl();
let body = self.parse_expr();
let fakeblock = P(ast::Block {
id: ast::DUMMY_NODE_ID,
@ -3060,7 +3065,7 @@ impl<'a> Parser<'a> {
self.mk_expr(
lo,
fakeblock.span.hi,
ExprClosure(capture_clause, optional_closure_kind, decl, fakeblock))
ExprClosure(capture_clause, decl, fakeblock))
}
pub fn parse_else_expr(&mut self) -> P<Expr> {
@ -4529,30 +4534,29 @@ impl<'a> Parser<'a> {
}
// parse the |arg, arg| header on a lambda
fn parse_fn_block_decl(&mut self) -> (P<FnDecl>, Option<ClosureKind>) {
let (optional_closure_kind, inputs_captures) = {
fn parse_fn_block_decl(&mut self) -> P<FnDecl> {
let inputs_captures = {
if self.eat(&token::OrOr) {
(None, Vec::new())
Vec::new()
} else {
self.expect(&token::BinOp(token::Or));
let optional_closure_kind =
self.parse_optional_closure_kind();
self.parse_obsolete_closure_kind();
let args = self.parse_seq_to_before_end(
&token::BinOp(token::Or),
seq_sep_trailing_allowed(token::Comma),
|p| p.parse_fn_block_arg()
);
self.bump();
(optional_closure_kind, args)
args
}
};
let output = self.parse_ret_ty();
(P(FnDecl {
P(FnDecl {
inputs: inputs_captures,
output: output,
variadic: false
}), optional_closure_kind)
})
}
/// Parses the `(arg, arg) -> return_type` header on a procedure.

View file

@ -25,7 +25,7 @@ use serialize::{Decodable, Decoder, Encodable, Encoder};
use std::fmt;
use std::mem;
use std::ops::Deref;
use std::path::BytesContainer;
use std::old_path::BytesContainer;
use std::rc::Rc;
#[allow(non_camel_case_types)]

View file

@ -11,11 +11,9 @@
pub use self::AnnNode::*;
use abi;
use ast::{self, FnClosureKind, FnMutClosureKind};
use ast::{FnOnceClosureKind};
use ast;
use ast::{MethodImplItem, RegionTyParamBound, TraitTyParamBound, TraitBoundModifier};
use ast::{RequiredMethod, ProvidedMethod, TypeImplItem, TypeTraitItem};
use ast::{ClosureKind};
use ast_util;
use owned_slice::OwnedSlice;
use attr::{AttrMetaMethods, AttributeMethods};
@ -350,7 +348,7 @@ pub fn method_to_string(p: &ast::Method) -> String {
}
pub fn fn_block_to_string(p: &ast::FnDecl) -> String {
$to_string(|s| s.print_fn_block_args(p, None))
$to_string(|s| s.print_fn_block_args(p))
}
pub fn path_to_string(p: &ast::Path) -> String {
@ -1747,10 +1745,10 @@ impl<'a> State<'a> {
}
try!(self.bclose_(expr.span, indent_unit));
}
ast::ExprClosure(capture_clause, opt_kind, ref decl, ref body) => {
ast::ExprClosure(capture_clause, ref decl, ref body) => {
try!(self.print_capture_clause(capture_clause));
try!(self.print_fn_block_args(&**decl, opt_kind));
try!(self.print_fn_block_args(&**decl));
try!(space(&mut self.s));
if !body.stmts.is_empty() || !body.expr.is_some() {
@ -2350,16 +2348,9 @@ impl<'a> State<'a> {
pub fn print_fn_block_args(
&mut self,
decl: &ast::FnDecl,
closure_kind: Option<ClosureKind>)
decl: &ast::FnDecl)
-> IoResult<()> {
try!(word(&mut self.s, "|"));
match closure_kind {
None => {}
Some(FnClosureKind) => try!(self.word_space("&:")),
Some(FnMutClosureKind) => try!(self.word_space("&mut:")),
Some(FnOnceClosureKind) => try!(self.word_space(":")),
}
try!(self.print_fn_args(decl, None));
try!(word(&mut self.s, "|"));

View file

@ -836,7 +836,7 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr) {
visitor.visit_arm(arm)
}
}
ExprClosure(_, _, ref function_declaration, ref body) => {
ExprClosure(_, ref function_declaration, ref body) => {
visitor.visit_fn(FkFnBlock,
&**function_declaration,
&**body,

View file

@ -11,6 +11,7 @@
#![crate_type = "lib"]
#![feature(staged_api)]
#![staged_api]
#![stable(feature = "lint_stability", since = "1.0.0")]
#[stable(feature = "test_feature", since = "1.0.0")]
#[deprecated(since = "1.0.0")]
@ -31,8 +32,6 @@ pub fn unstable() {}
#[unstable(feature = "test_feature", reason = "text")]
pub fn unstable_text() {}
pub fn unmarked() {}
#[stable(feature = "rust1", since = "1.0.0")]
pub fn stable() {}
#[stable(feature = "rust1", since = "1.0.0", reason = "text")]
@ -61,8 +60,6 @@ impl MethodTester {
#[unstable(feature = "test_feature", reason = "text")]
pub fn method_unstable_text(&self) {}
pub fn method_unmarked(&self) {}
#[stable(feature = "rust1", since = "1.0.0")]
pub fn method_stable(&self) {}
#[stable(feature = "rust1", since = "1.0.0", reason = "text")]
@ -79,6 +76,7 @@ impl MethodTester {
pub fn method_frozen_text(&self) {}
}
#[stable(feature = "test_feature", since = "1.0.0")]
pub trait Trait {
#[stable(feature = "test_feature", since = "1.0.0")]
#[deprecated(since = "1.0.0")]
@ -99,8 +97,6 @@ pub trait Trait {
#[unstable(feature = "test_feature", reason = "text")]
fn trait_unstable_text(&self) {}
fn trait_unmarked(&self) {}
#[stable(feature = "rust1", since = "1.0.0")]
fn trait_stable(&self) {}
#[stable(feature = "rust1", since = "1.0.0", reason = "text")]
@ -130,7 +126,6 @@ pub struct DeprecatedStruct { pub i: int }
pub struct DeprecatedUnstableStruct { pub i: int }
#[unstable(feature = "test_feature")]
pub struct UnstableStruct { pub i: int }
pub struct UnmarkedStruct { pub i: int }
#[stable(feature = "rust1", since = "1.0.0")]
pub struct StableStruct { pub i: int }
@ -142,10 +137,10 @@ pub struct DeprecatedUnitStruct;
pub struct DeprecatedUnstableUnitStruct;
#[unstable(feature = "test_feature")]
pub struct UnstableUnitStruct;
pub struct UnmarkedUnitStruct;
#[stable(feature = "rust1", since = "1.0.0")]
pub struct StableUnitStruct;
#[stable(feature = "test_feature", since = "1.0.0")]
pub enum Enum {
#[stable(feature = "test_feature", since = "1.0.0")]
#[deprecated(since = "1.0.0")]
@ -156,7 +151,6 @@ pub enum Enum {
#[unstable(feature = "test_feature")]
UnstableVariant,
UnmarkedVariant,
#[stable(feature = "rust1", since = "1.0.0")]
StableVariant,
}
@ -169,7 +163,6 @@ pub struct DeprecatedTupleStruct(pub int);
pub struct DeprecatedUnstableTupleStruct(pub int);
#[unstable(feature = "test_feature")]
pub struct UnstableTupleStruct(pub int);
pub struct UnmarkedTupleStruct(pub int);
#[stable(feature = "rust1", since = "1.0.0")]
pub struct StableTupleStruct(pub int);

View file

@ -8,34 +8,38 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![feature(unboxed_closures, overloaded_calls)]
#![feature(unboxed_closures)]
// Tests that we can't assign to or mutably borrow upvars from `Fn`
// closures (issue #17780)
fn set(x: &mut usize) { *x = 5; }
fn to_fn<A,F:Fn<A>>(f: F) -> F { f }
fn to_fn_mut<A,F:FnMut<A>>(f: F) -> F { f }
fn main() {
// By-ref captures
{
let mut x = 0us;
let _f = |&:| x = 42; //~ ERROR cannot assign
let _f = to_fn(|| x = 42); //~ ERROR cannot assign
let mut y = 0us;
let _g = |&:| set(&mut y); //~ ERROR cannot borrow
let _g = to_fn(|| set(&mut y)); //~ ERROR cannot borrow
let mut z = 0us;
let _h = |&mut:| { set(&mut z); |&:| z = 42; }; //~ ERROR cannot assign
let _h = to_fn_mut(|| { set(&mut z); to_fn(|| z = 42); }); //~ ERROR cannot assign
}
// By-value captures
{
let mut x = 0us;
let _f = move |&:| x = 42; //~ ERROR cannot assign
let _f = to_fn(move || x = 42); //~ ERROR cannot assign
let mut y = 0us;
let _g = move |&:| set(&mut y); //~ ERROR cannot borrow
let _g = to_fn(move || set(&mut y)); //~ ERROR cannot borrow
let mut z = 0us;
let _h = move |&mut:| { set(&mut z); move |&:| z = 42; }; //~ ERROR cannot assign
let _h = to_fn_mut(move || { set(&mut z); to_fn(move || z = 42); }); //~ ERROR cannot assign
}
}

View file

@ -8,11 +8,14 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![feature(box_syntax)]
#![feature(box_syntax,unboxed_closures)]
fn to_fn_mut<A,F:FnMut<A>>(f: F) -> F { f }
fn to_fn_once<A,F:FnOnce<A>>(f: F) -> F { f }
pub fn main() {
let bar = box 3;
let _g = |&mut:| {
let _h = move |:| -> isize { *bar }; //~ ERROR cannot move out of captured outer variable
};
let _g = to_fn_mut(|| {
let _h = to_fn_once(move || -> isize { *bar }); //~ ERROR cannot move out of
});
}

View file

@ -8,12 +8,16 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![feature(unboxed_closures)]
fn to_fn_once<A,F:FnOnce<A>>(f: F) -> F { f }
fn main() {
let x = 1;
move|:| { x = 2; };
to_fn_once(move|:| { x = 2; });
//~^ ERROR: cannot assign to immutable captured outer variable
let s = std::old_io::stdin();
move|:| { s.read_to_end(); };
to_fn_once(move|:| { s.read_to_end(); });
//~^ ERROR: cannot borrow immutable captured outer variable
}

View file

@ -8,12 +8,14 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![feature(box_syntax)]
#![feature(box_syntax, unboxed_closures)]
fn to_fn_once<A,F:FnOnce<A>>(f: F) -> F { f }
fn main() {
let r = {
let x = box 42;
let f = move|:| &x; //~ ERROR: `x` does not live long enough
let f = to_fn_once(move|| &x); //~ ERROR: `x` does not live long enough
f()
};

View file

@ -8,14 +8,15 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![feature(box_syntax)]
#![feature(box_syntax, unboxed_closures)]
fn to_fn_once<A,F:FnOnce<A>>(f: F) -> F { f }
fn do_it(x: &isize) { }
fn main() {
let x = box 22;
let f = move|:| do_it(&*x);
(move|:| {
let f = to_fn_once(move|| do_it(&*x));
to_fn_once(move|| {
f();
f();
//~^ ERROR: use of moved value: `f`

View file

@ -20,7 +20,7 @@
#![staged_api]
#[macro_use]
extern crate lint_stability; //~ ERROR: use of unmarked library feature
extern crate lint_stability;
mod cross_crate {
extern crate stability_cfg1;
@ -61,10 +61,6 @@ mod cross_crate {
foo.method_unstable_text(); //~ WARNING use of unstable library feature 'test_feature': text
foo.trait_unstable_text(); //~ WARNING use of unstable library feature 'test_feature': text
unmarked(); //~ ERROR use of unmarked library feature
foo.method_unmarked(); //~ ERROR use of unmarked library feature
foo.trait_unmarked(); //~ ERROR use of unmarked library feature
stable();
foo.method_stable();
foo.trait_stable();
@ -77,28 +73,24 @@ mod cross_crate {
let _ = DeprecatedUnstableStruct { i: 0 }; //~ ERROR use of deprecated item
//~^ WARNING use of unstable library feature
let _ = UnstableStruct { i: 0 }; //~ WARNING use of unstable library feature
let _ = UnmarkedStruct { i: 0 }; //~ ERROR use of unmarked library feature
let _ = StableStruct { i: 0 };
let _ = DeprecatedUnitStruct; //~ ERROR use of deprecated item
let _ = DeprecatedUnstableUnitStruct; //~ ERROR use of deprecated item
//~^ WARNING use of unstable library feature
let _ = UnstableUnitStruct; //~ WARNING use of unstable library feature
let _ = UnmarkedUnitStruct; //~ ERROR use of unmarked library feature
let _ = StableUnitStruct;
let _ = Enum::DeprecatedVariant; //~ ERROR use of deprecated item
let _ = Enum::DeprecatedUnstableVariant; //~ ERROR use of deprecated item
//~^ WARNING use of unstable library feature
let _ = Enum::UnstableVariant; //~ WARNING use of unstable library feature
let _ = Enum::UnmarkedVariant; //~ ERROR use of unmarked library feature
let _ = Enum::StableVariant;
let _ = DeprecatedTupleStruct (1); //~ ERROR use of deprecated item
let _ = DeprecatedUnstableTupleStruct (1); //~ ERROR use of deprecated item
//~^ WARNING use of unstable library feature
let _ = UnstableTupleStruct (1); //~ WARNING use of unstable library feature
let _ = UnmarkedTupleStruct (1); //~ ERROR use of unmarked library feature
let _ = StableTupleStruct (1);
// At the moment, the lint checker only checks stability in
@ -123,7 +115,6 @@ mod cross_crate {
//~^ WARNING use of unstable library feature
foo.trait_unstable(); //~ WARNING use of unstable library feature
foo.trait_unstable_text(); //~ WARNING use of unstable library feature 'test_feature': text
foo.trait_unmarked(); //~ ERROR use of unmarked library feature
foo.trait_stable();
}
@ -136,7 +127,6 @@ mod cross_crate {
//~^ WARNING use of unstable library feature
foo.trait_unstable(); //~ WARNING use of unstable library feature
foo.trait_unstable_text(); //~ WARNING use of unstable library feature 'test_feature': text
foo.trait_unmarked(); //~ ERROR use of unmarked library feature
foo.trait_stable();
}
@ -183,8 +173,6 @@ mod this_crate {
#[unstable(feature = "test_feature", reason = "text")]
pub fn unstable_text() {}
pub fn unmarked() {}
#[stable(feature = "rust1", since = "1.0.0")]
pub fn stable() {}
#[stable(feature = "rust1", since = "1.0.0", reason = "text")]
@ -206,8 +194,6 @@ mod this_crate {
#[unstable(feature = "test_feature", reason = "text")]
pub fn method_unstable_text(&self) {}
pub fn method_unmarked(&self) {}
#[stable(feature = "rust1", since = "1.0.0")]
pub fn method_stable(&self) {}
#[stable(feature = "rust1", since = "1.0.0", reason = "text")]
@ -227,8 +213,6 @@ mod this_crate {
#[unstable(feature = "test_feature", reason = "text")]
fn trait_unstable_text(&self) {}
fn trait_unmarked(&self) {}
#[stable(feature = "rust1", since = "1.0.0")]
fn trait_stable(&self) {}
#[stable(feature = "rust1", since = "1.0.0", reason = "text")]
@ -242,7 +226,6 @@ mod this_crate {
pub struct DeprecatedStruct { i: isize }
#[unstable(feature = "test_feature")]
pub struct UnstableStruct { i: isize }
pub struct UnmarkedStruct { i: isize }
#[stable(feature = "rust1", since = "1.0.0")]
pub struct StableStruct { i: isize }
@ -251,7 +234,6 @@ mod this_crate {
pub struct DeprecatedUnitStruct;
#[unstable(feature = "test_feature")]
pub struct UnstableUnitStruct;
pub struct UnmarkedUnitStruct;
#[stable(feature = "rust1", since = "1.0.0")]
pub struct StableUnitStruct;
@ -262,7 +244,6 @@ mod this_crate {
#[unstable(feature = "test_feature")]
UnstableVariant,
UnmarkedVariant,
#[stable(feature = "rust1", since = "1.0.0")]
StableVariant,
}
@ -272,7 +253,6 @@ mod this_crate {
pub struct DeprecatedTupleStruct(isize);
#[unstable(feature = "test_feature")]
pub struct UnstableTupleStruct(isize);
pub struct UnmarkedTupleStruct(isize);
#[stable(feature = "rust1", since = "1.0.0")]
pub struct StableTupleStruct(isize);
@ -299,10 +279,6 @@ mod this_crate {
foo.method_unstable_text();
foo.trait_unstable_text();
unmarked();
foo.method_unmarked();
foo.trait_unmarked();
stable();
foo.method_stable();
foo.trait_stable();
@ -313,22 +289,18 @@ mod this_crate {
let _ = DeprecatedStruct { i: 0 }; //~ ERROR use of deprecated item
let _ = UnstableStruct { i: 0 };
let _ = UnmarkedStruct { i: 0 };
let _ = StableStruct { i: 0 };
let _ = DeprecatedUnitStruct; //~ ERROR use of deprecated item
let _ = UnstableUnitStruct;
let _ = UnmarkedUnitStruct;
let _ = StableUnitStruct;
let _ = Enum::DeprecatedVariant; //~ ERROR use of deprecated item
let _ = Enum::UnstableVariant;
let _ = Enum::UnmarkedVariant;
let _ = Enum::StableVariant;
let _ = DeprecatedTupleStruct (1); //~ ERROR use of deprecated item
let _ = UnstableTupleStruct (1);
let _ = UnmarkedTupleStruct (1);
let _ = StableTupleStruct (1);
}
@ -337,7 +309,6 @@ mod this_crate {
foo.trait_deprecated_text(); //~ ERROR use of deprecated item: text
foo.trait_unstable();
foo.trait_unstable_text();
foo.trait_unmarked();
foo.trait_stable();
}
@ -346,7 +317,6 @@ mod this_crate {
foo.trait_deprecated_text(); //~ ERROR use of deprecated item: text
foo.trait_unstable();
foo.trait_unstable_text();
foo.trait_unmarked();
foo.trait_stable();
}

View file

@ -0,0 +1,33 @@
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// Checks that exported items without stability attributes cause an error
#![crate_type="lib"]
#![feature(staged_api)]
#![staged_api]
pub fn unmarked() {
//~^ ERROR This node does not have a stability attribute
()
}
#[unstable(feature = "foo")]
pub mod foo {
// #[unstable] is inherited
pub fn unmarked() {}
}
#[stable(feature = "bar", since="1.0.0")]
pub mod bar {
// #[stable] is not inherited
pub fn unmarked() {}
//~^ ERROR This node does not have a stability attribute
}

View file

@ -8,13 +8,15 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![feature(box_syntax)]
#![feature(box_syntax, unboxed_closures)]
use std::usize;
fn to_fn<A,F:Fn<A>>(f: F) -> F { f }
fn test(_x: Box<usize>) {}
fn main() {
let i = box 3;
let _f = |&:| test(i); //~ ERROR cannot move out
let _f = to_fn(|| test(i)); //~ ERROR cannot move out
}

View file

@ -13,4 +13,4 @@
pub fn main() {
let r = 1..2..3;
//~^ ERROR expected one of `.`, `;`, or an operator, found `..`
}
}

View file

@ -13,4 +13,4 @@
pub fn main() {
let r = ..1..2;
//~^ ERROR expected one of `.`, `;`, or an operator, found `..`
}
}

View file

@ -10,8 +10,10 @@
#![feature(unboxed_closures)]
fn to_fn_once<A,F:FnOnce<A>>(f: F) -> F { f }
fn main() {
let f = move|:| ();
let f = to_fn_once(move|| ());
f();
f(); //~ ERROR use of moved value
}

View file

@ -15,31 +15,35 @@
// if the upvar is captured by ref or the closure takes self by
// reference.
fn to_fn<A,F:Fn<A>>(f: F) -> F { f }
fn to_fn_mut<A,F:FnMut<A>>(f: F) -> F { f }
fn to_fn_once<A,F:FnOnce<A>>(f: F) -> F { f }
fn main() {
// By-ref cases
{
let x = box 0us;
let f = |&:| drop(x); //~ ERROR cannot move
let f = to_fn(|| drop(x)); //~ ERROR cannot move
}
{
let x = box 0us;
let f = |&mut:| drop(x); //~ ERROR cannot move
let f = to_fn_mut(|| drop(x)); //~ ERROR cannot move
}
{
let x = box 0us;
let f = |:| drop(x); // OK -- FnOnce
let f = to_fn_once(|| drop(x)); // OK -- FnOnce
}
// By-value cases
{
let x = box 0us;
let f = move |&:| drop(x); //~ ERROR cannot move
let f = to_fn(move || drop(x)); //~ ERROR cannot move
}
{
let x = box 0us;
let f = move |&mut:| drop(x); //~ ERROR cannot move
let f = to_fn_mut(move || drop(x)); //~ ERROR cannot move
}
{
let x = box 0us;
let f = move |:| drop(x); // this one is ok
let f = to_fn_once(move || drop(x)); // this one is ok
}
}

View file

@ -12,51 +12,56 @@
// as `mut` through a closure. Also test that we CAN mutate a moved copy,
// unless this is a `Fn` closure. Issue #16749.
#![feature(unboxed_closures)]
use std::mem;
fn to_fn<A,F:Fn<A>>(f: F) -> F { f }
fn to_fn_mut<A,F:FnMut<A>>(f: F) -> F { f }
fn a() {
let n = 0u8;
let mut f = |&mut:| { //~ ERROR closure cannot assign
let mut f = to_fn_mut(|| { //~ ERROR closure cannot assign
n += 1;
};
});
}
fn b() {
let mut n = 0u8;
let mut f = |&mut:| {
let mut f = to_fn_mut(|| {
n += 1; // OK
};
});
}
fn c() {
let n = 0u8;
let mut f = move |&mut:| {
let mut f = to_fn_mut(move || {
// If we just did a straight-forward desugaring, this would
// compile, but we do something a bit more subtle, and hence
// we get an error.
n += 1; //~ ERROR cannot assign
};
});
}
fn d() {
let mut n = 0u8;
let mut f = move |&mut:| {
let mut f = to_fn_mut(move || {
n += 1; // OK
};
});
}
fn e() {
let n = 0u8;
let mut f = move |&:| {
let mut f = to_fn(move || {
n += 1; //~ ERROR cannot assign
};
});
}
fn f() {
let mut n = 0u8;
let mut f = move |&:| {
let mut f = to_fn(move || {
n += 1; //~ ERROR cannot assign
};
});
}
fn main() { }

View file

@ -10,8 +10,10 @@
#![feature(unboxed_closures)]
fn to_fn_mut<A,F:FnMut<A>>(f: F) -> F { f }
fn main() {
let mut_ = |&mut: x| x;
let mut_ = to_fn_mut(|x| x);
mut_.call((0, )); //~ ERROR does not implement any method in scope named `call`
}

View file

@ -12,12 +12,14 @@
use std::ops::FnMut;
fn to_fn_mut<A,F:FnMut<A>>(f: F) -> F { f }
fn call_it<F:FnMut(isize,isize)->isize>(y: isize, mut f: F) -> isize {
f(2, y)
}
pub fn main() {
let f = |&mut: x: usize, y: isize| -> isize { (x as isize) + y };
let f = to_fn_mut(|x: usize, y: isize| -> isize { (x as isize) + y });
let z = call_it(3, f);
//~^ ERROR type mismatch
//~| ERROR type mismatch

View file

@ -1,23 +0,0 @@
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![feature(lang_items, overloaded_calls, unboxed_closures)]
fn c<F:Fn(isize, isize) -> isize>(f: F) -> isize {
f(5, 6)
}
fn main() {
let z: isize = 7;
assert_eq!(c(|&mut: x: isize, y| x + y + z), 10);
//~^ ERROR not implemented
//~| ERROR not implemented
}

View file

@ -149,4 +149,4 @@ fn main() {
assoc_enum(Enum::Variant2(8i64, 9i32));
}
fn zzz() { () }
fn zzz() { () }

View file

@ -9,11 +9,11 @@
// except according to those terms.
fn foo(i: int) -> int { i + 1 }
fn foo(i: isize) -> isize { i + 1 }
fn apply<A, F>(f: F, v: A) -> A where F: FnOnce(A) -> A { f(v) }
pub fn main() {
let f = {|: i| foo(i)};
let f = {|i| foo(i)};
assert_eq!(apply(f, 2), 3);
}

View file

@ -11,7 +11,7 @@
use std::slice::SliceExt;
use std::old_io::{Command, fs, USER_RWX};
use std::os;
use std::path::BytesContainer;
use std::old_path::BytesContainer;
use std::rand::random;
fn main() {

View file

@ -1,4 +1,3 @@
// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
@ -15,8 +14,8 @@
#![feature(box_syntax)]
#![feature(unboxed_closures)]
use std::path::{Path};
use std::path;
use std::old_path::{Path};
use std::old_path;
use std::result;
use std::thunk::Thunk;
@ -28,7 +27,7 @@ fn tester()
result::Result::Ok("more blah".to_string())
};
let path = path::Path::new("blah");
let path = old_path::Path::new("blah");
assert!(loader(&path).is_ok());
}

View file

@ -14,9 +14,9 @@
#![feature(box_syntax)]
#![feature(unboxed_closures)]
struct A { a: Box<int> }
struct A { a: Box<isize> }
fn foo() -> Box<FnMut() -> int + 'static> {
fn foo() -> Box<FnMut() -> isize + 'static> {
let k = box 22;
let _u = A {a: k.clone()};
let result = |&mut:| 22;

View file

@ -20,7 +20,7 @@ use std::old_io;
use std::old_io::fs;
use std::old_io::Command;
use std::os;
use std::path::Path;
use std::old_path::Path;
fn main() {
let my_args = os::args();

View file

@ -11,7 +11,7 @@
#![feature(unboxed_closures)]
fn main() {
let mut zero = |&mut:| {};
let () = zero.call_mut(());
let mut zero = || {};
let () = zero();
}