diff --git a/.travis.yml b/.travis.yml index 643ba7b..c2335e6 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,7 +7,7 @@ script: - cargo build - cargo doc - cargo test - - "if [ $TRAVIS_RUST_VERSION = nightly ]; then cargo test --features unstable; fi" + - "if [ $TRAVIS_RUST_VERSION = nightly ]; then cargo test --features bench; fi" - "if [ $TRAVIS_RUST_VERSION = nightly ]; then (cd capi/ctest; ./build-and-test.sh); fi" notifications: webhooks: http://build.servo.org:54856/travis diff --git a/Cargo.toml b/Cargo.toml index d46bdb3..8171c48 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "tendril" -version = "0.3.0" +version = "0.4.0" authors = ["Keegan McAllister ", "Simon Sapin ", "Chris Morgan "] @@ -19,4 +19,4 @@ utf-8 = "0.7" rand = "0" [features] -unstable = [] +bench = [] diff --git a/capi/Cargo.toml b/capi/Cargo.toml index 8004b1a..7223ca0 100644 --- a/capi/Cargo.toml +++ b/capi/Cargo.toml @@ -16,7 +16,6 @@ libc = "0.1" [dependencies.tendril] path = "../" -features = ["unstable"] # Drop flags and C API don’t play friends [build-dependencies] gcc = "0" diff --git a/capi/include/tendril.h b/capi/include/tendril.h index 6e8a937..8ee0d70 100644 --- a/capi/include/tendril.h +++ b/capi/include/tendril.h @@ -102,7 +102,7 @@ void tendril_debug_dump(const tendril *t, FILE *stream); //// implementation details follow //// -__attribute__((packed)) struct tendril_impl { +struct tendril_impl { uintptr_t __ptr; uint32_t __a; uint32_t __b; diff --git a/examples/fuzz.rs b/examples/fuzz.rs index 9c978e9..6d77f67 100644 --- a/examples/fuzz.rs +++ b/examples/fuzz.rs @@ -105,7 +105,7 @@ fn fuzz() { fn random_boundary(rng: &mut R, text: &str) -> usize { loop { let i = Range::new(0, text.len()+1).ind_sample(rng); - if is_char_boundary(text, i) { + if text.is_char_boundary(i) { return i; } } @@ -115,25 +115,16 @@ fn random_slice(rng: &mut R, text: &str) -> (usize, usize) { loop { let start = Range::new(0, text.len()+1).ind_sample(rng); let end = Range::new(start, text.len()+1).ind_sample(rng); - if !is_char_boundary(text, start) { + if !text.is_char_boundary(start) { continue; } - if end < text.len() && !is_char_boundary(text, end) { + if end < text.len() && !text.is_char_boundary(end) { continue; } return (start, end); } } -// Copy of the str::is_char_boundary method, which is unstable. -fn is_char_boundary(s: &str, index: usize) -> bool { - if index == s.len() { return true; } - match s.as_bytes().get(index) { - None => false, - Some(&b) => b < 128 || b >= 192, - } -} - static TEXT: &'static str = "It was from the artists and poets that the pertinent answers came, and I \ know that panic would have broken loose had they been able to compare notes. \ diff --git a/src/buf32.rs b/src/buf32.rs index 9fe7316..3b1f911 100644 --- a/src/buf32.rs +++ b/src/buf32.rs @@ -16,7 +16,6 @@ pub const MAX_LEN: usize = u32::MAX as usize; /// A buffer points to a header of type `H`, which is followed by `MIN_CAP` or more /// bytes of storage. -#[repr(packed)] pub struct Buf32 { pub ptr: *mut H, pub len: u32, diff --git a/src/lib.rs b/src/lib.rs index b137582..23b8218 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -4,19 +4,15 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![cfg_attr(feature = "unstable", feature(nonzero))] -#![cfg_attr(all(test, feature = "unstable"), feature(test))] +#![cfg_attr(all(test, feature = "bench"), feature(test))] #![cfg_attr(test, deny(warnings))] -#[cfg(feature = "unstable")] extern crate core; +#[cfg(all(test, feature = "bench"))] extern crate test; #[cfg(feature = "encoding")] pub extern crate encoding; #[macro_use] extern crate mac; extern crate futf; extern crate utf8; -#[cfg(all(test, feature = "unstable"))] -extern crate test; - pub use tendril::{Tendril, ByteTendril, StrTendril, SliceExt, ReadExt, SubtendrilError}; pub use tendril::{SendTendril, Atomicity, Atomic, NonAtomic}; pub use fmt::Format; diff --git a/src/tendril.rs b/src/tendril.rs index 07c2a2c..19c528c 100644 --- a/src/tendril.rs +++ b/src/tendril.rs @@ -24,7 +24,7 @@ use buf32::{self, Buf32}; use fmt::{self, Slice}; use fmt::imp::Fixup; use util::{unsafe_slice, unsafe_slice_mut, copy_and_advance, copy_lifetime_mut, copy_lifetime, - NonZero}; + NonZeroUsize}; use OFLOW; const MAX_INLINE_LEN: usize = 8; @@ -32,10 +32,10 @@ const MAX_INLINE_TAG: usize = 0xF; const EMPTY_TAG: usize = 0xF; #[inline(always)] -fn inline_tag(len: u32) -> NonZero { +fn inline_tag(len: u32) -> NonZeroUsize { debug_assert!(len <= MAX_INLINE_LEN as u32); unsafe { - NonZero::new(if len == 0 { + NonZeroUsize::new(if len == 0 { EMPTY_TAG } else { len as usize @@ -47,7 +47,7 @@ fn inline_tag(len: u32) -> NonZero { /// /// Exactly two types implement this trait: /// -/// - `Atomic`: use this in your tendril and you will have a `Send + Sync` tendril which works +/// - `Atomic`: use this in your tendril and you will have a `Send` tendril which works /// across threads; this is akin to `Arc`. /// /// - `NonAtomic`: use this in your tendril and you will have a tendril which is neither @@ -104,8 +104,8 @@ unsafe impl Atomicity for NonAtomic { /// A marker of an atomic (and hence concurrent) tendril. /// -/// This is used as the second, optional type parameter of a `Tendril`; `Tendril` thus -/// implements both `Send` and `Sync`. +/// This is used as the second, optional type parameter of a `Tendril`; +/// `Tendril` thus implements`Send`. /// /// This is akin to using `Arc` for reference counting. pub struct Atomic(AtomicUsize); @@ -182,16 +182,16 @@ pub enum SubtendrilError { /// /// The type parameter `A` indicates the atomicity of the tendril; it is by /// default `NonAtomic`, but can be specified as `Atomic` to get a tendril -/// which implements `Send` and `Sync` (viz. a thread-safe tendril). +/// which implements `Send` (viz. a thread-safe tendril). /// /// The maximum length of a `Tendril` is 4 GB. The library will panic if /// you attempt to go over the limit. -#[repr(packed)] +#[repr(C)] pub struct Tendril where F: fmt::Format, A: Atomicity, { - ptr: Cell>, + ptr: Cell, len: u32, aux: Cell, marker: PhantomData<*mut F>, @@ -199,7 +199,6 @@ pub struct Tendril } unsafe impl Send for Tendril where F: fmt::Format, A: Atomicity + Sync { } -unsafe impl Sync for Tendril where F: fmt::Format, A: Atomicity + Sync { } /// `Tendril` for storing native Rust strings. pub type StrTendril = Tendril; @@ -586,7 +585,7 @@ impl Tendril #[inline] pub fn clear(&mut self) { if self.ptr.get().get() <= MAX_INLINE_TAG { - self.ptr.set(unsafe { NonZero::new(EMPTY_TAG) }); + self.ptr.set(unsafe { NonZeroUsize::new(EMPTY_TAG) }); } else { let (_, shared, _) = unsafe { self.assume_buf() }; if shared { @@ -966,7 +965,7 @@ impl Tendril let header = p as *mut Header; (*header).cap = self.aux.get(); - self.ptr.set(NonZero::new(p | 1)); + self.ptr.set(NonZeroUsize::new(p | 1)); self.aux.set(0); } } @@ -989,7 +988,7 @@ impl Tendril self.make_owned(); let mut buf = self.assume_buf().0; buf.grow(cap); - self.ptr.set(NonZero::new(buf.ptr as usize)); + self.ptr.set(NonZeroUsize::new(buf.ptr as usize)); self.aux.set(buf.cap); } @@ -1032,7 +1031,7 @@ impl Tendril #[inline] unsafe fn owned(x: Buf32>) -> Tendril { Tendril { - ptr: Cell::new(NonZero::new(x.ptr as usize)), + ptr: Cell::new(NonZeroUsize::new(x.ptr as usize)), len: x.len, aux: Cell::new(x.cap), marker: PhantomData, @@ -1052,7 +1051,7 @@ impl Tendril #[inline] unsafe fn shared(buf: Buf32>, off: u32, len: u32) -> Tendril { Tendril { - ptr: Cell::new(NonZero::new((buf.ptr as usize) | 1)), + ptr: Cell::new(NonZeroUsize::new((buf.ptr as usize) | 1)), len: len, aux: Cell::new(off), marker: PhantomData, @@ -1548,7 +1547,7 @@ impl<'a, A> From<&'a Tendril> for String } -#[cfg(all(test, feature = "unstable"))] +#[cfg(all(test, feature = "bench"))] #[path="bench.rs"] mod bench; @@ -1561,7 +1560,6 @@ mod test { use std::thread; fn assert_send() { } - fn assert_sync() { } #[test] fn smoke_test() { @@ -1589,9 +1587,6 @@ mod test { assert_eq!(correct, mem::size_of::()); assert_eq!(correct, mem::size_of::()); - // Check that the NonZero optimization is working, if on unstable Rust. - let option_tag = if cfg!(feature = "unstable") { 0 } else { 1 }; - let correct = correct + option_tag; assert_eq!(correct, mem::size_of::>()); assert_eq!(correct, mem::size_of::>()); @@ -2211,7 +2206,6 @@ mod test { #[test] fn atomic() { assert_send::>(); - assert_sync::>(); let s: Tendril = Tendril::from_slice("this is a string"); assert!(!s.is_shared()); let mut t = s.clone(); diff --git a/src/util.rs b/src/util.rs index 964fe31..af489e7 100644 --- a/src/util.rs +++ b/src/util.rs @@ -40,19 +40,18 @@ pub unsafe fn copy_lifetime<'a, S: ?Sized, T: ?Sized + 'a> mem::transmute(ptr) } -#[cfg(feature = "unstable")] pub use core::nonzero::NonZero; - -#[cfg(not(feature = "unstable"))] #[derive(Copy, Clone)] -pub struct NonZero(T); +pub struct NonZeroUsize(&'static u8); -#[cfg(not(feature = "unstable"))] -impl NonZero { - pub unsafe fn new(x: T) -> NonZero { NonZero(x) } -} +impl NonZeroUsize { + #[inline] + pub unsafe fn new(value: usize) -> Self { + debug_assert!(value != 0); + NonZeroUsize(&*(value as *const u8)) + } -#[cfg(not(feature = "unstable"))] -impl NonZero { #[inline] - pub fn get(self) -> T { self.0 } + pub fn get(self) -> usize { + self.0 as *const u8 as usize + } }