Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Run on stable Rust #14

Merged
merged 7 commits into from
Jul 24, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 8 additions & 3 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
language: rust
rust: nightly
rust:
- nightly
- beta
- stable
script:
- cargo test
- cargo build
- cargo doc
- (cd capi/ctest; ./build-and-test.sh)
- cargo test
- "if [ $TRAVIS_RUST_VERSION = nightly ]; then cargo test --features unstable; fi"
- "if [ $TRAVIS_RUST_VERSION = nightly ]; then (cd capi/ctest; ./build-and-test.sh); fi"
after_success: curl https://raw.githubusercontent.com/kmcallister/travis-doc-upload/master/travis-doc-upload.sh | sh
notifications:
webhooks: http://build.servo.org:54856/travis
7 changes: 5 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[package]

name = "tendril"
version = "0.1.2"
version = "0.1.3"
authors = ["Keegan McAllister <mcallister.keegan@gmail.com>"]
repository = "https://github.com/kmcallister/tendril"
readme = "README.md"
Expand All @@ -11,7 +11,10 @@ description = "compact buffer / string type for zero-copy parsing"
[dependencies]
mac = "0"
encoding = "0"
futf = "0.1"
futf = "0.1.1"

[dev-dependencies]
rand = "0"

[features]
unstable = []
1 change: 1 addition & 0 deletions capi/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ libc = "0.1"

[dependencies.tendril]
path = "../"
features = ["unstable"] # Drop flags and C API don’t play friends

[build-dependencies]
gcc = "0"
16 changes: 12 additions & 4 deletions examples/fuzz.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@

//! A simple fuzz tester for the library.

#![feature(unsafe_no_drop_flag, str_char)]
#![deny(warnings)]

