CFG_STATIC_LIB_NAME_mips-unknown-linux-gnu=lib$(1).a
CFG_LIB_GLOB_mips-unknown-linux-gnu=lib$(1)-*.so
CFG_LIB_DSYM_GLOB_mips-unknown-linux-gnu=lib$(1)-*.dylib.dSYM
-CFG_JEMALLOC_CFLAGS_mips-unknown-linux-gnu := -mips32r2 -msoft-float -mabi=32 -mno-compact-eh $(CFLAGS)
-CFG_GCCISH_CFLAGS_mips-unknown-linux-gnu := -Wall -g -fPIC -mips32r2 -msoft-float -mabi=32 -mno-compact-eh $(CFLAGS)
+CFG_JEMALLOC_CFLAGS_mips-unknown-linux-gnu := -mips32r2 -msoft-float -mabi=32 $(CFLAGS)
+CFG_GCCISH_CFLAGS_mips-unknown-linux-gnu := -Wall -g -fPIC -mips32r2 -msoft-float -mabi=32 $(CFLAGS)
CFG_GCCISH_CXXFLAGS_mips-unknown-linux-gnu := -fno-rtti $(CXXFLAGS)
CFG_GCCISH_LINK_FLAGS_mips-unknown-linux-gnu := -shared -fPIC -g -mips32r2 -msoft-float -mabi=32
CFG_GCCISH_DEF_FLAG_mips-unknown-linux-gnu := -Wl,--export-dynamic,--dynamic-list=
CFG_LDPATH_mips-unknown-linux-gnu :=
CFG_RUN_mips-unknown-linux-gnu=
CFG_RUN_TARG_mips-unknown-linux-gnu=
-RUSTC_FLAGS_mips-unknown-linux-gnu := -C target-cpu=mips32r2 -C target-feature="+mips32r2,+o32" -C soft-float
+RUSTC_FLAGS_mips-unknown-linux-gnu := -C target-cpu=mips32r2 -C target-feature="+mips32r2" -C soft-float
CFG_GNU_TRIPLE_mips-unknown-linux-gnu := mips-unknown-linux-gnu
# mipsel-unknown-linux-gnu configuration
-CC_mipsel-unknown-linux-gnu=mipsel-unknown-linux-gnu-gcc
-CXX_mipsel-unknown-linux-gnu=mipsel-unknown-linux-gnu-g++
-CPP_mipsel-unknown-linux-gnu=mipsel-unknown-linux-gnu-gcc
-AR_mipsel-unknown-linux-gnu=mipsel-unknown-linux-gnu-ar
+CC_mipsel-unknown-linux-gnu=mipsel-linux-gnu-gcc
+CXX_mipsel-unknown-linux-gnu=mipsel-linux-gnu-g++
+CPP_mipsel-unknown-linux-gnu=mipsel-linux-gnu-gcc
+AR_mipsel-unknown-linux-gnu=mipsel-linux-gnu-ar
CFG_LIB_NAME_mipsel-unknown-linux-gnu=lib$(1).so
CFG_STATIC_LIB_NAME_mipsel-unknown-linux-gnu=lib$(1).a
CFG_LIB_GLOB_mipsel-unknown-linux-gnu=lib$(1)-*.so
CFG_LDPATH_mipsel-unknown-linux-gnu :=
CFG_RUN_mipsel-unknown-linux-gnu=
CFG_RUN_TARG_mipsel-unknown-linux-gnu=
-RUSTC_FLAGS_mipsel-unknown-linux-gnu := -C target-cpu=mips32 -C target-feature="+mips32,+o32"
+RUSTC_FLAGS_mipsel-unknown-linux-gnu := -C target-cpu=mips32 -C target-feature="+mips32"
CFG_GNU_TRIPLE_mipsel-unknown-linux-gnu := mipsel-unknown-linux-gnu
# * dist-docs - Stage docs for upload
PKG_NAME := $(CFG_PACKAGE_NAME)
+STD_PKG_NAME := rust-std-$(CFG_PACKAGE_VERS)
DOC_PKG_NAME := rust-docs-$(CFG_PACKAGE_VERS)
MINGW_PKG_NAME := rust-mingw-$(CFG_PACKAGE_VERS)
# Unix binary installer tarballs
######################################################################
-define DEF_INSTALLER
+define DEF_START_INSTALLER
+dist-install-dir-$(1)-%: PREPARE_DIR_CMD=$(DEFAULT_PREPARE_DIR_CMD)
+dist-install-dir-$(1)-%: PREPARE_BIN_CMD=$(DEFAULT_PREPARE_BIN_CMD)
+dist-install-dir-$(1)-%: PREPARE_LIB_CMD=$(DEFAULT_PREPARE_LIB_CMD)
+dist-install-dir-$(1)-%: PREPARE_MAN_CMD=$(DEFAULT_PREPARE_MAN_CMD)
+dist-install-dir-$(1)-%: PREPARE_CLEAN=true
$$(eval $$(call DEF_PREPARE,dir-$(1)))
+endef
+
+$(foreach target,$(CFG_TARGET),\
+ $(eval $(call DEF_START_INSTALLER,$(target))))
-dist-install-dir-$(1): PREPARE_HOST=$(1)
-dist-install-dir-$(1): PREPARE_TARGETS=$(2)
-dist-install-dir-$(1): PREPARE_DEST_DIR=tmp/dist/$$(PKG_NAME)-$(1)-image
-dist-install-dir-$(1): PREPARE_DIR_CMD=$(DEFAULT_PREPARE_DIR_CMD)
-dist-install-dir-$(1): PREPARE_BIN_CMD=$(DEFAULT_PREPARE_BIN_CMD)
-dist-install-dir-$(1): PREPARE_LIB_CMD=$(DEFAULT_PREPARE_LIB_CMD)
-dist-install-dir-$(1): PREPARE_MAN_CMD=$(DEFAULT_PREPARE_MAN_CMD)
-dist-install-dir-$(1): PREPARE_CLEAN=true
-dist-install-dir-$(1): prepare-base-dir-$(1) docs
+define DEF_INSTALLER
+
+dist-install-dir-$(1)-host: PREPARE_HOST=$(1)
+dist-install-dir-$(1)-host: PREPARE_TARGETS=$(2)
+dist-install-dir-$(1)-host: PREPARE_DEST_DIR=tmp/dist/$$(PKG_NAME)-$(1)-image
+dist-install-dir-$(1)-host: prepare-base-dir-$(1)-host docs
$$(Q)mkdir -p $$(PREPARE_DEST_DIR)/share/doc/rust
$$(Q)$$(PREPARE_MAN_CMD) $$(S)COPYRIGHT $$(PREPARE_DEST_DIR)/share/doc/rust
$$(Q)$$(PREPARE_MAN_CMD) $$(S)LICENSE-APACHE $$(PREPARE_DEST_DIR)/share/doc/rust
# This tiny morsel of metadata is used by rust-packaging
$$(Q)echo "$(CFG_VERSION)" > tmp/dist/$$(PKG_NAME)-$(1)-overlay/version
-dist/$$(PKG_NAME)-$(1).tar.gz: dist-install-dir-$(1) prepare-overlay-$(1)
+dist/$$(PKG_NAME)-$(1).tar.gz: dist-install-dir-$(1)-host prepare-overlay-$(1)
@$(call E, build: $$@)
-# Copy essential gcc components into installer
-ifdef CFG_WINDOWSY_$(1)
-ifeq ($$(findstring gnu,$(1)),gnu)
- $$(Q)rm -Rf tmp/dist/win-rust-gcc-$(1)
- $$(Q)$$(CFG_PYTHON) $$(S)src/etc/make-win-dist.py tmp/dist/$$(PKG_NAME)-$(1)-image tmp/dist/win-rust-gcc-$(1) $(1)
- $$(Q)cp -r $$(S)src/etc/third-party tmp/dist/$$(PKG_NAME)-$(1)-image/share/doc/
+# On a 32-bit MinGW target we've got a few runtime DLL dependencies that we need
+# to include. THe first argument to `make-win-dist` is where to put these DLLs
+# (the image we're creating) and the second argument is a junk directory to
+# ignore all the other MinGW stuff the script creates.
+ifeq ($(2),i686-pc-windows-gnu)
+ $$(Q)rm -Rf tmp/dist/win-rust-gcc-$(2)
+ $$(Q)$$(CFG_PYTHON) $$(S)src/etc/make-win-dist.py \
+ tmp/dist/$$(STD_PKG_NAME)-$(2)-image \
+ tmp/dist/win-rust-gcc-$(2) $(2)
+endif
+# On 32-bit MinGW we're always including a DLL which needs some extra licenses
+# to distribute. On 64-bit MinGW we don't actually distribute anything requiring
+# us to distribute a license but it's likely that the install will *also*
+# include the rust-mingw package down below, which also need licenses, so to be
+# safe we just inlude it here in all MinGW packages.
+ifdef CFG_WINDOWSY_$(2)
+ifeq ($$(findstring $(2),gnu),gnu)
+ $$(Q)cp -r $$(S)src/etc/third-party \
+ tmp/dist/$$(STD_PKG_NAME)-$(2)-image/share/doc/
endif
endif
$$(Q)$$(S)src/rust-installer/gen-installer.sh \
--bulk-dirs=share/doc/rust/html
$$(Q)rm -R tmp/dist/$$(DOC_PKG_NAME)-$(1)-image
+# Creates the rust-mingw package, and the first argument to make-win-dist is a
+# "temporary directory" which is just thrown away (this contains the runtime
+# DLLs included in the rustc package above) and the second argument is where to
+# place all the MinGW components (which is what we want).
dist-mingw-install-dir-$(1):
$$(Q)mkdir -p tmp/dist/rust-mingw-tmp-$(1)-image
$$(Q)rm -Rf tmp/dist/$$(MINGW_PKG_NAME)-$(1)-image
$$(Q)$$(CFG_PYTHON) $$(S)src/etc/make-win-dist.py \
- tmp/dist/rust-mingw-tmp-$(1)-image tmp/dist/$$(MINGW_PKG_NAME)-$(1)-image $(1)
+ tmp/dist/rust-mingw-tmp-$(1)-image \
+ tmp/dist/$$(MINGW_PKG_NAME)-$(1)-image $(1)
dist/$$(MINGW_PKG_NAME)-$(1).tar.gz: dist-mingw-install-dir-$(1)
@$(call E, build: $$@)
endef
-ifneq ($(CFG_ENABLE_DIST_HOST_ONLY),)
-$(foreach host,$(CFG_HOST),\
- $(eval $(call DEF_INSTALLER,$(host),$(host))))
-else
-$(foreach host,$(CFG_HOST),\
- $(eval $(call DEF_INSTALLER,$(host),$(CFG_TARGET))))
-endif
+# $(1) - host
+# $(2) - target
+define DEF_INSTALLER_TARGETS
+
+dist-install-dir-$(2)-target: PREPARE_HOST=$(1)
+dist-install-dir-$(2)-target: PREPARE_TARGETS=$(2)
+dist-install-dir-$(2)-target: PREPARE_DEST_DIR=tmp/dist/$$(STD_PKG_NAME)-$(2)-image
+dist-install-dir-$(2)-target: prepare-base-dir-$(2)-target
-dist-install-dirs: $(foreach host,$(CFG_HOST),dist-install-dir-$(host))
+dist/$$(STD_PKG_NAME)-$(2).tar.gz: dist-install-dir-$(2)-target
+ @$$(call E, build: $$@)
+ $$(Q)$$(S)src/rust-installer/gen-installer.sh \
+ --product-name=Rust \
+ --rel-manifest-dir=rustlib \
+ --success-message=std-is-standing-at-the-ready. \
+ --image-dir=tmp/dist/$$(STD_PKG_NAME)-$(2)-image \
+ --work-dir=tmp/dist \
+ --output-dir=dist \
+ --package-name=$$(STD_PKG_NAME)-$(2) \
+ --component-name=rust-std-$(2) \
+ --legacy-manifest-dirs=rustlib,cargo
+ $$(Q)rm -R tmp/dist/$$(STD_PKG_NAME)-$(2)-image
+endef
+
+$(foreach host,$(CFG_HOST),\
+ $(eval $(call DEF_INSTALLER,$(host))))
+$(foreach target,$(CFG_TARGET),\
+ $(eval $(call DEF_INSTALLER_TARGETS,$(CFG_BUILD),$(target))))
ifdef CFG_WINDOWSY_$(CFG_BUILD)
define BUILD_MINGW_TARBALL
MAYBE_DOC_TARBALLS=$(foreach host,$(CFG_HOST),dist/$(DOC_PKG_NAME)-$(host).tar.gz)
endif
-dist-tar-bins: $(foreach host,$(CFG_HOST),dist/$(PKG_NAME)-$(host).tar.gz) \
+dist-tar-bins: \
+ $(foreach host,$(CFG_HOST),dist/$(PKG_NAME)-$(host).tar.gz) \
+ $(foreach target,$(CFG_TARGET),dist/$(STD_PKG_NAME)-$(target).tar.gz) \
$(MAYBE_DOC_TARBALLS) $(MAYBE_MINGW_TARBALLS)
# Just try to run the compiler for the build host
# option. This file may not be copied, modified, or distributed
# except according to those terms.
+RUN_INSALLER = cd tmp/empty_dir && \
+ sh ../../tmp/dist/$(1)/install.sh \
+ --prefix="$(DESTDIR)$(CFG_PREFIX)" \
+ --libdir="$(DESTDIR)$(CFG_LIBDIR)" \
+ --mandir="$(DESTDIR)$(CFG_MANDIR)"
+
install:
ifeq (root user, $(USER) $(patsubst %,user,$(SUDO_USER)))
# Build the dist as the original user
$(Q)$(MAKE) prepare_install
endif
ifeq ($(CFG_DISABLE_DOCS),)
- $(Q)cd tmp/empty_dir && sh ../../tmp/dist/$(DOC_PKG_NAME)-$(CFG_BUILD)/install.sh --prefix="$(DESTDIR)$(CFG_PREFIX)" --libdir="$(DESTDIR)$(CFG_LIBDIR)" --mandir="$(DESTDIR)$(CFG_MANDIR)"
+ $(Q)$(call RUN_INSALLER,$(DOC_PKG_NAME)-$(CFG_BUILD)) --disable-ldconfig
endif
- $(Q)cd tmp/empty_dir && sh ../../tmp/dist/$(PKG_NAME)-$(CFG_BUILD)/install.sh --prefix="$(DESTDIR)$(CFG_PREFIX)" --libdir="$(DESTDIR)$(CFG_LIBDIR)" --mandir="$(DESTDIR)$(CFG_MANDIR)"
+ $(Q)$(foreach target,$(CFG_TARGET),\
+ ($(call RUN_INSALLER,$(STD_PKG_NAME)-$(target)) --disable-ldconfig);)
+ $(Q)$(call RUN_INSALLER,$(PKG_NAME)-$(CFG_BUILD))
# Remove tmp files because it's a decent amount of disk space
$(Q)rm -R tmp/dist
$(Q)$(MAKE) prepare_uninstall
endif
ifeq ($(CFG_DISABLE_DOCS),)
- $(Q)cd tmp/empty_dir && sh ../../tmp/dist/$(DOC_PKG_NAME)-$(CFG_BUILD)/install.sh --uninstall --prefix="$(DESTDIR)$(CFG_PREFIX)" --libdir="$(DESTDIR)$(CFG_LIBDIR)" --mandir="$(DESTDIR)$(CFG_MANDIR)"
+ $(Q)$(call RUN_INSALLER,$(DOC_PKG_NAME)-$(CFG_BUILD)) --uninstall
endif
- $(Q)cd tmp/empty_dir && sh ../../tmp/dist/$(PKG_NAME)-$(CFG_BUILD)/install.sh --uninstall --prefix="$(DESTDIR)$(CFG_PREFIX)" --libdir="$(DESTDIR)$(CFG_LIBDIR)" --mandir="$(DESTDIR)$(CFG_MANDIR)"
+ $(Q)$(call RUN_INSALLER,$(PKG_NAME)-$(CFG_BUILD)) --uninstall
+ $(Q)$(foreach target,$(CFG_TARGET),\
+ ($(call RUN_INSALLER,$(STD_PKG_NAME)-$(target)) --uninstall);)
# Remove tmp files because it's a decent amount of disk space
$(Q)rm -R tmp/dist
define DEF_PREPARE
-prepare-base-$(1): PREPARE_SOURCE_DIR=$$(PREPARE_HOST)/stage$$(PREPARE_STAGE)
-prepare-base-$(1): PREPARE_SOURCE_BIN_DIR=$$(PREPARE_SOURCE_DIR)/bin
-prepare-base-$(1): PREPARE_SOURCE_LIB_DIR=$$(PREPARE_SOURCE_DIR)/$$(CFG_LIBDIR_RELATIVE)
-prepare-base-$(1): PREPARE_SOURCE_MAN_DIR=$$(S)/man
-prepare-base-$(1): PREPARE_DEST_BIN_DIR=$$(PREPARE_DEST_DIR)/bin
-prepare-base-$(1): PREPARE_DEST_LIB_DIR=$$(PREPARE_DEST_DIR)/$$(CFG_LIBDIR_RELATIVE)
-prepare-base-$(1): PREPARE_DEST_MAN_DIR=$$(PREPARE_DEST_DIR)/share/man/man1
-prepare-base-$(1): prepare-everything-$(1)
+prepare-base-$(1)-%: PREPARE_SOURCE_DIR=$$(PREPARE_HOST)/stage$$(PREPARE_STAGE)
+prepare-base-$(1)-%: PREPARE_SOURCE_BIN_DIR=$$(PREPARE_SOURCE_DIR)/bin
+prepare-base-$(1)-%: PREPARE_SOURCE_LIB_DIR=$$(PREPARE_SOURCE_DIR)/$$(CFG_LIBDIR_RELATIVE)
+prepare-base-$(1)-%: PREPARE_SOURCE_MAN_DIR=$$(S)/man
+prepare-base-$(1)-%: PREPARE_DEST_BIN_DIR=$$(PREPARE_DEST_DIR)/bin
+prepare-base-$(1)-%: PREPARE_DEST_LIB_DIR=$$(PREPARE_DEST_DIR)/$$(CFG_LIBDIR_RELATIVE)
+prepare-base-$(1)-%: PREPARE_DEST_MAN_DIR=$$(PREPARE_DEST_DIR)/share/man/man1
-prepare-everything-$(1): prepare-host-$(1) prepare-targets-$(1) prepare-debugger-scripts-$(1)
+prepare-base-$(1)-target: prepare-target-$(1)
+prepare-base-$(1)-host: prepare-host-$(1) prepare-debugger-scripts-$(1)
prepare-host-$(1): prepare-host-tools-$(1)
$$(foreach host,$$(CFG_HOST), \
$$(eval $$(call DEF_PREPARE_HOST_LIB,$$(lib),$$(PREPARE_STAGE),$$(host),$(1)))))
-prepare-targets-$(1): \
+prepare-target-$(1): \
$$(foreach host,$$(CFG_HOST), \
$$(foreach target,$$(CFG_TARGET), \
prepare-target-$$(target)-host-$$(host)-$$(PREPARE_STAGE)-$(1)))
It is sometimes obvious that no such access can occur, like the case above.
However, when dealing with a generic type parameter, such access can
occur indirectly. Examples of such indirect access are:
+
* invoking a callback,
* via a trait method call.
fn new(data: T) -> Self {
unsafe {
// Wouldn't it be nice if heap::allocate worked like this?
- let ptr = heap::allocate<RcBox<T>>();
+ let ptr = heap::allocate::<RcBox<T>>();
ptr::write(ptr, RcBox {
data: data,
ref_count: 1,
use alloc::raw_vec::RawVec;
+use super::range::RangeArgument;
+
const INITIAL_CAPACITY: usize = 7; // 2^3 - 1
const MINIMUM_CAPACITY: usize = 1; // 2 - 1
const MAXIMUM_ZST_CAPACITY: usize = 1 << (usize::BITS - 1); // Largest possible power of two
len);
}
+ /// Copies a potentially wrapping block of memory len long from src to dest.
+ /// (abs(dst - src) + len) must be no larger than cap() (There must be at
+ /// most one continuous overlapping region between src and dest).
+ unsafe fn wrap_copy(&self, dst: usize, src: usize, len: usize) {
+ debug_assert!(
+ (if src <= dst { dst - src } else { src - dst }) + len <= self.cap(),
+ "dst={} src={} len={} cap={}", dst, src, len, self.cap());
+
+ if src == dst || len == 0 { return }
+
+ let dst_after_src = self.wrap_sub(dst, src) < len;
+
+ let src_pre_wrap_len = self.cap() - src;
+ let dst_pre_wrap_len = self.cap() - dst;
+ let src_wraps = src_pre_wrap_len < len;
+ let dst_wraps = dst_pre_wrap_len < len;
+
+ match (dst_after_src, src_wraps, dst_wraps) {
+ (_, false, false) => {
+ // src doesn't wrap, dst doesn't wrap
+ //
+ // S . . .
+ // 1 [_ _ A A B B C C _]
+ // 2 [_ _ A A A A B B _]
+ // D . . .
+ //
+ self.copy(dst, src, len);
+ }
+ (false, false, true) => {
+ // dst before src, src doesn't wrap, dst wraps
+ //
+ // S . . .
+ // 1 [A A B B _ _ _ C C]
+ // 2 [A A B B _ _ _ A A]
+ // 3 [B B B B _ _ _ A A]
+ // . . D .
+ //
+ self.copy(dst, src, dst_pre_wrap_len);
+ self.copy(0, src + dst_pre_wrap_len, len - dst_pre_wrap_len);
+ }
+ (true, false, true) => {
+ // src before dst, src doesn't wrap, dst wraps
+ //
+ // S . . .
+ // 1 [C C _ _ _ A A B B]
+ // 2 [B B _ _ _ A A B B]
+ // 3 [B B _ _ _ A A A A]
+ // . . D .
+ //
+ self.copy(0, src + dst_pre_wrap_len, len - dst_pre_wrap_len);
+ self.copy(dst, src, dst_pre_wrap_len);
+ }
+ (false, true, false) => {
+ // dst before src, src wraps, dst doesn't wrap
+ //
+ // . . S .
+ // 1 [C C _ _ _ A A B B]
+ // 2 [C C _ _ _ B B B B]
+ // 3 [C C _ _ _ B B C C]
+ // D . . .
+ //
+ self.copy(dst, src, src_pre_wrap_len);
+ self.copy(dst + src_pre_wrap_len, 0, len - src_pre_wrap_len);
+ }
+ (true, true, false) => {
+ // src before dst, src wraps, dst doesn't wrap
+ //
+ // . . S .
+ // 1 [A A B B _ _ _ C C]
+ // 2 [A A A A _ _ _ C C]
+ // 3 [C C A A _ _ _ C C]
+ // D . . .
+ //
+ self.copy(dst + src_pre_wrap_len, 0, len - src_pre_wrap_len);
+ self.copy(dst, src, src_pre_wrap_len);
+ }
+ (false, true, true) => {
+ // dst before src, src wraps, dst wraps
+ //
+ // . . . S .
+ // 1 [A B C D _ E F G H]
+ // 2 [A B C D _ E G H H]
+ // 3 [A B C D _ E G H A]
+ // 4 [B C C D _ E G H A]
+ // . . D . .
+ //
+ debug_assert!(dst_pre_wrap_len > src_pre_wrap_len);
+ let delta = dst_pre_wrap_len - src_pre_wrap_len;
+ self.copy(dst, src, src_pre_wrap_len);
+ self.copy(dst + src_pre_wrap_len, 0, delta);
+ self.copy(0, delta, len - dst_pre_wrap_len);
+ }
+ (true, true, true) => {
+ // src before dst, src wraps, dst wraps
+ //
+ // . . S . .
+ // 1 [A B C D _ E F G H]
+ // 2 [A A B D _ E F G H]
+ // 3 [H A B D _ E F G H]
+ // 4 [H A B D _ E F F G]
+ // . . . D .
+ //
+ debug_assert!(src_pre_wrap_len > dst_pre_wrap_len);
+ let delta = src_pre_wrap_len - dst_pre_wrap_len;
+ self.copy(delta, 0, len - src_pre_wrap_len);
+ self.copy(0, self.cap() - delta, delta);
+ self.copy(dst, src, dst_pre_wrap_len);
+ }
+ }
+ }
+
/// Frobs the head and tail sections around to handle the fact that we
/// just reallocated. Unsafe because it trusts old_cap.
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn is_empty(&self) -> bool { self.len() == 0 }
- /// Creates a draining iterator that clears the `VecDeque` and iterates over
- /// the removed items from start to end.
+ /// Create a draining iterator that removes the specified range in the
+ /// `VecDeque` and yields the removed items from start to end. The element
+ /// range is removed even if the iterator is not consumed until the end.
+ ///
+ /// Note: It is unspecified how many elements are removed from the deque,
+ /// if the `Drain` value is not dropped, but the borrow it holds expires
+ /// (eg. due to mem::forget).
+ ///
+ /// # Panics
+ ///
+ /// Panics if the starting point is greater than the end point or if
+ /// the end point is greater than the length of the vector.
///
/// # Examples
///
///
/// use std::collections::VecDeque;
///
+ /// // draining using `..` clears the whole deque.
/// let mut v = VecDeque::new();
/// v.push_back(1);
- /// assert_eq!(v.drain().next(), Some(1));
+ /// assert_eq!(v.drain(..).next(), Some(1));
/// assert!(v.is_empty());
/// ```
#[inline]
#[unstable(feature = "drain",
reason = "matches collection reform specification, waiting for dust to settle",
issue = "27711")]
- pub fn drain(&mut self) -> Drain<T> {
+ pub fn drain<R>(&mut self, range: R) -> Drain<T> where R: RangeArgument<usize> {
+ // Memory safety
+ //
+ // When the Drain is first created, the source deque is shortened to
+ // make sure no uninitialized or moved-from elements are accessible at
+ // all if the Drain's destructor never gets to run.
+ //
+ // Drain will ptr::read out the values to remove.
+ // When finished, the remaining data will be copied back to cover the hole,
+ // and the head/tail values will be restored correctly.
+ //
+ let len = self.len();
+ let start = *range.start().unwrap_or(&0);
+ let end = *range.end().unwrap_or(&len);
+ assert!(start <= end, "drain lower bound was too large");
+ assert!(end <= len, "drain upper bound was too large");
+
+ // The deque's elements are parted into three segments:
+ // * self.tail -> drain_tail
+ // * drain_tail -> drain_head
+ // * drain_head -> self.head
+ //
+ // T = self.tail; H = self.head; t = drain_tail; h = drain_head
+ //
+ // We store drain_tail as self.head, and drain_head and self.head as
+ // after_tail and after_head respectively on the Drain. This also
+ // truncates the effective array such that if the Drain is leaked, we
+ // have forgotten about the potentially moved values after the start of
+ // the drain.
+ //
+ // T t h H
+ // [. . . o o x x o o . . .]
+ //
+ let drain_tail = self.wrap_add(self.tail, start);
+ let drain_head = self.wrap_add(self.tail, end);
+ let head = self.head;
+
+ // "forget" about the values after the start of the drain until after
+ // the drain is complete and the Drain destructor is run.
+ self.head = drain_tail;
+
Drain {
- inner: self,
+ deque: self as *mut _,
+ after_tail: drain_head,
+ after_head: head,
+ iter: Iter {
+ tail: drain_tail,
+ head: drain_head,
+ ring: unsafe { self.buffer_as_mut_slice() },
+ },
}
}
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
pub fn clear(&mut self) {
- self.drain();
+ self.drain(..);
}
/// Provides a reference to the front element, or `None` if the sequence is
#[stable(feature = "append", since = "1.4.0")]
pub fn append(&mut self, other: &mut Self) {
// naive impl
- self.extend(other.drain());
+ self.extend(other.drain(..));
}
/// Retains only the elements specified by the predicate.
reason = "matches collection reform specification, waiting for dust to settle",
issue = "27711")]
pub struct Drain<'a, T: 'a> {
- inner: &'a mut VecDeque<T>,
+ after_tail: usize,
+ after_head: usize,
+ iter: Iter<'a, T>,
+ deque: *mut VecDeque<T>,
}
+unsafe impl<'a, T: Sync> Sync for Drain<'a, T> {}
+unsafe impl<'a, T: Send> Send for Drain<'a, T> {}
+
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, T: 'a> Drop for Drain<'a, T> {
fn drop(&mut self) {
for _ in self.by_ref() {}
- self.inner.head = 0;
- self.inner.tail = 0;
+
+ let source_deque = unsafe { &mut *self.deque };
+
+ // T = source_deque_tail; H = source_deque_head; t = drain_tail; h = drain_head
+ //
+ // T t h H
+ // [. . . o o x x o o . . .]
+ //
+ let orig_tail = source_deque.tail;
+ let drain_tail = source_deque.head;
+ let drain_head = self.after_tail;
+ let orig_head = self.after_head;
+
+ let tail_len = count(orig_tail, drain_tail, source_deque.cap());
+ let head_len = count(drain_head, orig_head, source_deque.cap());
+
+ // Restore the original head value
+ source_deque.head = orig_head;
+
+ match (tail_len, head_len) {
+ (0, 0) => {
+ source_deque.head = 0;
+ source_deque.tail = 0;
+ }
+ (0, _) => {
+ source_deque.tail = drain_head;
+ }
+ (_, 0) => {
+ source_deque.head = drain_tail;
+ }
+ _ => unsafe {
+ if tail_len <= head_len {
+ source_deque.tail = source_deque.wrap_sub(drain_head, tail_len);
+ source_deque.wrap_copy(source_deque.tail, orig_tail, tail_len);
+ } else {
+ source_deque.head = source_deque.wrap_add(drain_tail, head_len);
+ source_deque.wrap_copy(drain_tail, drain_head, head_len);
+ }
+ }
+ }
}
}
#[inline]
fn next(&mut self) -> Option<T> {
- self.inner.pop_front()
+ self.iter.next().map(|elt|
+ unsafe {
+ ptr::read(elt)
+ }
+ )
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
- let len = self.inner.len();
- (len, Some(len))
+ self.iter.size_hint()
}
}
impl<'a, T: 'a> DoubleEndedIterator for Drain<'a, T> {
#[inline]
fn next_back(&mut self) -> Option<T> {
- self.inner.pop_back()
+ self.iter.next_back().map(|elt|
+ unsafe {
+ ptr::read(elt)
+ }
+ )
}
}
}
}
+ #[test]
+ fn test_drain() {
+ let mut tester: VecDeque<usize> = VecDeque::with_capacity(7);
+
+ let cap = tester.capacity();
+ for len in 0..cap + 1 {
+ for tail in 0..cap + 1 {
+ for drain_start in 0..len + 1 {
+ for drain_end in drain_start..len + 1 {
+ tester.tail = tail;
+ tester.head = tail;
+ for i in 0..len {
+ tester.push_back(i);
+ }
+
+ // Check that we drain the correct values
+ let drained: VecDeque<_> =
+ tester.drain(drain_start..drain_end).collect();
+ let drained_expected: VecDeque<_> =
+ (drain_start..drain_end).collect();
+ assert_eq!(drained, drained_expected);
+
+ // We shouldn't have changed the capacity or made the
+ // head or tail out of bounds
+ assert_eq!(tester.capacity(), cap);
+ assert!(tester.tail < tester.cap());
+ assert!(tester.head < tester.cap());
+
+ // We should see the correct values in the VecDeque
+ let expected: VecDeque<_> =
+ (0..drain_start).chain(drain_end..len).collect();
+ assert_eq!(expected, tester);
+ }
+ }
+ }
+ }
+ }
+
#[test]
fn test_shrink_to_fit() {
// This test checks that every single combination of head and tail position,
let mut d: VecDeque<i32> = VecDeque::new();
{
- let mut iter = d.drain();
+ let mut iter = d.drain(..);
assert_eq!(iter.size_hint(), (0, Some(0)));
assert_eq!(iter.next(), None);
d.push_back(i);
}
- assert_eq!(d.drain().collect::<Vec<_>>(), [0, 1, 2, 3, 4]);
+ assert_eq!(d.drain(..).collect::<Vec<_>>(), [0, 1, 2, 3, 4]);
assert!(d.is_empty());
}
d.push_front(i);
}
- assert_eq!(d.drain().collect::<Vec<_>>(), [8,7,6,0,1,2,3,4]);
+ assert_eq!(d.drain(..).collect::<Vec<_>>(), [8,7,6,0,1,2,3,4]);
assert!(d.is_empty());
}
}
{
- let mut it = d.drain();
+ let mut it = d.drain(..);
assert_eq!(it.size_hint(), (8, Some(8)));
assert_eq!(it.next(), Some(8));
assert_eq!(it.size_hint(), (7, Some(7)));
impl<T> !Send for *mut T { }
/// Types with a constant size known at compile-time.
+///
+/// All type parameters which can be bounded have an implicit bound of `Sized`. The special syntax
+/// `?Sized` can be used to remove this bound if it is not appropriate.
+///
+/// ```
+/// struct Foo<T>(T);
+/// struct Bar<T: ?Sized>(T);
+///
+/// // struct FooUse(Foo<[i32]>); // error: Sized is not implemented for [i32]
+/// struct BarUse(Bar<[i32]>); // OK
+/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[lang = "sized"]
#[rustc_on_unimplemented = "`{Self}` does not have a constant size known at compile-time"]
}
}
}
+
+ #[test]
+ fn read_dir_not_found() {
+ let res = fs::read_dir("/path/that/does/not/exist");
+ assert_eq!(res.err().unwrap().kind(), ErrorKind::NotFound);
+ }
}
drop(p.wait());
}
- #[cfg(unix)]
#[cfg(all(unix, not(target_os="android")))]
+ #[test]
fn signal_reported_right() {
use os::unix::process::ExitStatusExt;
pub const EXCEPTION_MAXIMUM_PARAMETERS: usize = 15;
pub const EXCEPTION_STACK_OVERFLOW: DWORD = 0xc00000fd;
+pub const ERROR_PATH_NOT_FOUND: libc::c_int = 3;
+
#[repr(C)]
#[cfg(target_arch = "x86")]
pub struct WSADATA {
libc::ERROR_ALREADY_EXISTS => ErrorKind::AlreadyExists,
libc::ERROR_BROKEN_PIPE => ErrorKind::BrokenPipe,
libc::ERROR_FILE_NOT_FOUND => ErrorKind::NotFound,
+ c::ERROR_PATH_NOT_FOUND => ErrorKind::NotFound,
libc::ERROR_NO_DATA => ErrorKind::BrokenPipe,
libc::ERROR_OPERATION_ABORTED => ErrorKind::TimedOut,
let mut attrs = newitem.attrs.clone();
attrs.extend(item.attrs.iter().filter(|a| {
match &a.name()[..] {
- "allow" | "warn" | "deny" | "forbid" => true,
+ "allow" | "warn" | "deny" | "forbid" | "stable" | "unstable" => true,
_ => false,
}
}).cloned());
}
all_sync_send!(EnumSet::<Foo>::new(), iter);
- all_sync_send!(VecDeque::<usize>::new(), iter, iter_mut, drain, into_iter);
+ all_sync_send!(VecDeque::<usize>::new(), iter, iter_mut, into_iter);
+ is_sync_send!(VecDeque::<usize>::new(), drain(..));
all_sync_send!(Vec::<usize>::new(), into_iter);
is_sync_send!(Vec::<usize>::new(), drain(..));