extern crate rand;
Expand Down Expand Up @@ -106,7 +105,7 @@ fn fuzz() {
fn random_boundary<R: Rng>(rng: &mut R, text: &str) -> usize {
loop {
let i = Range::new(0, text.len()+1).ind_sample(rng);
if text.is_char_boundary(i) {
if is_char_boundary(text, i) {
return i;
}
}
Expand All @@ -116,16 +115,25 @@ fn random_slice<R: Rng>(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 !text.is_char_boundary(start) {
if !is_char_boundary(text, start) {
continue;
}
if end < text.len() && !text.is_char_boundary(end) {
if end < text.len() && !is_char_boundary(text, 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. \
Expand Down
56 changes: 18 additions & 38 deletions src/buf32.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,12 @@

//! Provides an unsafe owned buffer type, used in implementing `Tendril`.

use std::{mem, ptr, cmp, u32, slice};
use std::rt::heap;
use std::{mem, ptr, u32, slice};

use OFLOW;

pub const MIN_CAP: u32 = 16;

// NB: This alignment must be sufficient for H!
pub const MIN_ALIGN: usize = 4;

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
Expand All @@ -28,17 +24,12 @@ pub struct Buf32<H> {
}

#[inline(always)]
fn add_header<H>(x: u32) -> usize {
(x as usize).checked_add(mem::size_of::<H>())
.expect(OFLOW)
}

#[inline(always)]
fn full_cap<H>(size: usize) -> u32 {
cmp::min(u32::MAX as usize,
heap::usable_size(size, MIN_ALIGN)
.checked_sub(mem::size_of::<H>())
.expect(OFLOW)) as u32
fn bytes_to_vec_capacity<H>(x: u32) -> usize {
let header = mem::size_of::<H>();
debug_assert!(header > 0);
let x = (x as usize).checked_add(header).expect(OFLOW);
// Integer ceil http://stackoverflow.com/a/2745086/1162888
1 + ((x - 1) / header)
}

impl<H> Buf32<H> {
Expand All @@ -48,26 +39,21 @@ impl<H> Buf32<H> {
cap = MIN_CAP;
}

let alloc_size = add_header::<H>(cap);
let ptr = heap::allocate(alloc_size, MIN_ALIGN);
if ptr.is_null() {
::alloc::oom();
}

let ptr = ptr as *mut H;
let mut vec = Vec::<H>::with_capacity(bytes_to_vec_capacity::<H>(cap));
let ptr = vec.as_mut_ptr();
mem::forget(vec);
ptr::write(ptr, h);

Buf32 {
ptr: ptr,
len: 0,
cap: full_cap::<H>(alloc_size),
cap: cap,
}
}

#[inline]
pub unsafe fn destroy(self) {
let alloc_size = add_header::<H>(self.cap);
heap::deallocate(self.ptr as *mut u8, alloc_size, MIN_ALIGN);
mem::drop(Vec::from_raw_parts(self.ptr, 1, bytes_to_vec_capacity::<H>(self.cap)));
}

#[inline(always)]
Expand Down Expand Up @@ -95,17 +81,11 @@ impl<H> Buf32<H> {
}

let new_cap = new_cap.checked_next_power_of_two().expect(OFLOW);
let alloc_size = add_header::<H>(new_cap);
let ptr = heap::reallocate(self.ptr as *mut u8,
add_header::<H>(new_cap),
alloc_size,
MIN_ALIGN);
if ptr.is_null() {
::alloc::oom();
}

self.ptr = ptr as *mut H;
self.cap = full_cap::<H>(alloc_size);
let mut vec = Vec::from_raw_parts(self.ptr, 0, bytes_to_vec_capacity::<H>(self.cap));
vec.reserve_exact(bytes_to_vec_capacity::<H>(new_cap));
self.ptr = vec.as_mut_ptr();
self.cap = new_cap;
mem::forget(vec);
}
}

Expand All @@ -117,7 +97,7 @@ mod test {
#[test]
fn smoke_test() {
unsafe {
let mut b = Buf32::with_capacity(0, ());
let mut b = Buf32::with_capacity(0, 0u8);
assert_eq!(b"", b.data());

b.grow(5);
Expand Down
32 changes: 20 additions & 12 deletions src/fmt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,9 @@
//! the format sneaks in. For that reason, these traits require
//! `unsafe impl`.

use std::{char, str, mem, slice};
use std::{char, str, mem};
use std::default::Default;
use std::io::Write;

use futf::{self, Codepoint, Meaning};

Expand Down Expand Up @@ -266,8 +267,7 @@ unsafe impl<'a> CharFormat<'a> for ASCII {
{
let n = ch as u32;
if n > 0x7F { return Err(()); }
let n = n as u8;
cont(slice::ref_slice(&n));
cont(&[n as u8]);
Ok(())
}
}
Expand Down Expand Up @@ -344,10 +344,14 @@ unsafe impl<'a> CharFormat<'a> for UTF8 {
where F: FnOnce(&[u8])
{
unsafe {
let mut buf: [u8; 4] = mem::uninitialized();
let n = ch.encode_utf8(&mut buf).expect("Tendril: internal error");
debug_assert!(n <= 4);
cont(unsafe_slice(&buf, 0, n));
let mut utf_8: [u8; 4] = mem::uninitialized();
let bytes_written = {
let mut buffer = &mut utf_8[..];
write!(buffer, "{}", ch).ok().expect("Tendril: internal error");
debug_assert!(buffer.len() <= 4);
4 - buffer.len()
};
cont(unsafe_slice(&utf_8, 0, bytes_written));
Ok(())
}
}
Expand Down Expand Up @@ -434,9 +438,14 @@ unsafe impl Format for WTF8 {
};

let n = 0x10000 + ((hi as u32) << 10) + (lo as u32);
fixup.insert_len = char::from_u32(n).expect(ERR)
.encode_utf8(&mut fixup.insert_bytes).expect(ERR)
as u32;

fixup.insert_len = {
let mut buffer = &mut fixup.insert_bytes[..];
write!(buffer, "{}", char::from_u32(n).expect(ERR)).ok().expect(ERR);
debug_assert!(buffer.len() <= 4);
4 - buffer.len() as u32
};

return fixup;
}
}
Expand Down Expand Up @@ -491,8 +500,7 @@ unsafe impl<'a> CharFormat<'a> for Latin1 {
{
let n = ch as u32;
if n > 0xFF { return Err(()); }
let n = n as u8;
cont(slice::ref_slice(&n));
cont(&[n as u8]);
Ok(())
}
}
11 changes: 5 additions & 6 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,16 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![feature(alloc, core, unsafe_no_drop_flag, filling_drop, unicode, ref_slice, nonzero, heap_api, oom)]
#![cfg_attr(test, feature(test, str_char))]
#![deny(warnings)]
#![cfg_attr(feature = "unstable", feature(core, nonzero, unsafe_no_drop_flag, filling_drop))]
#![cfg_attr(all(test, feature = "unstable"), feature(test, str_char))]
#![cfg_attr(test, deny(warnings))]

extern crate alloc;
extern crate core;
#[cfg(feature = "unstable")] extern crate core;
#[macro_use] extern crate mac;
extern crate futf;
extern crate encoding;

#[cfg(test)]
#[cfg(all(test, feature = "unstable"))]
extern crate test;

pub use tendril::{Tendril, ByteTendril, StrTendril, SliceExt, ReadExt, SubtendrilError};
Expand Down
32 changes: 21 additions & 11 deletions src/tendril.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,18 @@ use std::marker::PhantomData;
use std::cell::Cell;
use std::ops::{Deref, DerefMut};
use std::iter::IntoIterator;
use std::io::Write;
use std::default::Default;
use std::cmp::Ordering;
use std::fmt as strfmt;

use core::nonzero::NonZero;
use encoding::{self, EncodingRef, DecoderTrap, EncoderTrap};

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};
use util::{unsafe_slice, unsafe_slice_mut, copy_and_advance, copy_lifetime_mut, copy_lifetime,
NonZero, is_post_drop};
use OFLOW;

const MAX_INLINE_LEN: usize = 8;
Expand Down Expand Up @@ -86,7 +87,7 @@ pub enum SubtendrilError {
///
/// The maximum length of a `Tendril` is 4 GB. The library will panic if
/// you attempt to go over the limit.
#[unsafe_no_drop_flag]
#[cfg_attr(feature = "unstable", unsafe_no_drop_flag)]
#[repr(packed)]
pub struct Tendril<F>
where F: fmt::Format,
Expand Down Expand Up @@ -126,7 +127,7 @@ impl<F> Drop for Tendril<F>
fn drop(&mut self) {
unsafe {
let p = *self.ptr.get();
if p <= MAX_INLINE_TAG || p == mem::POST_DROP_USIZE {
if p <= MAX_INLINE_TAG || is_post_drop(p) {
return;
}

Expand Down Expand Up @@ -976,7 +977,7 @@ impl io::Write for Tendril<fmt::Bytes> {
impl encoding::ByteWriter for Tendril<fmt::Bytes> {
#[inline]
fn write_byte(&mut self, b: u8) {
self.push_slice(slice::ref_slice(&b));
self.push_slice(&[b]);
}

#[inline]
Expand Down Expand Up @@ -1080,9 +1081,14 @@ impl Tendril<fmt::UTF8> {
#[inline]
pub fn push_char(&mut self, c: char) {
unsafe {
let mut buf: [u8; 4] = mem::uninitialized();
let n = c.encode_utf8(&mut buf).expect("Tendril::push_char: internal error");
self.push_bytes_without_validating(unsafe_slice(&buf, 0, n));
let mut utf_8: [u8; 4] = mem::uninitialized();
let bytes_written = {
let mut buffer = &mut utf_8[..];
write!(buffer, "{}", c).ok().expect("Tendril::push_char: internal error");
debug_assert!(buffer.len() <= 4);
4 - buffer.len()
};
self.push_bytes_without_validating(unsafe_slice(&utf_8, 0, bytes_written));
}
}

Expand Down Expand Up @@ -1149,7 +1155,7 @@ impl<'a> From<&'a Tendril<fmt::UTF8>> for String {
}


#[cfg(test)]
#[cfg(all(test, feature = "unstable"))]
#[path="bench.rs"]
mod bench;

Expand All @@ -1173,11 +1179,15 @@ mod test {
#[test]
fn assert_sizes() {
use std::mem;
let correct = mem::size_of::<*const ()>() + 8;
let drop_flag = if cfg!(feature = "unstable") { 0 } else { 1 };
let correct = mem::size_of::<*const ()>() + 8 + drop_flag;

assert_eq!(correct, mem::size_of::<ByteTendril>());
assert_eq!(correct, mem::size_of::<StrTendril>());

// Check that the NonZero<T> optimization is working.
// Check that the NonZero<T> 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::<Option<ByteTendril>>());
assert_eq!(correct, mem::size_of::<Option<StrTendril>>());

Expand Down
Loading