diff --git a/src/doc/complement-lang-faq.md b/src/doc/complement-lang-faq.md index 9e73863239fbc..a9a9e0858ec6b 100644 --- a/src/doc/complement-lang-faq.md +++ b/src/doc/complement-lang-faq.md @@ -17,7 +17,7 @@ Some examples that demonstrate different aspects of the language: * [sprocketnes], an NES emulator with no GC, using modern Rust conventions * The language's general-purpose [hash] function, SipHash-2-4. Bit twiddling, OO, macros * The standard library's [HashMap], a sendable hash map in an OO style -* The extra library's [json] module. Enums and pattern matching +* The standard library's [json] module. Enums and pattern matching [sprocketnes]: https://github.com/pcwalton/sprocketnes [hash]: https://github.com/rust-lang/rust/blob/master/src/libstd/hash/mod.rs diff --git a/src/doc/guide-ffi.md b/src/doc/guide-ffi.md index b8808eaf57d93..7ee1c1a7032a5 100644 --- a/src/doc/guide-ffi.md +++ b/src/doc/guide-ffi.md @@ -451,7 +451,7 @@ them. ~~~no_run extern crate libc; -use std::c_str::ToCStr; +use std::ffi::CString; use std::ptr; #[link(name = "readline")] @@ -460,11 +460,10 @@ extern { } fn main() { - "[my-awesome-shell] $".with_c_str(|buf| { - unsafe { rl_prompt = buf; } - // get a line, process it - unsafe { rl_prompt = ptr::null(); } - }); + let prompt = CString::from_slice(b"[my-awesome-shell] $"); + unsafe { rl_prompt = prompt.as_ptr(); } + // get a line, process it + unsafe { rl_prompt = ptr::null(); } } ~~~ @@ -509,23 +508,28 @@ to define a block for all windows systems, not just x86 ones. # Interoperability with foreign code -Rust guarantees that the layout of a `struct` is compatible with the platform's representation in C -only if the `#[repr(C)]` attribute is applied to it. `#[repr(C, packed)]` can be used to lay out -struct members without padding. `#[repr(C)]` can also be applied to an enum. - -Rust's owned boxes (`Box`) use non-nullable pointers as handles which point to the contained -object. However, they should not be manually created because they are managed by internal -allocators. References can safely be assumed to be non-nullable pointers directly to the type. -However, breaking the borrow checking or mutability rules is not guaranteed to be safe, so prefer -using raw pointers (`*`) if that's needed because the compiler can't make as many assumptions about -them. - -Vectors and strings share the same basic memory layout, and utilities are available in the `vec` and -`str` modules for working with C APIs. However, strings are not terminated with `\0`. If you need a -NUL-terminated string for interoperability with C, you should use the `c_str::to_c_str` function. - -The standard library includes type aliases and function definitions for the C standard library in -the `libc` module, and Rust links against `libc` and `libm` by default. +Rust guarantees that the layout of a `struct` is compatible with the platform's +representation in C only if the `#[repr(C)]` attribute is applied to it. +`#[repr(C, packed)]` can be used to lay out struct members without padding. +`#[repr(C)]` can also be applied to an enum. + +Rust's owned boxes (`Box`) use non-nullable pointers as handles which point +to the contained object. However, they should not be manually created because +they are managed by internal allocators. References can safely be assumed to be +non-nullable pointers directly to the type. However, breaking the borrow +checking or mutability rules is not guaranteed to be safe, so prefer using raw +pointers (`*`) if that's needed because the compiler can't make as many +assumptions about them. + +Vectors and strings share the same basic memory layout, and utilities are +available in the `vec` and `str` modules for working with C APIs. However, +strings are not terminated with `\0`. If you need a NUL-terminated string for +interoperability with C, you should use the `CString` type in the `std::ffi` +module. + +The standard library includes type aliases and function definitions for the C +standard library in the `libc` module, and Rust links against `libc` and `libm` +by default. # The "nullable pointer optimization" diff --git a/src/doc/guide-ownership.md b/src/doc/guide-ownership.md index bf750ecaa8f67..bdf589bbfe236 100644 --- a/src/doc/guide-ownership.md +++ b/src/doc/guide-ownership.md @@ -230,8 +230,9 @@ fn add_one(num: &int) -> int { ``` Rust has a feature called 'lifetime elision,' which allows you to not write -lifetime annotations in certain circumstances. This is one of them. Without -eliding the lifetimes, `add_one` looks like this: +lifetime annotations in certain circumstances. This is one of them. We will +cover the others later. Without eliding the lifetimes, `add_one` looks like +this: ```rust fn add_one<'a>(num: &'a int) -> int { @@ -449,6 +450,81 @@ This is the simplest kind of multiple ownership possible. For example, there's also `Arc`, which uses more expensive atomic instructions to be the thread-safe counterpart of `Rc`. +## Lifetime Elision + +Earlier, we mentioned 'lifetime elision,' a feature of Rust which allows you to +not write lifetime annotations in certain circumstances. All references have a +lifetime, and so if you elide a lifetime (like `&T` instead of `&'a T`), Rust +will do three things to determine what those lifetimes should be. + +When talking about lifetime elision, we use the term 'input lifetime' and +'output lifetime'. An 'input liftime' is a lifetime associated with a parameter +of a function, and an 'output lifetime' is a lifetime associated with the return +value of a function. For example, this function has an input lifetime: + +```{rust,ignore} +fn foo<'a>(bar: &'a str) +``` + +This one has an output lifetime: + +```{rust,ignore} +fn foo<'a>() -> &'a str +``` + +This one has both: + +```{rust,ignore} +fn foo<'a>(bar: &'a str) -> &'a str +``` + +Here are the three rules: + +* Each elided lifetime in a function's arguments becomes a distinct lifetime + parameter. + +* If there is exactly one input lifetime, elided or not, that lifetime is + assigned to all elided lifetimes in the return values of that function.. + +* If there are multiple input lifetimes, but one of them is `&self` or `&mut + self`, the lifetime of `self` is assigned to all elided output lifetimes. + +Otherwise, it is an error to elide an output lifetime. + +### Examples + +Here are some examples of functions with elided lifetimes, and the version of +what the elided lifetimes are expand to: + +```{rust,ignore} +fn print(s: &str); // elided +fn print<'a>(s: &'a str); // expanded + +fn debug(lvl: uint, s: &str); // elided +fn debug<'a>(lvl: uint, s: &'a str); // expanded + +// In the preceeding example, `lvl` doesn't need a lifetime because it's not a +// reference (`&`). Only things relating to references (such as a `struct` +// which contains a reference) need lifetimes. + +fn substr(s: &str, until: uint) -> &str; // elided +fn substr<'a>(s: &'a str, until: uint) -> &'a str; // expanded + +fn get_str() -> &str; // ILLEGAL, no inputs + +fn frob(s: &str, t: &str) -> &str; // ILLEGAL, two inputs + +fn get_mut(&mut self) -> &mut T; // elided +fn get_mut<'a>(&'a mut self) -> &'a mut T; // expanded + +fn args(&mut self, args: &[T]) -> &mut Command // elided +fn args<'a, 'b, T:ToCStr>(&'a mut self, args: &'b [T]) -> &'a mut Command // expanded + +fn new(buf: &mut [u8]) -> BufWriter; // elided +fn new<'a>(buf: &'a mut [u8]) -> BufWriter<'a> // expanded + +``` + # Related Resources Coming Soon. diff --git a/src/doc/guide-testing.md b/src/doc/guide-testing.md index 682c89fcc53fc..8d113bb931a09 100644 --- a/src/doc/guide-testing.md +++ b/src/doc/guide-testing.md @@ -503,6 +503,8 @@ Advice on writing benchmarks: * Make the code in the `iter` loop do something simple, to assist in pinpointing performance improvements (or regressions) +## Gotcha: optimizations + There's another tricky part to writing benchmarks: benchmarks compiled with optimizations activated can be dramatically changed by the optimizer so that the benchmark is no longer benchmarking what one expects. For example, the @@ -554,8 +556,12 @@ extern crate test; # fn main() { # struct X; impl X { fn iter(&self, _: || -> T) {} } let b = X; b.iter(|| { - test::black_box(range(0u, 1000).fold(0, |old, new| old ^ new)); -}); + let mut n = 1000_u32; + + test::black_box(&mut n); // pretend to modify `n` + + range(0, n).fold(0, |a, b| a ^ b) +}) # } ``` @@ -571,3 +577,6 @@ test bench_xor_1000_ints ... bench: 1 ns/iter (+/- 0) test result: ok. 0 passed; 0 failed; 0 ignored; 1 measured ``` + +However, the optimizer can still modify a testcase in an undesirable manner +even when using either of the above. diff --git a/src/doc/guide.md b/src/doc/guide.md index 2376a9cd2101c..596afb78c4803 100644 --- a/src/doc/guide.md +++ b/src/doc/guide.md @@ -355,7 +355,7 @@ Hello, world! Bam! We build our project with `cargo build`, and run it with `./target/hello_world`. This hasn't bought us a whole lot over our simple use of `rustc`, but think about the future: when our project has more than one -file, we would need to call `rustc` twice, and pass it a bunch of options to +file, we would need to call `rustc` more than once, and pass it a bunch of options to tell it to build everything together. With Cargo, as our project grows, we can just `cargo build` and it'll work the right way. @@ -977,7 +977,7 @@ fn main() { ``` Even though Rust functions can only return one value, a tuple _is_ one value, -that happens to be made up of two. You can also see in this example how you +that happens to be made up of more than one value. You can also see in this example how you can destructure a pattern returned by a function, as well. Tuples are a very simple data structure, and so are not often what you want. diff --git a/src/doc/reference.md b/src/doc/reference.md index d793028526052..0d3f9430bd677 100644 --- a/src/doc/reference.md +++ b/src/doc/reference.md @@ -3484,8 +3484,9 @@ fn main() { ``` -Patterns can also dereference pointers by using the `&`, `box` symbols, -as appropriate. For example, these two matches on `x: &int` are equivalent: +Patterns can also dereference pointers by using the `&`, `&mut` and `box` +symbols, as appropriate. For example, these two matches on `x: &int` are +equivalent: ``` # let x = &3i; diff --git a/src/libcollections/bit.rs b/src/libcollections/bit.rs index 5e7089bb7aca2..7f40422bf6669 100644 --- a/src/libcollections/bit.rs +++ b/src/libcollections/bit.rs @@ -2541,7 +2541,7 @@ mod bitv_bench { for _ in range(0u, 100) { bitv |= 1 << ((r.next_u32() as uint) % u32::BITS); } - black_box(&bitv) + black_box(&bitv); }); } @@ -2553,7 +2553,7 @@ mod bitv_bench { for _ in range(0u, 100) { bitv.set((r.next_u32() as uint) % BENCH_BITS, true); } - black_box(&bitv) + black_box(&bitv); }); } diff --git a/src/libcollections/dlist.rs b/src/libcollections/dlist.rs index ca8e75ac43c8d..504d41f2df0e0 100644 --- a/src/libcollections/dlist.rs +++ b/src/libcollections/dlist.rs @@ -1064,6 +1064,7 @@ mod tests { } #[allow(deprecated)] + #[test] fn test_append() { { let mut m = DList::new(); diff --git a/src/libcollections/slice.rs b/src/libcollections/slice.rs index 3602bfc10c307..a5e44dc1ddcff 100644 --- a/src/libcollections/slice.rs +++ b/src/libcollections/slice.rs @@ -120,7 +120,7 @@ pub use core::slice::{from_raw_buf, from_raw_mut_buf}; /// Allocating extension methods for slices. #[unstable = "needs associated types, may merge with other traits"] -pub trait SliceExt for Sized? { +pub trait SliceExt { type Item; /// Sorts the slice, in place, using `compare` to compare @@ -989,7 +989,7 @@ impl SliceExt for [T] { //////////////////////////////////////////////////////////////////////////////// #[unstable = "U should be an associated type"] /// An extension trait for concatenating slices -pub trait SliceConcatExt for Sized? { +pub trait SliceConcatExt { /// Flattens a slice of `T` into a single value `U`. #[stable] fn concat(&self) -> U; diff --git a/src/libcollections/str.rs b/src/libcollections/str.rs index ecf17820d2d8f..a467846cc08cf 100644 --- a/src/libcollections/str.rs +++ b/src/libcollections/str.rs @@ -59,7 +59,6 @@ use core::char::CharExt; use core::clone::Clone; use core::iter::AdditiveIterator; use core::iter::{range, Iterator, IteratorExt}; -use core::kinds::Sized; use core::ops; use core::option::Option::{self, Some, None}; use core::slice::AsSlice; @@ -401,7 +400,7 @@ Section: Trait implementations */ /// Any string that can be represented as a slice. -pub trait StrExt for Sized?: ops::Slice { +pub trait StrExt: ops::Slice { /// Escapes each char in `s` with `char::escape_default`. #[unstable = "return type may change to be an iterator"] fn escape_default(&self) -> String { @@ -2829,7 +2828,7 @@ mod bench { let s = "ศไทย中华Việt Nam; Mary had a little lamb, Little lamb"; b.iter(|| { - for ch in s.chars() { black_box(ch) } + for ch in s.chars() { black_box(ch); } }); } @@ -2857,7 +2856,7 @@ mod bench { let s = "ศไทย中华Việt Nam; Mary had a little lamb, Little lamb"; b.iter(|| { - for ch in s.chars().rev() { black_box(ch) } + for ch in s.chars().rev() { black_box(ch); } }); } diff --git a/src/libcollections/string.rs b/src/libcollections/string.rs index e7451331908ae..11e6c48cfdbad 100644 --- a/src/libcollections/string.rs +++ b/src/libcollections/string.rs @@ -320,30 +320,6 @@ impl String { } } - /// Creates a `String` from a null-terminated `*const u8` buffer. - /// - /// This function is unsafe because we dereference memory until we find the - /// NUL character, which is not guaranteed to be present. Additionally, the - /// slice is not checked to see whether it contains valid UTF-8 - #[unstable = "just renamed from `mod raw`"] - pub unsafe fn from_raw_buf(buf: *const u8) -> String { - String::from_str(str::from_c_str(buf as *const i8)) - } - - /// Creates a `String` from a `*const u8` buffer of the given length. - /// - /// This function is unsafe because it blindly assumes the validity of the - /// pointer `buf` for `len` bytes of memory. This function will copy the - /// memory from `buf` into a new allocation (owned by the returned - /// `String`). - /// - /// This function is also unsafe because it does not validate that the - /// buffer is valid UTF-8 encoded data. - #[unstable = "just renamed from `mod raw`"] - pub unsafe fn from_raw_buf_len(buf: *const u8, len: uint) -> String { - String::from_utf8_unchecked(Vec::from_raw_buf(buf, len)) - } - /// Converts a vector of bytes to a new `String` without checking if /// it contains valid UTF-8. This is unsafe because it assumes that /// the UTF-8-ness of the vector has already been validated. @@ -1126,24 +1102,6 @@ mod tests { String::from_str("\u{FFFD}𐒋\u{FFFD}")); } - #[test] - fn test_from_buf_len() { - unsafe { - let a = vec![65u8, 65, 65, 65, 65, 65, 65, 0]; - assert_eq!(String::from_raw_buf_len(a.as_ptr(), 3), String::from_str("AAA")); - } - } - - #[test] - fn test_from_buf() { - unsafe { - let a = vec![65, 65, 65, 65, 65, 65, 65, 0]; - let b = a.as_ptr(); - let c = String::from_raw_buf(b); - assert_eq!(c, String::from_str("AAAAAAA")); - } - } - #[test] fn test_push_bytes() { let mut s = String::from_str("ABC"); diff --git a/src/libcore/borrow.rs b/src/libcore/borrow.rs index 7e4d73d598d8d..6695cae6a1cf6 100644 --- a/src/libcore/borrow.rs +++ b/src/libcore/borrow.rs @@ -53,13 +53,13 @@ use option::Option; use self::Cow::*; /// A trait for borrowing data. -pub trait BorrowFrom for Sized? { +pub trait BorrowFrom { /// Immutably borrow from an owned value. fn borrow_from(owned: &Owned) -> &Self; } /// A trait for mutably borrowing data. -pub trait BorrowFromMut for Sized? : BorrowFrom { +pub trait BorrowFromMut : BorrowFrom { /// Mutably borrow from an owned value. fn borrow_from_mut(owned: &mut Owned) -> &mut Self; } @@ -103,7 +103,7 @@ impl<'a, T, Sized? B> IntoCow<'a, T, B> for Cow<'a, T, B> where B: ToOwned { } /// A generalization of Clone to borrowed data. -pub trait ToOwned for Sized?: BorrowFrom { +pub trait ToOwned: BorrowFrom { /// Create owned data from borrowed data, usually by copying. fn to_owned(&self) -> Owned; } diff --git a/src/libcore/cmp.rs b/src/libcore/cmp.rs index 13f9f5ccee916..c4ed0a75a4ec8 100644 --- a/src/libcore/cmp.rs +++ b/src/libcore/cmp.rs @@ -69,7 +69,7 @@ use option::Option::{self, Some, None}; /// only if `a != b`. #[lang="eq"] #[stable] -pub trait PartialEq for Sized? { +pub trait PartialEq { /// This method tests for `self` and `other` values to be equal, and is used by `==`. #[stable] fn eq(&self, other: &Rhs) -> bool; @@ -90,7 +90,7 @@ pub trait PartialEq for Sized? { /// - symmetric: `a == b` implies `b == a`; and /// - transitive: `a == b` and `b == c` implies `a == c`. #[stable] -pub trait Eq for Sized?: PartialEq { +pub trait Eq: PartialEq { // FIXME #13101: this method is used solely by #[deriving] to // assert that every component of a type implements #[deriving] // itself, the current deriving infrastructure means doing this @@ -164,7 +164,7 @@ impl Ordering { /// - transitive, `a < b` and `b < c` implies `a < c`. The same must hold for /// both `==` and `>`. #[stable] -pub trait Ord for Sized?: Eq + PartialOrd { +pub trait Ord: Eq + PartialOrd { /// This method returns an ordering between `self` and `other` values. /// /// By convention, `self.cmp(&other)` returns the ordering matching @@ -224,7 +224,7 @@ impl PartialOrd for Ordering { /// 5.11). #[lang="ord"] #[stable] -pub trait PartialOrd for Sized?: PartialEq { +pub trait PartialOrd: PartialEq { /// This method returns an ordering between `self` and `other` values /// if one exists. #[stable] diff --git a/src/libcore/fmt/mod.rs b/src/libcore/fmt/mod.rs index 102836f8d3024..bde2fb7525211 100644 --- a/src/libcore/fmt/mod.rs +++ b/src/libcore/fmt/mod.rs @@ -222,7 +222,7 @@ impl<'a> Show for Arguments<'a> { /// to this trait. There is not an explicit way of selecting this trait to be /// used for formatting, it is only if no other format is specified. #[unstable = "I/O and core have yet to be reconciled"] -pub trait Show for Sized? { +pub trait Show { /// Formats the value using the given formatter. fn fmt(&self, &mut Formatter) -> Result; } @@ -230,49 +230,49 @@ pub trait Show for Sized? { /// Format trait for the `o` character #[unstable = "I/O and core have yet to be reconciled"] -pub trait Octal for Sized? { +pub trait Octal { /// Formats the value using the given formatter. fn fmt(&self, &mut Formatter) -> Result; } /// Format trait for the `b` character #[unstable = "I/O and core have yet to be reconciled"] -pub trait Binary for Sized? { +pub trait Binary { /// Formats the value using the given formatter. fn fmt(&self, &mut Formatter) -> Result; } /// Format trait for the `x` character #[unstable = "I/O and core have yet to be reconciled"] -pub trait LowerHex for Sized? { +pub trait LowerHex { /// Formats the value using the given formatter. fn fmt(&self, &mut Formatter) -> Result; } /// Format trait for the `X` character #[unstable = "I/O and core have yet to be reconciled"] -pub trait UpperHex for Sized? { +pub trait UpperHex { /// Formats the value using the given formatter. fn fmt(&self, &mut Formatter) -> Result; } /// Format trait for the `p` character #[unstable = "I/O and core have yet to be reconciled"] -pub trait Pointer for Sized? { +pub trait Pointer { /// Formats the value using the given formatter. fn fmt(&self, &mut Formatter) -> Result; } /// Format trait for the `e` character #[unstable = "I/O and core have yet to be reconciled"] -pub trait LowerExp for Sized? { +pub trait LowerExp { /// Formats the value using the given formatter. fn fmt(&self, &mut Formatter) -> Result; } /// Format trait for the `E` character #[unstable = "I/O and core have yet to be reconciled"] -pub trait UpperExp for Sized? { +pub trait UpperExp { /// Formats the value using the given formatter. fn fmt(&self, &mut Formatter) -> Result; } diff --git a/src/libcore/hash/mod.rs b/src/libcore/hash/mod.rs index b0a5ec9fe12ed..d929e12a073c7 100644 --- a/src/libcore/hash/mod.rs +++ b/src/libcore/hash/mod.rs @@ -76,7 +76,7 @@ pub mod sip; /// A hashable type. The `S` type parameter is an abstract hash state that is /// used by the `Hash` to compute the hash. It defaults to /// `std::hash::sip::SipState`. -pub trait Hash for Sized? { +pub trait Hash { /// Computes the hash of a value. fn hash(&self, state: &mut S); } diff --git a/src/libcore/kinds.rs b/src/libcore/kinds.rs index e50aaef5f09f3..4769c783e5829 100644 --- a/src/libcore/kinds.rs +++ b/src/libcore/kinds.rs @@ -19,19 +19,19 @@ /// Types able to be transferred across task boundaries. #[lang="send"] -pub unsafe trait Send for Sized? : 'static { +pub unsafe trait Send : 'static { // empty. } /// Types with a constant size known at compile-time. #[lang="sized"] -pub trait Sized for Sized? { +pub trait Sized { // Empty. } /// Types that can be copied by simply copying bits (i.e. `memcpy`). #[lang="copy"] -pub trait Copy for Sized? { +pub trait Copy { // Empty. } @@ -81,7 +81,7 @@ pub trait Copy for Sized? { /// reference; not doing this is undefined behaviour (for example, /// `transmute`-ing from `&T` to `&mut T` is illegal). #[lang="sync"] -pub unsafe trait Sync for Sized? { +pub unsafe trait Sync { // Empty } diff --git a/src/libcore/ops.rs b/src/libcore/ops.rs index c9b71092f9072..ef9f7f25c6a66 100644 --- a/src/libcore/ops.rs +++ b/src/libcore/ops.rs @@ -721,7 +721,7 @@ shr_impl! { uint u8 u16 u32 u64 int i8 i16 i32 i64 } #[cfg(stage0)] #[allow(missing_docs)] #[lang="index"] -pub trait Index for Sized? { +pub trait Index { /// The method for the indexing (`Foo[Bar]`) operation fn index<'a>(&'a self, index: &Index) -> &'a Result; } @@ -757,7 +757,7 @@ pub trait Index for Sized? { /// ``` #[cfg(not(stage0))] // NOTE(stage0) remove cfg after a snapshot #[lang="index"] -pub trait Index for Sized? { +pub trait Index { type Sized? Output; /// The method for the indexing (`Foo[Bar]`) operation @@ -768,7 +768,7 @@ pub trait Index for Sized? { #[cfg(stage0)] #[allow(missing_docs)] #[lang="index_mut"] -pub trait IndexMut for Sized? { +pub trait IndexMut { /// The method for the indexing (`Foo[Bar]`) operation fn index_mut<'a>(&'a mut self, index: &Index) -> &'a mut Result; } @@ -804,7 +804,7 @@ pub trait IndexMut for Sized? { /// ``` #[cfg(not(stage0))] // NOTE(stage0) remove cfg after a snapshot #[lang="index_mut"] -pub trait IndexMut for Sized? { +pub trait IndexMut { type Sized? Output; /// The method for the indexing (`Foo[Bar]`) operation @@ -849,7 +849,7 @@ pub trait IndexMut for Sized? { /// } /// ``` #[lang="slice"] -pub trait Slice for Sized? { +pub trait Slice { /// The method for the slicing operation foo[] fn as_slice_<'a>(&'a self) -> &'a Result; /// The method for the slicing operation foo[from..] @@ -898,7 +898,7 @@ pub trait Slice for Sized? { /// } /// ``` #[lang="slice_mut"] -pub trait SliceMut for Sized? { +pub trait SliceMut { /// The method for the slicing operation foo[] fn as_mut_slice_<'a>(&'a mut self) -> &'a mut Result; /// The method for the slicing operation foo[from..] @@ -1025,7 +1025,7 @@ pub struct RangeTo { /// } /// ``` #[lang="deref"] -pub trait Deref for Sized? { +pub trait Deref { type Sized? Target; /// The method called to dereference a value @@ -1082,7 +1082,7 @@ impl<'a, Sized? T> Deref for &'a mut T { /// } /// ``` #[lang="deref_mut"] -pub trait DerefMut for Sized? : Deref { +pub trait DerefMut : Deref { /// The method called to mutably dereference a value fn deref_mut<'a>(&'a mut self) -> &'a mut ::Target; } @@ -1093,14 +1093,14 @@ impl<'a, Sized? T> DerefMut for &'a mut T { /// A version of the call operator that takes an immutable receiver. #[lang="fn"] -pub trait Fn for Sized? { +pub trait Fn { /// This is called when the call operator is used. extern "rust-call" fn call(&self, args: Args) -> Result; } /// A version of the call operator that takes a mutable receiver. #[lang="fn_mut"] -pub trait FnMut for Sized? { +pub trait FnMut { /// This is called when the call operator is used. extern "rust-call" fn call_mut(&mut self, args: Args) -> Result; } diff --git a/src/libcore/raw.rs b/src/libcore/raw.rs index 3bef1d1536377..5ef6f6b2623aa 100644 --- a/src/libcore/raw.rs +++ b/src/libcore/raw.rs @@ -20,7 +20,6 @@ use kinds::Copy; use mem; -use kinds::Sized; /// The representation of a Rust slice #[repr(C)] @@ -52,7 +51,7 @@ pub struct TraitObject { /// This trait is meant to map equivalences between raw structs and their /// corresponding rust values. -pub trait Repr for Sized? { +pub trait Repr { /// This function "unwraps" a rust value (without consuming it) into its raw /// struct representation. This can be used to read/write different values /// for the struct. This is a safe method because by default it does not diff --git a/src/libcore/slice.rs b/src/libcore/slice.rs index f17a775cf4240..1fde906062ec4 100644 --- a/src/libcore/slice.rs +++ b/src/libcore/slice.rs @@ -64,7 +64,7 @@ use raw::Slice as RawSlice; /// Extension methods for slices. #[allow(missing_docs)] // docs in libcollections -pub trait SliceExt for Sized? { +pub trait SliceExt { type Item; fn slice<'a>(&'a self, start: uint, end: uint) -> &'a [Self::Item]; @@ -636,7 +636,7 @@ impl ops::SliceMut for [T] { /// Data that is viewable as a slice. #[experimental = "will be replaced by slice syntax"] -pub trait AsSlice for Sized? { +pub trait AsSlice { /// Work with `self` as a slice. fn as_slice<'a>(&'a self) -> &'a [T]; } @@ -1372,12 +1372,11 @@ pub unsafe fn from_raw_mut_buf<'a, T>(p: &'a *mut T, len: uint) -> &'a mut [T] { /// Operations on `[u8]`. #[experimental = "needs review"] pub mod bytes { - use kinds::Sized; use ptr; use slice::SliceExt; /// A trait for operations on mutable `[u8]`s. - pub trait MutableByteVector for Sized? { + pub trait MutableByteVector { /// Sets all bytes of the receiver to the given value. fn set_memory(&mut self, value: u8); } @@ -1461,7 +1460,7 @@ impl PartialOrd for [T] { /// Extension methods for slices containing integers. #[experimental] -pub trait IntSliceExt for Sized? { +pub trait IntSliceExt { /// Converts the slice to an immutable slice of unsigned integers with the same width. fn as_unsigned<'a>(&'a self) -> &'a [U]; /// Converts the slice to an immutable slice of signed integers with the same width. diff --git a/src/libcore/str/mod.rs b/src/libcore/str/mod.rs index d069744f8da54..9865395e4a0ac 100644 --- a/src/libcore/str/mod.rs +++ b/src/libcore/str/mod.rs @@ -190,7 +190,7 @@ pub unsafe fn from_utf8_unchecked<'a>(v: &'a [u8]) -> &'a str { /// # Panics /// /// This function will panic if the string pointed to by `s` is not valid UTF-8. -#[unstable = "may change location based on the outcome of the c_str module"] +#[deprecated = "use std::ffi::c_str_to_bytes + str::from_utf8"] pub unsafe fn from_c_str(s: *const i8) -> &'static str { let s = s as *const u8; let mut len = 0u; @@ -230,7 +230,7 @@ impl CharEq for F where F: FnMut(char) -> bool { impl<'a> CharEq for &'a [char] { #[inline] fn matches(&mut self, c: char) -> bool { - self.iter().any(|&mut m| m.matches(c)) + self.iter().any(|&m| { let mut m = m; m.matches(c) }) } #[inline] @@ -1130,7 +1130,7 @@ pub mod traits { #[unstable = "Instead of taking this bound generically, this trait will be \ replaced with one of slicing syntax, deref coercions, or \ a more generic conversion trait"] -pub trait Str for Sized? { +pub trait Str { /// Work with `self` as a slice. fn as_slice<'a>(&'a self) -> &'a str; } @@ -1171,7 +1171,7 @@ delegate_iter!{pattern forward &'a str in RSplitN<'a, P>} /// Methods for string slices #[allow(missing_docs)] -pub trait StrExt for Sized? { +pub trait StrExt { // NB there are no docs here are they're all located on the StrExt trait in // libcollections, not here. diff --git a/src/libflate/lib.rs b/src/libflate/lib.rs index aa1550ae5b874..a0c9da3ae6d49 100644 --- a/src/libflate/lib.rs +++ b/src/libflate/lib.rs @@ -21,15 +21,34 @@ #![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", html_favicon_url = "http://www.rust-lang.org/favicon.ico", html_root_url = "http://doc.rust-lang.org/nightly/")] -#![feature(phase, unboxed_closures)] +#![feature(phase, unboxed_closures, associated_types)] #[cfg(test)] #[phase(plugin, link)] extern crate log; extern crate libc; use libc::{c_void, size_t, c_int}; -use std::c_vec::CVec; +use std::ops::Deref; use std::ptr::Unique; +use std::slice; + +pub struct Bytes { + ptr: Unique, + len: uint, +} + +impl Deref for Bytes { + type Target = [u8]; + fn deref(&self) -> &[u8] { + unsafe { slice::from_raw_mut_buf(&self.ptr.0, self.len) } + } +} + +impl Drop for Bytes { + fn drop(&mut self) { + unsafe { libc::free(self.ptr.0 as *mut _); } + } +} #[link(name = "miniz", kind = "static")] extern { @@ -52,7 +71,7 @@ static LZ_NORM : c_int = 0x80; // LZ with 128 probes, "normal" static TINFL_FLAG_PARSE_ZLIB_HEADER : c_int = 0x1; // parse zlib header and adler32 checksum static TDEFL_WRITE_ZLIB_HEADER : c_int = 0x01000; // write zlib header and adler32 checksum -fn deflate_bytes_internal(bytes: &[u8], flags: c_int) -> Option> { +fn deflate_bytes_internal(bytes: &[u8], flags: c_int) -> Option { unsafe { let mut outsz : size_t = 0; let res = tdefl_compress_mem_to_heap(bytes.as_ptr() as *const _, @@ -60,8 +79,8 @@ fn deflate_bytes_internal(bytes: &[u8], flags: c_int) -> Option> { &mut outsz, flags); if !res.is_null() { - let res = Unique(res); - Some(CVec::new_with_dtor(res.0 as *mut u8, outsz as uint, move|:| libc::free(res.0))) + let res = Unique(res as *mut u8); + Some(Bytes { ptr: res, len: outsz as uint }) } else { None } @@ -69,16 +88,16 @@ fn deflate_bytes_internal(bytes: &[u8], flags: c_int) -> Option> { } /// Compress a buffer, without writing any sort of header on the output. -pub fn deflate_bytes(bytes: &[u8]) -> Option> { +pub fn deflate_bytes(bytes: &[u8]) -> Option { deflate_bytes_internal(bytes, LZ_NORM) } /// Compress a buffer, using a header that zlib can understand. -pub fn deflate_bytes_zlib(bytes: &[u8]) -> Option> { +pub fn deflate_bytes_zlib(bytes: &[u8]) -> Option { deflate_bytes_internal(bytes, LZ_NORM | TDEFL_WRITE_ZLIB_HEADER) } -fn inflate_bytes_internal(bytes: &[u8], flags: c_int) -> Option> { +fn inflate_bytes_internal(bytes: &[u8], flags: c_int) -> Option { unsafe { let mut outsz : size_t = 0; let res = tinfl_decompress_mem_to_heap(bytes.as_ptr() as *const _, @@ -86,8 +105,8 @@ fn inflate_bytes_internal(bytes: &[u8], flags: c_int) -> Option> { &mut outsz, flags); if !res.is_null() { - let res = Unique(res); - Some(CVec::new_with_dtor(res.0 as *mut u8, outsz as uint, move|:| libc::free(res.0))) + let res = Unique(res as *mut u8); + Some(Bytes { ptr: res, len: outsz as uint }) } else { None } @@ -95,12 +114,12 @@ fn inflate_bytes_internal(bytes: &[u8], flags: c_int) -> Option> { } /// Decompress a buffer, without parsing any sort of header on the input. -pub fn inflate_bytes(bytes: &[u8]) -> Option> { +pub fn inflate_bytes(bytes: &[u8]) -> Option { inflate_bytes_internal(bytes, 0) } /// Decompress a buffer that starts with a zlib header. -pub fn inflate_bytes_zlib(bytes: &[u8]) -> Option> { +pub fn inflate_bytes_zlib(bytes: &[u8]) -> Option { inflate_bytes_internal(bytes, TINFL_FLAG_PARSE_ZLIB_HEADER) } diff --git a/src/libgraphviz/lib.rs b/src/libgraphviz/lib.rs index e3bcf70e8c82f..64cc490f4b163 100644 --- a/src/libgraphviz/lib.rs +++ b/src/libgraphviz/lib.rs @@ -587,7 +587,7 @@ pub fn render_opts<'a, N:Clone+'a, E:Clone+'a, G:Labeller<'a,N,E>+GraphWalk<'a,N mod tests { use self::NodeLabels::*; use super::{Id, Labeller, Nodes, Edges, GraphWalk, render}; - use super::LabelText::{mod, LabelStr, EscStr}; + use super::LabelText::{self, LabelStr, EscStr}; use std::io::IoResult; use std::borrow::IntoCow; use std::iter::repeat; diff --git a/src/librand/lib.rs b/src/librand/lib.rs index 0f8dbc78cde32..18f508e816f2b 100644 --- a/src/librand/lib.rs +++ b/src/librand/lib.rs @@ -243,7 +243,7 @@ pub trait Rng : Sized { /// println!("{}", rng.gen_weighted_bool(3)); /// ``` fn gen_weighted_bool(&mut self, n: uint) -> bool { - n == 0 || self.gen_range(0, n) == 0 + n <= 1 || self.gen_range(0, n) == 0 } /// Return an iterator of random characters from the set A-Z,a-z,0-9. diff --git a/src/librbml/lib.rs b/src/librbml/lib.rs index f7d5bfcd117d6..3acedac111d60 100644 --- a/src/librbml/lib.rs +++ b/src/librbml/lib.rs @@ -25,7 +25,7 @@ html_playground_url = "http://play.rust-lang.org/")] #![allow(unknown_features)] #![feature(macro_rules, phase, slicing_syntax, globs)] -#![feature(unboxed_closures)] +#![feature(unboxed_closures, associated_types)] #![allow(missing_docs)] extern crate serialize; @@ -417,6 +417,7 @@ pub mod reader { } } + #[cfg(stage0)] impl<'doc> serialize::Decoder for Decoder<'doc> { fn read_nil(&mut self) -> DecodeResult<()> { Ok(()) } @@ -671,6 +672,263 @@ pub mod reader { ApplicationError(err.to_string()) } } + + #[cfg(not(stage0))] + impl<'doc> serialize::Decoder for Decoder<'doc> { + type Error = Error; + fn read_nil(&mut self) -> DecodeResult<()> { Ok(()) } + + fn read_u64(&mut self) -> DecodeResult { Ok(doc_as_u64(try!(self.next_doc(EsU64)))) } + fn read_u32(&mut self) -> DecodeResult { Ok(doc_as_u32(try!(self.next_doc(EsU32)))) } + fn read_u16(&mut self) -> DecodeResult { Ok(doc_as_u16(try!(self.next_doc(EsU16)))) } + fn read_u8 (&mut self) -> DecodeResult { Ok(doc_as_u8 (try!(self.next_doc(EsU8 )))) } + fn read_uint(&mut self) -> DecodeResult { + let v = doc_as_u64(try!(self.next_doc(EsUint))); + if v > (::std::uint::MAX as u64) { + Err(IntTooBig(v as uint)) + } else { + Ok(v as uint) + } + } + + fn read_i64(&mut self) -> DecodeResult { + Ok(doc_as_u64(try!(self.next_doc(EsI64))) as i64) + } + fn read_i32(&mut self) -> DecodeResult { + Ok(doc_as_u32(try!(self.next_doc(EsI32))) as i32) + } + fn read_i16(&mut self) -> DecodeResult { + Ok(doc_as_u16(try!(self.next_doc(EsI16))) as i16) + } + fn read_i8 (&mut self) -> DecodeResult { + Ok(doc_as_u8(try!(self.next_doc(EsI8 ))) as i8) + } + fn read_int(&mut self) -> DecodeResult { + let v = doc_as_u64(try!(self.next_doc(EsInt))) as i64; + if v > (int::MAX as i64) || v < (int::MIN as i64) { + debug!("FIXME \\#6122: Removing this makes this function miscompile"); + Err(IntTooBig(v as uint)) + } else { + Ok(v as int) + } + } + + fn read_bool(&mut self) -> DecodeResult { + Ok(doc_as_u8(try!(self.next_doc(EsBool))) != 0) + } + + fn read_f64(&mut self) -> DecodeResult { + let bits = doc_as_u64(try!(self.next_doc(EsF64))); + Ok(unsafe { transmute(bits) }) + } + fn read_f32(&mut self) -> DecodeResult { + let bits = doc_as_u32(try!(self.next_doc(EsF32))); + Ok(unsafe { transmute(bits) }) + } + fn read_char(&mut self) -> DecodeResult { + Ok(char::from_u32(doc_as_u32(try!(self.next_doc(EsChar)))).unwrap()) + } + fn read_str(&mut self) -> DecodeResult { + Ok(try!(self.next_doc(EsStr)).as_str()) + } + + // Compound types: + fn read_enum(&mut self, name: &str, f: F) -> DecodeResult where + F: FnOnce(&mut Decoder<'doc>) -> DecodeResult, + { + debug!("read_enum({})", name); + try!(self._check_label(name)); + + let doc = try!(self.next_doc(EsEnum)); + + let (old_parent, old_pos) = (self.parent, self.pos); + self.parent = doc; + self.pos = self.parent.start; + + let result = try!(f(self)); + + self.parent = old_parent; + self.pos = old_pos; + Ok(result) + } + + fn read_enum_variant(&mut self, _: &[&str], + mut f: F) -> DecodeResult + where F: FnMut(&mut Decoder<'doc>, uint) -> DecodeResult, + { + debug!("read_enum_variant()"); + let idx = try!(self._next_uint(EsEnumVid)); + debug!(" idx={}", idx); + + let doc = try!(self.next_doc(EsEnumBody)); + + let (old_parent, old_pos) = (self.parent, self.pos); + self.parent = doc; + self.pos = self.parent.start; + + let result = try!(f(self, idx)); + + self.parent = old_parent; + self.pos = old_pos; + Ok(result) + } + + fn read_enum_variant_arg(&mut self, idx: uint, f: F) -> DecodeResult where + F: FnOnce(&mut Decoder<'doc>) -> DecodeResult, + { + debug!("read_enum_variant_arg(idx={})", idx); + f(self) + } + + fn read_enum_struct_variant(&mut self, _: &[&str], + mut f: F) -> DecodeResult + where F: FnMut(&mut Decoder<'doc>, uint) -> DecodeResult, + { + debug!("read_enum_struct_variant()"); + let idx = try!(self._next_uint(EsEnumVid)); + debug!(" idx={}", idx); + + let doc = try!(self.next_doc(EsEnumBody)); + + let (old_parent, old_pos) = (self.parent, self.pos); + self.parent = doc; + self.pos = self.parent.start; + + let result = try!(f(self, idx)); + + self.parent = old_parent; + self.pos = old_pos; + Ok(result) + } + + fn read_enum_struct_variant_field(&mut self, + name: &str, + idx: uint, + f: F) + -> DecodeResult where + F: FnOnce(&mut Decoder<'doc>) -> DecodeResult, + { + debug!("read_enum_struct_variant_arg(name={}, idx={})", name, idx); + f(self) + } + + fn read_struct(&mut self, name: &str, _: uint, f: F) -> DecodeResult where + F: FnOnce(&mut Decoder<'doc>) -> DecodeResult, + { + debug!("read_struct(name={})", name); + f(self) + } + + fn read_struct_field(&mut self, name: &str, idx: uint, f: F) -> DecodeResult where + F: FnOnce(&mut Decoder<'doc>) -> DecodeResult, + { + debug!("read_struct_field(name={}, idx={})", name, idx); + try!(self._check_label(name)); + f(self) + } + + fn read_tuple(&mut self, tuple_len: uint, f: F) -> DecodeResult where + F: FnOnce(&mut Decoder<'doc>) -> DecodeResult, + { + debug!("read_tuple()"); + self.read_seq(move |d, len| { + if len == tuple_len { + f(d) + } else { + Err(Expected(format!("Expected tuple of length `{}`, \ + found tuple of length `{}`", tuple_len, len))) + } + }) + } + + fn read_tuple_arg(&mut self, idx: uint, f: F) -> DecodeResult where + F: FnOnce(&mut Decoder<'doc>) -> DecodeResult, + { + debug!("read_tuple_arg(idx={})", idx); + self.read_seq_elt(idx, f) + } + + fn read_tuple_struct(&mut self, name: &str, len: uint, f: F) -> DecodeResult where + F: FnOnce(&mut Decoder<'doc>) -> DecodeResult, + { + debug!("read_tuple_struct(name={})", name); + self.read_tuple(len, f) + } + + fn read_tuple_struct_arg(&mut self, + idx: uint, + f: F) + -> DecodeResult where + F: FnOnce(&mut Decoder<'doc>) -> DecodeResult, + { + debug!("read_tuple_struct_arg(idx={})", idx); + self.read_tuple_arg(idx, f) + } + + fn read_option(&mut self, mut f: F) -> DecodeResult where + F: FnMut(&mut Decoder<'doc>, bool) -> DecodeResult, + { + debug!("read_option()"); + self.read_enum("Option", move |this| { + this.read_enum_variant(&["None", "Some"], move |this, idx| { + match idx { + 0 => f(this, false), + 1 => f(this, true), + _ => { + Err(Expected(format!("Expected None or Some"))) + } + } + }) + }) + } + + fn read_seq(&mut self, f: F) -> DecodeResult where + F: FnOnce(&mut Decoder<'doc>, uint) -> DecodeResult, + { + debug!("read_seq()"); + self.push_doc(EsVec, move |d| { + let len = try!(d._next_uint(EsVecLen)); + debug!(" len={}", len); + f(d, len) + }) + } + + fn read_seq_elt(&mut self, idx: uint, f: F) -> DecodeResult where + F: FnOnce(&mut Decoder<'doc>) -> DecodeResult, + { + debug!("read_seq_elt(idx={})", idx); + self.push_doc(EsVecElt, f) + } + + fn read_map(&mut self, f: F) -> DecodeResult where + F: FnOnce(&mut Decoder<'doc>, uint) -> DecodeResult, + { + debug!("read_map()"); + self.push_doc(EsMap, move |d| { + let len = try!(d._next_uint(EsMapLen)); + debug!(" len={}", len); + f(d, len) + }) + } + + fn read_map_elt_key(&mut self, idx: uint, f: F) -> DecodeResult where + F: FnOnce(&mut Decoder<'doc>) -> DecodeResult, + { + debug!("read_map_elt_key(idx={})", idx); + self.push_doc(EsMapKey, f) + } + + fn read_map_elt_val(&mut self, idx: uint, f: F) -> DecodeResult where + F: FnOnce(&mut Decoder<'doc>) -> DecodeResult, + { + debug!("read_map_elt_val(idx={})", idx); + self.push_doc(EsMapVal, f) + } + + fn error(&mut self, err: &str) -> Error { + ApplicationError(err.to_string()) + } + } } pub mod writer { @@ -872,7 +1130,212 @@ pub mod writer { } } + #[cfg(stage0)] impl<'a, W: Writer + Seek> serialize::Encoder for Encoder<'a, W> { + + fn emit_nil(&mut self) -> EncodeResult { + Ok(()) + } + + fn emit_uint(&mut self, v: uint) -> EncodeResult { + self.wr_tagged_u64(EsUint as uint, v as u64) + } + fn emit_u64(&mut self, v: u64) -> EncodeResult { + self.wr_tagged_u64(EsU64 as uint, v) + } + fn emit_u32(&mut self, v: u32) -> EncodeResult { + self.wr_tagged_u32(EsU32 as uint, v) + } + fn emit_u16(&mut self, v: u16) -> EncodeResult { + self.wr_tagged_u16(EsU16 as uint, v) + } + fn emit_u8(&mut self, v: u8) -> EncodeResult { + self.wr_tagged_u8(EsU8 as uint, v) + } + + fn emit_int(&mut self, v: int) -> EncodeResult { + self.wr_tagged_i64(EsInt as uint, v as i64) + } + fn emit_i64(&mut self, v: i64) -> EncodeResult { + self.wr_tagged_i64(EsI64 as uint, v) + } + fn emit_i32(&mut self, v: i32) -> EncodeResult { + self.wr_tagged_i32(EsI32 as uint, v) + } + fn emit_i16(&mut self, v: i16) -> EncodeResult { + self.wr_tagged_i16(EsI16 as uint, v) + } + fn emit_i8(&mut self, v: i8) -> EncodeResult { + self.wr_tagged_i8(EsI8 as uint, v) + } + + fn emit_bool(&mut self, v: bool) -> EncodeResult { + self.wr_tagged_u8(EsBool as uint, v as u8) + } + + fn emit_f64(&mut self, v: f64) -> EncodeResult { + let bits = unsafe { mem::transmute(v) }; + self.wr_tagged_u64(EsF64 as uint, bits) + } + fn emit_f32(&mut self, v: f32) -> EncodeResult { + let bits = unsafe { mem::transmute(v) }; + self.wr_tagged_u32(EsF32 as uint, bits) + } + fn emit_char(&mut self, v: char) -> EncodeResult { + self.wr_tagged_u32(EsChar as uint, v as u32) + } + + fn emit_str(&mut self, v: &str) -> EncodeResult { + self.wr_tagged_str(EsStr as uint, v) + } + + fn emit_enum(&mut self, name: &str, f: F) -> EncodeResult where + F: FnOnce(&mut Encoder<'a, W>) -> EncodeResult, + { + try!(self._emit_label(name)); + try!(self.start_tag(EsEnum as uint)); + try!(f(self)); + self.end_tag() + } + + fn emit_enum_variant(&mut self, + _: &str, + v_id: uint, + _: uint, + f: F) -> EncodeResult where + F: FnOnce(&mut Encoder<'a, W>) -> EncodeResult, + { + try!(self._emit_tagged_uint(EsEnumVid, v_id)); + try!(self.start_tag(EsEnumBody as uint)); + try!(f(self)); + self.end_tag() + } + + fn emit_enum_variant_arg(&mut self, _: uint, f: F) -> EncodeResult where + F: FnOnce(&mut Encoder<'a, W>) -> EncodeResult, + { + f(self) + } + + fn emit_enum_struct_variant(&mut self, + v_name: &str, + v_id: uint, + cnt: uint, + f: F) -> EncodeResult where + F: FnOnce(&mut Encoder<'a, W>) -> EncodeResult, + { + self.emit_enum_variant(v_name, v_id, cnt, f) + } + + fn emit_enum_struct_variant_field(&mut self, + _: &str, + idx: uint, + f: F) -> EncodeResult where + F: FnOnce(&mut Encoder<'a, W>) -> EncodeResult, + { + self.emit_enum_variant_arg(idx, f) + } + + fn emit_struct(&mut self, _: &str, _len: uint, f: F) -> EncodeResult where + F: FnOnce(&mut Encoder<'a, W>) -> EncodeResult, + { + f(self) + } + + fn emit_struct_field(&mut self, name: &str, _: uint, f: F) -> EncodeResult where + F: FnOnce(&mut Encoder<'a, W>) -> EncodeResult, + { + try!(self._emit_label(name)); + f(self) + } + + fn emit_tuple(&mut self, len: uint, f: F) -> EncodeResult where + F: FnOnce(&mut Encoder<'a, W>) -> EncodeResult, + { + self.emit_seq(len, f) + } + fn emit_tuple_arg(&mut self, idx: uint, f: F) -> EncodeResult where + F: FnOnce(&mut Encoder<'a, W>) -> EncodeResult, + { + self.emit_seq_elt(idx, f) + } + + fn emit_tuple_struct(&mut self, _: &str, len: uint, f: F) -> EncodeResult where + F: FnOnce(&mut Encoder<'a, W>) -> EncodeResult, + { + self.emit_seq(len, f) + } + fn emit_tuple_struct_arg(&mut self, idx: uint, f: F) -> EncodeResult where + F: FnOnce(&mut Encoder<'a, W>) -> EncodeResult, + { + self.emit_seq_elt(idx, f) + } + + fn emit_option(&mut self, f: F) -> EncodeResult where + F: FnOnce(&mut Encoder<'a, W>) -> EncodeResult, + { + self.emit_enum("Option", f) + } + fn emit_option_none(&mut self) -> EncodeResult { + self.emit_enum_variant("None", 0, 0, |_| Ok(())) + } + fn emit_option_some(&mut self, f: F) -> EncodeResult where + F: FnOnce(&mut Encoder<'a, W>) -> EncodeResult, + { + + self.emit_enum_variant("Some", 1, 1, f) + } + + fn emit_seq(&mut self, len: uint, f: F) -> EncodeResult where + F: FnOnce(&mut Encoder<'a, W>) -> EncodeResult, + { + + try!(self.start_tag(EsVec as uint)); + try!(self._emit_tagged_uint(EsVecLen, len)); + try!(f(self)); + self.end_tag() + } + + fn emit_seq_elt(&mut self, _idx: uint, f: F) -> EncodeResult where + F: FnOnce(&mut Encoder<'a, W>) -> EncodeResult, + { + + try!(self.start_tag(EsVecElt as uint)); + try!(f(self)); + self.end_tag() + } + + fn emit_map(&mut self, len: uint, f: F) -> EncodeResult where + F: FnOnce(&mut Encoder<'a, W>) -> EncodeResult, + { + + try!(self.start_tag(EsMap as uint)); + try!(self._emit_tagged_uint(EsMapLen, len)); + try!(f(self)); + self.end_tag() + } + + fn emit_map_elt_key(&mut self, _idx: uint, mut f: F) -> EncodeResult where + F: FnMut(&mut Encoder<'a, W>) -> EncodeResult, + { + + try!(self.start_tag(EsMapKey as uint)); + try!(f(self)); + self.end_tag() + } + + fn emit_map_elt_val(&mut self, _idx: uint, f: F) -> EncodeResult where + F: FnOnce(&mut Encoder<'a, W>) -> EncodeResult, + { + try!(self.start_tag(EsMapVal as uint)); + try!(f(self)); + self.end_tag() + } + } + #[cfg(not(stage0))] + impl<'a, W: Writer + Seek> serialize::Encoder for Encoder<'a, W> { + type Error = io::IoError; + fn emit_nil(&mut self) -> EncodeResult { Ok(()) } diff --git a/src/librustc/lint/builtin.rs b/src/librustc/lint/builtin.rs index 269aa8fda1326..7025f6f079f10 100644 --- a/src/librustc/lint/builtin.rs +++ b/src/librustc/lint/builtin.rs @@ -550,20 +550,20 @@ impl LintPass for BoxPointers { } declare_lint! { - RAW_POINTER_DERIVING, + RAW_POINTER_DERIVE, Warn, "uses of #[derive] with raw pointers are rarely correct" } -struct RawPtrDerivingVisitor<'a, 'tcx: 'a> { +struct RawPtrDeriveVisitor<'a, 'tcx: 'a> { cx: &'a Context<'a, 'tcx> } -impl<'a, 'tcx, 'v> Visitor<'v> for RawPtrDerivingVisitor<'a, 'tcx> { +impl<'a, 'tcx, 'v> Visitor<'v> for RawPtrDeriveVisitor<'a, 'tcx> { fn visit_ty(&mut self, ty: &ast::Ty) { static MSG: &'static str = "use of `#[derive]` with a raw pointer"; if let ast::TyPtr(..) = ty.node { - self.cx.span_lint(RAW_POINTER_DERIVING, ty.span, MSG); + self.cx.span_lint(RAW_POINTER_DERIVE, ty.span, MSG); } visit::walk_ty(self, ty); } @@ -572,21 +572,21 @@ impl<'a, 'tcx, 'v> Visitor<'v> for RawPtrDerivingVisitor<'a, 'tcx> { fn visit_block(&mut self, _: &ast::Block) {} } -pub struct RawPointerDeriving { +pub struct RawPointerDerive { checked_raw_pointers: NodeSet, } -impl RawPointerDeriving { - pub fn new() -> RawPointerDeriving { - RawPointerDeriving { +impl RawPointerDerive { + pub fn new() -> RawPointerDerive { + RawPointerDerive { checked_raw_pointers: NodeSet::new(), } } } -impl LintPass for RawPointerDeriving { +impl LintPass for RawPointerDerive { fn get_lints(&self) -> LintArray { - lint_array!(RAW_POINTER_DERIVING) + lint_array!(RAW_POINTER_DERIVE) } fn check_item(&mut self, cx: &Context, item: &ast::Item) { @@ -611,7 +611,7 @@ impl LintPass for RawPointerDeriving { if !self.checked_raw_pointers.insert(item.id) { return } match item.node { ast::ItemStruct(..) | ast::ItemEnum(..) => { - let mut visitor = RawPtrDerivingVisitor { cx: cx }; + let mut visitor = RawPtrDeriveVisitor { cx: cx }; visit::walk_item(&mut visitor, &*item); } _ => {} diff --git a/src/librustc/lint/context.rs b/src/librustc/lint/context.rs index 69e5b4889c288..521e5e305bc77 100644 --- a/src/librustc/lint/context.rs +++ b/src/librustc/lint/context.rs @@ -208,7 +208,7 @@ impl LintStore { add_builtin_with_new!(sess, TypeLimits, - RawPointerDeriving, + RawPointerDerive, MissingDoc, ); @@ -247,6 +247,7 @@ impl LintStore { self.register_renamed("unknown_crate_type", "unknown_crate_types"); self.register_renamed("variant_size_difference", "variant_size_differences"); self.register_renamed("transmute_fat_ptr", "fat_ptr_transmutes"); + self.register_renamed("raw_pointer_deriving", "raw_pointer_derive"); } diff --git a/src/librustc/metadata/cstore.rs b/src/librustc/metadata/cstore.rs index 2f4acaca4de4d..ec0b80c3a5342 100644 --- a/src/librustc/metadata/cstore.rs +++ b/src/librustc/metadata/cstore.rs @@ -23,8 +23,8 @@ use metadata::loader; use util::nodemap::{FnvHashMap, NodeMap}; use std::cell::RefCell; -use std::c_vec::CVec; use std::rc::Rc; +use flate::Bytes; use syntax::ast; use syntax::codemap::Span; use syntax::parse::token::IdentInterner; @@ -36,7 +36,7 @@ use syntax::parse::token::IdentInterner; pub type cnum_map = FnvHashMap; pub enum MetadataBlob { - MetadataVec(CVec), + MetadataVec(Bytes), MetadataArchive(loader::ArchiveMetadata), } diff --git a/src/librustc/metadata/loader.rs b/src/librustc/metadata/loader.rs index c18bd421b3b07..7c0645b4ca204 100644 --- a/src/librustc/metadata/loader.rs +++ b/src/librustc/metadata/loader.rs @@ -226,7 +226,7 @@ use syntax::codemap::Span; use syntax::diagnostic::SpanHandler; use util::fs; -use std::c_str::ToCStr; +use std::ffi::CString; use std::cmp; use std::collections::{HashMap, HashSet}; use std::io::fs::PathExtensions; @@ -720,9 +720,8 @@ fn get_metadata_section_imp(is_osx: bool, filename: &Path) -> Result Result, E> def_id_encoder_helpers for S { fn emit_def_id(&mut self, did: ast::DefId) { did.encode(self).ok().unwrap() } } +#[cfg(not(stage0))] +impl def_id_encoder_helpers for S { + fn emit_def_id(&mut self, did: ast::DefId) { + did.encode(self).ok().unwrap() + } +} + trait def_id_decoder_helpers { fn read_def_id(&mut self, dcx: &DecodeContext) -> ast::DefId; fn read_def_id_nodcx(&mut self, cdata: &cstore::crate_metadata) -> ast::DefId; } +#[cfg(stage0)] impl, E> def_id_decoder_helpers for D { fn read_def_id(&mut self, dcx: &DecodeContext) -> ast::DefId { let did: ast::DefId = Decodable::decode(self).ok().unwrap(); @@ -288,6 +297,20 @@ impl, E> def_id_decoder_helpers for D { } } +#[cfg(not(stage0))] +impl def_id_decoder_helpers for D { + fn read_def_id(&mut self, dcx: &DecodeContext) -> ast::DefId { + let did: ast::DefId = Decodable::decode(self).ok().unwrap(); + did.tr(dcx) + } + + fn read_def_id_nodcx(&mut self, + cdata: &cstore::crate_metadata) -> ast::DefId { + let did: ast::DefId = Decodable::decode(self).ok().unwrap(); + decoder::translate_def_id(cdata, did) + } +} + // ______________________________________________________________________ // Encoding and decoding the AST itself // diff --git a/src/librustc/middle/cfg/construct.rs b/src/librustc/middle/cfg/construct.rs index de81f307c4d7c..3c672d0fdb6fa 100644 --- a/src/librustc/middle/cfg/construct.rs +++ b/src/librustc/middle/cfg/construct.rs @@ -119,7 +119,7 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> { } ast::PatBox(ref subpat) | - ast::PatRegion(ref subpat) | + ast::PatRegion(ref subpat, _) | ast::PatIdent(_, _, Some(ref subpat)) => { let subpat_exit = self.pat(&**subpat, pred); self.add_node(pat.id, &[subpat_exit]) diff --git a/src/librustc/middle/check_match.rs b/src/librustc/middle/check_match.rs index 2d9284846acf3..f2b9ecb5ec432 100644 --- a/src/librustc/middle/check_match.rs +++ b/src/librustc/middle/check_match.rs @@ -473,7 +473,7 @@ fn construct_witness(cx: &MatchCheckCtxt, ctor: &Constructor, } } - ty::ty_rptr(_, ty::mt { ty, .. }) => { + ty::ty_rptr(_, ty::mt { ty, mutbl }) => { match ty.sty { ty::ty_vec(_, Some(n)) => match ctor { &Single => { @@ -493,7 +493,7 @@ fn construct_witness(cx: &MatchCheckCtxt, ctor: &Constructor, _ => { assert_eq!(pats_len, 1); - ast::PatRegion(pats.nth(0).unwrap()) + ast::PatRegion(pats.nth(0).unwrap(), mutbl) } } } @@ -860,7 +860,7 @@ pub fn specialize<'a>(cx: &MatchCheckCtxt, r: &[&'a Pat], ast::PatTup(ref args) => Some(args.iter().map(|p| &**p).collect()), - ast::PatBox(ref inner) | ast::PatRegion(ref inner) => + ast::PatBox(ref inner) | ast::PatRegion(ref inner, _) => Some(vec![&**inner]), ast::PatLit(ref expr) => { diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index 31c3ca4199feb..f600086fc5e62 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -1262,8 +1262,10 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> { } } - ast::PatBox(ref subpat) | ast::PatRegion(ref subpat) => { - // @p1, ~p1, ref p1 + ast::PatBox(ref subpat) | ast::PatRegion(ref subpat, _) => { + // box p1, &p1, &mut p1. we can ignore the mutability of + // PatRegion since that information is already contained + // in the type. let subcmt = try!(self.cat_deref(pat, cmt, 0, false)); try!(self.cat_pattern_(subcmt, &**subpat, op)); } diff --git a/src/librustc/middle/traits/util.rs b/src/librustc/middle/traits/util.rs index ab8888f9a33eb..229d34fe4237c 100644 --- a/src/librustc/middle/traits/util.rs +++ b/src/librustc/middle/traits/util.rs @@ -92,8 +92,8 @@ impl<'cx, 'tcx> Elaborator<'cx, 'tcx> { // Only keep those bounds that we haven't already // seen. This is necessary to prevent infinite // recursion in some cases. One common case is when - // people define `trait Sized { }` rather than `trait - // Sized for Sized? { }`. + // people define `trait Sized: Sized { }` rather than `trait + // Sized { }`. predicates.retain(|r| self.visited.insert(r.clone())); self.stack.push(StackEntry { position: 0, diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index 5834844382207..4ee1728114ce5 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -1778,6 +1778,10 @@ impl<'tcx> Generics<'tcx> { !self.regions.is_empty_in(space) } + pub fn is_empty(&self) -> bool { + self.types.is_empty() && self.regions.is_empty() + } + pub fn to_bounds(&self, tcx: &ty::ctxt<'tcx>, substs: &Substs<'tcx>) -> GenericBounds<'tcx> { GenericBounds { diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs index f9f899401b175..138f648049c73 100644 --- a/src/librustc/session/config.rs +++ b/src/librustc/session/config.rs @@ -105,6 +105,7 @@ pub struct Options { pub prints: Vec, pub cg: CodegenOptions, pub color: ColorConfig, + pub show_span: Option, pub externs: HashMap>, pub crate_name: Option, /// An optional name to use as the crate for std during std injection, @@ -211,6 +212,7 @@ pub fn basic_options() -> Options { prints: Vec::new(), cg: basic_codegen_options(), color: Auto, + show_span: None, externs: HashMap::new(), crate_name: None, alt_std_name: None, @@ -259,7 +261,6 @@ debugging_opts! { BORROWCK_STATS, NO_LANDING_PADS, DEBUG_LLVM, - SHOW_SPAN, COUNT_TYPE_SIZES, META_STATS, GC, @@ -299,7 +300,6 @@ pub fn debugging_opts_map() -> Vec<(&'static str, &'static str, u64)> { ("no-landing-pads", "omit landing pads for unwinding", NO_LANDING_PADS), ("debug-llvm", "enable debug output from LLVM", DEBUG_LLVM), - ("show-span", "show spans for compiler debugging", SHOW_SPAN), ("count-type-sizes", "count the sizes of aggregate types", COUNT_TYPE_SIZES), ("meta-stats", "gather metadata statistics", META_STATS), @@ -823,6 +823,7 @@ pub fn rustc_optgroups() -> Vec { `flowgraph=` (graphviz formatted flowgraph for node), or `everybody_loops` (all function bodies replaced with `loop {}`).", "TYPE"), + opt::opt_u("", "show-span", "Show spans for compiler debugging", "expr|pat|ty"), opt::flagopt("", "dep-info", "Output dependency info to after compiling, \ in a format suitable for use by Makefiles", "FILENAME"), @@ -1143,6 +1144,7 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options { prints: prints, cg: cg, color: color, + show_span: None, externs: externs, crate_name: crate_name, alt_std_name: None, diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs index 770e8d73ec761..abb780615ae7b 100644 --- a/src/librustc/session/mod.rs +++ b/src/librustc/session/mod.rs @@ -201,8 +201,8 @@ impl Session { pub fn no_landing_pads(&self) -> bool { self.debugging_opt(config::NO_LANDING_PADS) } - pub fn show_span(&self) -> bool { - self.debugging_opt(config::SHOW_SPAN) + pub fn unstable_options(&self) -> bool { + self.debugging_opt(config::UNSTABLE_OPTIONS) } pub fn print_enum_sizes(&self) -> bool { self.debugging_opt(config::PRINT_ENUM_SIZES) diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index 9639af5ca1cd5..0c7c9513719ac 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -38,7 +38,7 @@ use syntax::{ast, ast_util}; use syntax::owned_slice::OwnedSlice; /// Produces a string suitable for debugging output. -pub trait Repr<'tcx> for Sized? { +pub trait Repr<'tcx> { fn repr(&self, tcx: &ctxt<'tcx>) -> String; } diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index 1455aa3c99bb3..2a78958c0dc13 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -146,8 +146,8 @@ pub fn phase_1_parse_input(sess: &Session, cfg: ast::CrateConfig, input: &Input) println!("{}", json::as_json(&krate)); } - if sess.show_span() { - syntax::show_span::run(sess.diagnostic(), &krate); + if let Some(ref s) = sess.opts.show_span { + syntax::show_span::run(sess.diagnostic(), s.as_slice(), &krate); } krate @@ -572,7 +572,7 @@ pub fn stop_after_phase_1(sess: &Session) -> bool { debug!("invoked with --parse-only, returning early from compile_input"); return true; } - if sess.show_span() { + if sess.opts.show_span.is_some() { return true; } return sess.opts.debugging_opts & config::AST_JSON_NOEXPAND != 0; diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index 983188c709000..2e8cde658904c 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -134,7 +134,7 @@ fn run_compiler(args: &[String]) { _ => early_error("multiple input filenames provided") }; - let sess = build_session(sopts, input_file_path, descriptions); + let mut sess = build_session(sopts, input_file_path, descriptions); let cfg = config::build_configuration(&sess); if print_crate_info(&sess, Some(&input), &odir, &ofile) { return @@ -145,7 +145,7 @@ fn run_compiler(args: &[String]) { pretty::parse_pretty(&sess, a.as_slice(), false) }); let pretty = if pretty.is_none() && - sess.debugging_opt(config::UNSTABLE_OPTIONS) { + sess.unstable_options() { matches.opt_str("xpretty").map(|a| { // extended with unstable pretty-print variants pretty::parse_pretty(&sess, a.as_slice(), true) @@ -162,6 +162,10 @@ fn run_compiler(args: &[String]) { None => {/* continue */ } } + if sess.unstable_options() { + sess.opts.show_span = matches.opt_str("show-span"); + } + let r = matches.opt_strs("Z"); if r.contains(&("ls".to_string())) { match input { diff --git a/src/librustc_llvm/archive_ro.rs b/src/librustc_llvm/archive_ro.rs index 53992d4567a34..d3555e4c04363 100644 --- a/src/librustc_llvm/archive_ro.rs +++ b/src/librustc_llvm/archive_ro.rs @@ -13,7 +13,7 @@ use libc; use ArchiveRef; -use std::c_str::ToCStr; +use std::ffi::CString; use std::mem; use std::raw; @@ -30,9 +30,8 @@ impl ArchiveRO { /// raised. pub fn open(dst: &Path) -> Option { unsafe { - let ar = dst.with_c_str(|dst| { - ::LLVMRustOpenArchive(dst) - }); + let s = CString::from_slice(dst.as_vec()); + let ar = ::LLVMRustOpenArchive(s.as_ptr()); if ar.is_null() { None } else { @@ -45,9 +44,9 @@ impl ArchiveRO { pub fn read<'a>(&'a self, file: &str) -> Option<&'a [u8]> { unsafe { let mut size = 0 as libc::size_t; - let ptr = file.with_c_str(|file| { - ::LLVMRustArchiveReadSection(self.ptr, file, &mut size) - }); + let file = CString::from_slice(file.as_bytes()); + let ptr = ::LLVMRustArchiveReadSection(self.ptr, file.as_ptr(), + &mut size); if ptr.is_null() { None } else { diff --git a/src/librustc_llvm/lib.rs b/src/librustc_llvm/lib.rs index 2ec5f37634afb..854ac5ff5c01c 100644 --- a/src/librustc_llvm/lib.rs +++ b/src/librustc_llvm/lib.rs @@ -47,7 +47,7 @@ pub use self::Visibility::*; pub use self::DiagnosticSeverity::*; pub use self::Linkage::*; -use std::c_str::ToCStr; +use std::ffi::CString; use std::cell::RefCell; use std::{raw, mem}; use libc::{c_uint, c_ushort, uint64_t, c_int, size_t, c_char}; @@ -2114,10 +2114,9 @@ impl Drop for TargetData { } pub fn mk_target_data(string_rep: &str) -> TargetData { + let string_rep = CString::from_slice(string_rep.as_bytes()); TargetData { - lltd: string_rep.with_c_str(|buf| { - unsafe { LLVMCreateTargetData(buf) } - }) + lltd: unsafe { LLVMCreateTargetData(string_rep.as_ptr()) } } } diff --git a/src/librustc_trans/back/lto.rs b/src/librustc_trans/back/lto.rs index c6488ec6638a3..f3e90c43a8414 100644 --- a/src/librustc_trans/back/lto.rs +++ b/src/librustc_trans/back/lto.rs @@ -20,7 +20,7 @@ use rustc::util::common::time; use libc; use flate; -use std::c_str::ToCStr; +use std::ffi::CString; use std::iter; use std::mem; use std::num::Int; @@ -139,9 +139,10 @@ pub fn run(sess: &session::Session, llmod: ModuleRef, } // Internalize everything but the reachable symbols of the current module - let cstrs: Vec<::std::c_str::CString> = - reachable.iter().map(|s| s.to_c_str()).collect(); - let arr: Vec<*const libc::c_char> = cstrs.iter().map(|c| c.as_ptr()).collect(); + let cstrs: Vec = reachable.iter().map(|s| { + CString::from_slice(s.as_bytes()) + }).collect(); + let arr: Vec<*const i8> = cstrs.iter().map(|c| c.as_ptr()).collect(); let ptr = arr.as_ptr(); unsafe { llvm::LLVMRustRunRestrictionPass(llmod, @@ -164,7 +165,7 @@ pub fn run(sess: &session::Session, llmod: ModuleRef, unsafe { let pm = llvm::LLVMCreatePassManager(); llvm::LLVMRustAddAnalysisPasses(tm, pm, llmod); - "verify".with_c_str(|s| llvm::LLVMRustAddPass(pm, s)); + llvm::LLVMRustAddPass(pm, "verify\0".as_ptr() as *const _); let builder = llvm::LLVMPassManagerBuilderCreate(); llvm::LLVMPassManagerBuilderPopulateLTOPassManager(builder, pm, @@ -172,7 +173,7 @@ pub fn run(sess: &session::Session, llmod: ModuleRef, /* RunInliner = */ True); llvm::LLVMPassManagerBuilderDispose(builder); - "verify".with_c_str(|s| llvm::LLVMRustAddPass(pm, s)); + llvm::LLVMRustAddPass(pm, "verify\0".as_ptr() as *const _); time(sess.time_passes(), "LTO passes", (), |()| llvm::LLVMRunPassManager(pm, llmod)); diff --git a/src/librustc_trans/back/write.rs b/src/librustc_trans/back/write.rs index 33011d9e35c10..98e2b4b9dddb5 100644 --- a/src/librustc_trans/back/write.rs +++ b/src/librustc_trans/back/write.rs @@ -22,7 +22,7 @@ use syntax::codemap; use syntax::diagnostic; use syntax::diagnostic::{Emitter, Handler, Level, mk_handler}; -use std::c_str::{ToCStr, CString}; +use std::ffi::{self, CString}; use std::io::Command; use std::io::fs; use std::iter::Unfold; @@ -32,7 +32,7 @@ use std::mem; use std::sync::{Arc, Mutex}; use std::sync::mpsc::channel; use std::thread; -use libc::{c_uint, c_int, c_void}; +use libc::{self, c_uint, c_int, c_void}; #[derive(Clone, Copy, PartialEq, PartialOrd, Ord, Eq)] pub enum OutputType { @@ -49,8 +49,9 @@ pub fn llvm_err(handler: &diagnostic::Handler, msg: String) -> ! { if cstr == ptr::null() { handler.fatal(msg[]); } else { - let err = CString::new(cstr, true); - let err = String::from_utf8_lossy(err.as_bytes()); + let err = ffi::c_str_to_bytes(&cstr); + let err = String::from_utf8_lossy(err.as_slice()).to_string(); + libc::free(cstr as *mut _); handler.fatal(format!("{}: {}", msg[], err[])[]); @@ -66,13 +67,12 @@ pub fn write_output_file( output: &Path, file_type: llvm::FileType) { unsafe { - output.with_c_str(|output| { - let result = llvm::LLVMRustWriteOutputFile( - target, pm, m, output, file_type); - if !result { - llvm_err(handler, "could not write output".to_string()); - } - }) + let output = CString::from_slice(output.as_vec()); + let result = llvm::LLVMRustWriteOutputFile( + target, pm, m, output.as_ptr(), file_type); + if !result { + llvm_err(handler, "could not write output".to_string()); + } } } @@ -221,28 +221,25 @@ fn create_target_machine(sess: &Session) -> TargetMachineRef { let triple = sess.target.target.llvm_target[]; let tm = unsafe { - triple.with_c_str(|t| { - let cpu = match sess.opts.cg.target_cpu { - Some(ref s) => s[], - None => sess.target.target.options.cpu[] - }; - cpu.with_c_str(|cpu| { - target_feature(sess).with_c_str(|features| { - llvm::LLVMRustCreateTargetMachine( - t, cpu, features, - code_model, - reloc_model, - opt_level, - true /* EnableSegstk */, - use_softfp, - no_fp_elim, - !any_library && reloc_model == llvm::RelocPIC, - ffunction_sections, - fdata_sections, - ) - }) - }) - }) + let triple = CString::from_slice(triple.as_bytes()); + let cpu = match sess.opts.cg.target_cpu { + Some(ref s) => s.as_slice(), + None => sess.target.target.options.cpu.as_slice() + }; + let cpu = CString::from_slice(cpu.as_bytes()); + let features = CString::from_slice(target_feature(sess).as_bytes()); + llvm::LLVMRustCreateTargetMachine( + triple.as_ptr(), cpu.as_ptr(), features.as_ptr(), + code_model, + reloc_model, + opt_level, + true /* EnableSegstk */, + use_softfp, + no_fp_elim, + !any_library && reloc_model == llvm::RelocPIC, + ffunction_sections, + fdata_sections, + ) }; if tm.is_null() { @@ -371,8 +368,9 @@ unsafe extern "C" fn diagnostic_handler(info: DiagnosticInfoRef, user: *mut c_vo match llvm::diagnostic::Diagnostic::unpack(info) { llvm::diagnostic::Optimization(opt) => { - let pass_name = CString::new(opt.pass_name, false); - let pass_name = pass_name.as_str().expect("got a non-UTF8 pass name from LLVM"); + let pass_name = str::from_utf8(ffi::c_str_to_bytes(&opt.pass_name)) + .ok() + .expect("got a non-UTF8 pass name from LLVM"); let enabled = match cgcx.remark { AllPasses => true, SomePasses(ref v) => v.iter().any(|s| *s == pass_name), @@ -416,9 +414,9 @@ unsafe fn optimize_and_codegen(cgcx: &CodegenContext, if config.emit_no_opt_bc { let ext = format!("{}.no-opt.bc", name_extra); - output_names.with_extension(ext[]).with_c_str(|buf| { - llvm::LLVMWriteBitcodeToFile(llmod, buf); - }) + let out = output_names.with_extension(ext.as_slice()); + let out = CString::from_slice(out.as_vec()); + llvm::LLVMWriteBitcodeToFile(llmod, out.as_ptr()); } match config.opt_level { @@ -433,7 +431,8 @@ unsafe fn optimize_and_codegen(cgcx: &CodegenContext, // If we're verifying or linting, add them to the function pass // manager. let addpass = |&: pass: &str| { - pass.with_c_str(|s| llvm::LLVMRustAddPass(fpm, s)) + let pass = CString::from_slice(pass.as_bytes()); + llvm::LLVMRustAddPass(fpm, pass.as_ptr()) }; if !config.no_verify { assert!(addpass("verify")); } @@ -445,12 +444,11 @@ unsafe fn optimize_and_codegen(cgcx: &CodegenContext, } for pass in config.passes.iter() { - pass.with_c_str(|s| { - if !llvm::LLVMRustAddPass(mpm, s) { - cgcx.handler.warn(format!("unknown pass {}, ignoring", - *pass)[]); - } - }) + let pass = CString::from_slice(pass.as_bytes()); + if !llvm::LLVMRustAddPass(mpm, pass.as_ptr()) { + cgcx.handler.warn(format!("unknown pass {}, ignoring", + pass).as_slice()); + } } // Finally, run the actual optimization passes @@ -470,9 +468,9 @@ unsafe fn optimize_and_codegen(cgcx: &CodegenContext, if config.emit_lto_bc { let name = format!("{}.lto.bc", name_extra); - output_names.with_extension(name[]).with_c_str(|buf| { - llvm::LLVMWriteBitcodeToFile(llmod, buf); - }) + let out = output_names.with_extension(name.as_slice()); + let out = CString::from_slice(out.as_vec()); + llvm::LLVMWriteBitcodeToFile(llmod, out.as_ptr()); } }, _ => {}, @@ -504,18 +502,18 @@ unsafe fn optimize_and_codegen(cgcx: &CodegenContext, if config.emit_bc { let ext = format!("{}.bc", name_extra); - output_names.with_extension(ext[]).with_c_str(|buf| { - llvm::LLVMWriteBitcodeToFile(llmod, buf); - }) + let out = output_names.with_extension(ext.as_slice()); + let out = CString::from_slice(out.as_vec()); + llvm::LLVMWriteBitcodeToFile(llmod, out.as_ptr()); } time(config.time_passes, "codegen passes", (), |()| { if config.emit_ir { let ext = format!("{}.ll", name_extra); - output_names.with_extension(ext[]).with_c_str(|output| { - with_codegen(tm, llmod, config.no_builtins, |cpm| { - llvm::LLVMRustPrintModule(cpm, llmod, output); - }) + let out = output_names.with_extension(ext.as_slice()); + let out = CString::from_slice(out.as_vec()); + with_codegen(tm, llmod, config.no_builtins, |cpm| { + llvm::LLVMRustPrintModule(cpm, llmod, out.as_ptr()); }) } @@ -995,7 +993,7 @@ unsafe fn configure_llvm(sess: &Session) { let mut llvm_args = Vec::new(); { let mut add = |&mut : arg: &str| { - let s = arg.to_c_str(); + let s = CString::from_slice(arg.as_bytes()); llvm_args.push(s.as_ptr()); llvm_c_strs.push(s); }; @@ -1083,7 +1081,7 @@ unsafe fn populate_llvm_passes(fpm: llvm::PassManagerRef, match opt { llvm::CodeGenLevelDefault | llvm::CodeGenLevelAggressive => { - "mergefunc".with_c_str(|s| llvm::LLVMRustAddPass(mpm, s)); + llvm::LLVMRustAddPass(mpm, "mergefunc\0".as_ptr() as *const _); } _ => {} }; diff --git a/src/librustc_trans/trans/_match.rs b/src/librustc_trans/trans/_match.rs index 50cbe664b9079..fed0931cab71d 100644 --- a/src/librustc_trans/trans/_match.rs +++ b/src/librustc_trans/trans/_match.rs @@ -683,7 +683,7 @@ fn any_uniq_pat(m: &[Match], col: uint) -> bool { } fn any_region_pat(m: &[Match], col: uint) -> bool { - any_pat!(m, col, ast::PatRegion(_)) + any_pat!(m, col, ast::PatRegion(..)) } fn any_irrefutable_adt_pat(tcx: &ty::ctxt, m: &[Match], col: uint) -> bool { @@ -1725,7 +1725,7 @@ fn bind_irrefutable_pat<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, let llbox = Load(bcx, val); bcx = bind_irrefutable_pat(bcx, &**inner, llbox, cleanup_scope); } - ast::PatRegion(ref inner) => { + ast::PatRegion(ref inner, _) => { let loaded_val = Load(bcx, val); bcx = bind_irrefutable_pat(bcx, &**inner, loaded_val, cleanup_scope); } diff --git a/src/librustc_trans/trans/asm.rs b/src/librustc_trans/trans/asm.rs index 5597e112f76d1..f18d483f70328 100644 --- a/src/librustc_trans/trans/asm.rs +++ b/src/librustc_trans/trans/asm.rs @@ -20,9 +20,8 @@ use trans::expr; use trans::type_of; use trans::type_::Type; -use std::c_str::ToCStr; -use std::string::String; use syntax::ast; +use std::ffi::CString; use libc::{c_uint, c_char}; // Take an inline assembly expression and splat it out via LLVM @@ -121,18 +120,16 @@ pub fn trans_inline_asm<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, ia: &ast::InlineAsm) ast::AsmIntel => llvm::AD_Intel }; - let r = ia.asm.get().with_c_str(|a| { - constraints.with_c_str(|c| { - InlineAsmCall(bcx, - a, - c, - inputs[], + let asm = CString::from_slice(ia.asm.get().as_bytes()); + let constraints = CString::from_slice(constraints.as_bytes()); + let r = InlineAsmCall(bcx, + asm.as_ptr(), + constraints.as_ptr(), + inputs.as_slice(), output_type, ia.volatile, ia.alignstack, - dialect) - }) - }); + dialect); // Again, based on how many outputs we have if num_outputs == 1 { diff --git a/src/librustc_trans/trans/base.rs b/src/librustc_trans/trans/base.rs index 518042cf70889..d0324e2f86f98 100644 --- a/src/librustc_trans/trans/base.rs +++ b/src/librustc_trans/trans/base.rs @@ -88,11 +88,12 @@ use util::nodemap::NodeMap; use arena::TypedArena; use libc::{c_uint, uint64_t}; -use std::c_str::ToCStr; +use std::ffi::{self, CString}; use std::cell::{Cell, RefCell}; use std::collections::HashSet; use std::mem; use std::rc::Rc; +use std::str; use std::{i8, i16, i32, i64}; use syntax::abi::{Rust, RustCall, RustIntrinsic, Abi}; use syntax::ast_util::local_def; @@ -187,11 +188,10 @@ impl<'a, 'tcx> Drop for StatRecorder<'a, 'tcx> { pub fn decl_fn(ccx: &CrateContext, name: &str, cc: llvm::CallConv, ty: Type, output: ty::FnOutput) -> ValueRef { - let llfn: ValueRef = name.with_c_str(|buf| { - unsafe { - llvm::LLVMGetOrInsertFunction(ccx.llmod(), buf, ty.to_ref()) - } - }); + let buf = CString::from_slice(name.as_bytes()); + let llfn: ValueRef = unsafe { + llvm::LLVMGetOrInsertFunction(ccx.llmod(), buf.as_ptr(), ty.to_ref()) + }; // diverging functions may unwind, but can never return normally if output == ty::FnDiverging { @@ -334,9 +334,8 @@ pub fn get_extern_const<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, did: ast::DefId, None => () } unsafe { - let c = name.with_c_str(|buf| { - llvm::LLVMAddGlobal(ccx.llmod(), ty.to_ref(), buf) - }); + let buf = CString::from_slice(name.as_bytes()); + let c = llvm::LLVMAddGlobal(ccx.llmod(), ty.to_ref(), buf.as_ptr()); // Thread-local statics in some other crate need to *always* be linked // against in a thread-local fashion, so we need to be sure to apply the // thread-local attribute locally if it was present remotely. If we @@ -475,15 +474,17 @@ pub fn set_always_inline(f: ValueRef) { } pub fn set_split_stack(f: ValueRef) { - "split-stack".with_c_str(|buf| { - unsafe { llvm::LLVMAddFunctionAttrString(f, llvm::FunctionIndex as c_uint, buf); } - }) + unsafe { + llvm::LLVMAddFunctionAttrString(f, llvm::FunctionIndex as c_uint, + "split-stack\0".as_ptr() as *const _); + } } pub fn unset_split_stack(f: ValueRef) { - "split-stack".with_c_str(|buf| { - unsafe { llvm::LLVMRemoveFunctionAttrString(f, llvm::FunctionIndex as c_uint, buf); } - }) + unsafe { + llvm::LLVMRemoveFunctionAttrString(f, llvm::FunctionIndex as c_uint, + "split-stack\0".as_ptr() as *const _); + } } // Double-check that we never ask LLVM to declare the same symbol twice. It @@ -537,11 +538,8 @@ pub fn get_res_dtor<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, // Structural comparison: a rather involved form of glue. pub fn maybe_name_value(cx: &CrateContext, v: ValueRef, s: &str) { if cx.sess().opts.cg.save_temps { - s.with_c_str(|buf| { - unsafe { - llvm::LLVMSetValueName(v, buf) - } - }) + let buf = CString::from_slice(s.as_bytes()); + unsafe { llvm::LLVMSetValueName(v, buf.as_ptr()) } } } @@ -2645,11 +2643,10 @@ pub fn create_entry_wrapper(ccx: &CrateContext, unsafe { llvm::LLVMRustSetDLLExportStorageClass(llfn) } } - let llbb = "top".with_c_str(|buf| { - unsafe { - llvm::LLVMAppendBasicBlockInContext(ccx.llcx(), llfn, buf) - } - }); + let llbb = unsafe { + llvm::LLVMAppendBasicBlockInContext(ccx.llcx(), llfn, + "top\0".as_ptr() as *const _) + }; let bld = ccx.raw_builder(); unsafe { llvm::LLVMPositionBuilderAtEnd(bld, llbb); @@ -2670,9 +2667,9 @@ pub fn create_entry_wrapper(ccx: &CrateContext, }; let args = { - let opaque_rust_main = "rust_main".with_c_str(|buf| { - llvm::LLVMBuildPointerCast(bld, rust_main, Type::i8p(ccx).to_ref(), buf) - }); + let opaque_rust_main = llvm::LLVMBuildPointerCast(bld, + rust_main, Type::i8p(ccx).to_ref(), + "rust_main\0".as_ptr() as *const _); vec!( opaque_rust_main, @@ -2779,9 +2776,9 @@ pub fn get_item_val(ccx: &CrateContext, id: ast::NodeId) -> ValueRef { format!("Illegal null byte in export_name \ value: `{}`", sym)[]); } - let g = sym.with_c_str(|buf| { - llvm::LLVMAddGlobal(ccx.llmod(), llty, buf) - }); + let buf = CString::from_slice(sym.as_bytes()); + let g = llvm::LLVMAddGlobal(ccx.llmod(), llty, + buf.as_ptr()); if attr::contains_name(i.attrs[], "thread_local") { @@ -2823,9 +2820,8 @@ pub fn get_item_val(ccx: &CrateContext, id: ast::NodeId) -> ValueRef { sect.get())[]); } unsafe { - sect.get().with_c_str(|buf| { - llvm::LLVMSetSection(v, buf); - }) + let buf = CString::from_slice(sect.get().as_bytes()); + llvm::LLVMSetSection(v, buf.as_ptr()); } }, None => () @@ -2992,17 +2988,16 @@ pub fn write_metadata(cx: &SharedCrateContext, krate: &ast::Crate) -> Vec { let name = format!("rust_metadata_{}_{}", cx.link_meta().crate_name, cx.link_meta().crate_hash); - let llglobal = name.with_c_str(|buf| { - unsafe { - llvm::LLVMAddGlobal(cx.metadata_llmod(), val_ty(llconst).to_ref(), buf) - } - }); + let buf = CString::from_vec(name.into_bytes()); + let llglobal = unsafe { + llvm::LLVMAddGlobal(cx.metadata_llmod(), val_ty(llconst).to_ref(), + buf.as_ptr()) + }; unsafe { llvm::LLVMSetInitializer(llglobal, llconst); let name = loader::meta_section_name(cx.sess().target.target.options.is_like_osx); - name.with_c_str(|buf| { - llvm::LLVMSetSection(llglobal, buf) - }); + let name = CString::from_slice(name.as_bytes()); + llvm::LLVMSetSection(llglobal, name.as_ptr()) } return metadata; } @@ -3010,8 +3005,6 @@ pub fn write_metadata(cx: &SharedCrateContext, krate: &ast::Crate) -> Vec { /// Find any symbols that are defined in one compilation unit, but not declared /// in any other compilation unit. Give these symbols internal linkage. fn internalize_symbols(cx: &SharedCrateContext, reachable: &HashSet) { - use std::c_str::CString; - unsafe { let mut declared = HashSet::new(); @@ -3041,7 +3034,8 @@ fn internalize_symbols(cx: &SharedCrateContext, reachable: &HashSet) { continue } - let name = CString::new(llvm::LLVMGetValueName(val), false); + let name = ffi::c_str_to_bytes(&llvm::LLVMGetValueName(val)) + .to_vec(); declared.insert(name); } } @@ -3057,9 +3051,10 @@ fn internalize_symbols(cx: &SharedCrateContext, reachable: &HashSet) { continue } - let name = CString::new(llvm::LLVMGetValueName(val), false); + let name = ffi::c_str_to_bytes(&llvm::LLVMGetValueName(val)) + .to_vec(); if !declared.contains(&name) && - !reachable.contains(name.as_str().unwrap()) { + !reachable.contains(str::from_utf8(name.as_slice()).unwrap()) { llvm::SetLinkage(val, llvm::InternalLinkage); } } diff --git a/src/librustc_trans/trans/builder.rs b/src/librustc_trans/trans/builder.rs index 97f0b92a290f8..e09d36ddae923 100644 --- a/src/librustc_trans/trans/builder.rs +++ b/src/librustc_trans/trans/builder.rs @@ -20,7 +20,8 @@ use trans::machine::llalign_of_pref; use trans::type_::Type; use util::nodemap::FnvHashMap; use libc::{c_uint, c_char}; -use std::c_str::ToCStr; + +use std::ffi::CString; use syntax::codemap::Span; pub struct Builder<'a, 'tcx: 'a> { @@ -429,9 +430,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { if name.is_empty() { llvm::LLVMBuildAlloca(self.llbuilder, ty.to_ref(), noname()) } else { - name.with_c_str(|c| { - llvm::LLVMBuildAlloca(self.llbuilder, ty.to_ref(), c) - }) + let name = CString::from_slice(name.as_bytes()); + llvm::LLVMBuildAlloca(self.llbuilder, ty.to_ref(), + name.as_ptr()) } } } @@ -774,12 +775,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let comment_text = format!("{} {}", "#", sanitized.replace("\n", "\n\t# ")); self.count_insn("inlineasm"); - let asm = comment_text.with_c_str(|c| { - unsafe { - llvm::LLVMConstInlineAsm(Type::func(&[], &Type::void(self.ccx)).to_ref(), - c, noname(), False, False) - } - }); + let comment_text = CString::from_vec(comment_text.into_bytes()); + let asm = unsafe { + llvm::LLVMConstInlineAsm(Type::func(&[], &Type::void(self.ccx)).to_ref(), + comment_text.as_ptr(), noname(), False, + False) + }; self.call(asm, &[], None); } } @@ -926,9 +927,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let bb: BasicBlockRef = llvm::LLVMGetInsertBlock(self.llbuilder); let fn_: ValueRef = llvm::LLVMGetBasicBlockParent(bb); let m: ModuleRef = llvm::LLVMGetGlobalParent(fn_); - let t: ValueRef = "llvm.trap".with_c_str(|buf| { - llvm::LLVMGetNamedFunction(m, buf) - }); + let p = "llvm.trap\0".as_ptr(); + let t: ValueRef = llvm::LLVMGetNamedFunction(m, p as *const _); assert!((t as int != 0)); let args: &[ValueRef] = &[]; self.count_insn("trap"); diff --git a/src/librustc_trans/trans/cabi_x86_64.rs b/src/librustc_trans/trans/cabi_x86_64.rs index f59d152fa473c..9ec0c822bf5fe 100644 --- a/src/librustc_trans/trans/cabi_x86_64.rs +++ b/src/librustc_trans/trans/cabi_x86_64.rs @@ -63,7 +63,7 @@ impl RegClass { } } -trait ClassList for Sized? { +trait ClassList { fn is_pass_byval(&self) -> bool; fn is_ret_bysret(&self) -> bool; } diff --git a/src/librustc_trans/trans/common.rs b/src/librustc_trans/trans/common.rs index e8dee19ed54c1..094f98e988aad 100644 --- a/src/librustc_trans/trans/common.rs +++ b/src/librustc_trans/trans/common.rs @@ -44,7 +44,7 @@ use util::nodemap::{FnvHashMap, NodeMap}; use arena::TypedArena; use libc::{c_uint, c_char}; -use std::c_str::ToCStr; +use std::ffi::CString; use std::cell::{Cell, RefCell}; use std::vec::Vec; use syntax::ast::Ident; @@ -401,9 +401,8 @@ impl<'a, 'tcx> FunctionContext<'a, 'tcx> { if self.llreturn.get().is_none() { self.llreturn.set(Some(unsafe { - "return".with_c_str(|buf| { - llvm::LLVMAppendBasicBlockInContext(self.ccx.llcx(), self.llfn, buf) - }) + llvm::LLVMAppendBasicBlockInContext(self.ccx.llcx(), self.llfn, + "return\0".as_ptr() as *const _) })) } @@ -429,11 +428,10 @@ impl<'a, 'tcx> FunctionContext<'a, 'tcx> { opt_node_id: Option) -> Block<'a, 'tcx> { unsafe { - let llbb = name.with_c_str(|buf| { - llvm::LLVMAppendBasicBlockInContext(self.ccx.llcx(), - self.llfn, - buf) - }); + let name = CString::from_slice(name.as_bytes()); + let llbb = llvm::LLVMAppendBasicBlockInContext(self.ccx.llcx(), + self.llfn, + name.as_ptr()); BlockS::new(llbb, is_lpad, opt_node_id, self) } } @@ -708,7 +706,8 @@ pub fn C_integral(t: Type, u: u64, sign_extend: bool) -> ValueRef { pub fn C_floating(s: &str, t: Type) -> ValueRef { unsafe { - s.with_c_str(|buf| llvm::LLVMConstRealOfString(t.to_ref(), buf)) + let s = CString::from_slice(s.as_bytes()); + llvm::LLVMConstRealOfString(t.to_ref(), s.as_ptr()) } } @@ -789,9 +788,8 @@ pub fn C_cstr(cx: &CrateContext, s: InternedString, null_terminated: bool) -> Va !null_terminated as Bool); let gsym = token::gensym("str"); - let g = format!("str{}", gsym.uint()).with_c_str(|buf| { - llvm::LLVMAddGlobal(cx.llmod(), val_ty(sc).to_ref(), buf) - }); + let buf = CString::from_vec(format!("str{}", gsym.uint()).into_bytes()); + let g = llvm::LLVMAddGlobal(cx.llmod(), val_ty(sc).to_ref(), buf.as_ptr()); llvm::LLVMSetInitializer(g, sc); llvm::LLVMSetGlobalConstant(g, True); llvm::SetLinkage(g, llvm::InternalLinkage); @@ -815,9 +813,10 @@ pub fn C_binary_slice(cx: &CrateContext, data: &[u8]) -> ValueRef { let lldata = C_bytes(cx, data); let gsym = token::gensym("binary"); - let g = format!("binary{}", gsym.uint()).with_c_str(|buf| { - llvm::LLVMAddGlobal(cx.llmod(), val_ty(lldata).to_ref(), buf) - }); + let name = format!("binary{}", gsym.uint()); + let name = CString::from_vec(name.into_bytes()); + let g = llvm::LLVMAddGlobal(cx.llmod(), val_ty(lldata).to_ref(), + name.as_ptr()); llvm::LLVMSetInitializer(g, lldata); llvm::LLVMSetGlobalConstant(g, True); llvm::SetLinkage(g, llvm::InternalLinkage); diff --git a/src/librustc_trans/trans/consts.rs b/src/librustc_trans/trans/consts.rs index b17e852d7cbc4..9432fa8bd3d59 100644 --- a/src/librustc_trans/trans/consts.rs +++ b/src/librustc_trans/trans/consts.rs @@ -24,7 +24,6 @@ use middle::subst::Substs; use middle::ty::{self, Ty}; use util::ppaux::{Repr, ty_to_string}; -use std::c_str::ToCStr; use std::iter::repeat; use libc::c_uint; use syntax::{ast, ast_util}; @@ -103,9 +102,8 @@ fn const_vec(cx: &CrateContext, e: &ast::Expr, pub fn const_addr_of(cx: &CrateContext, cv: ValueRef, mutbl: ast::Mutability) -> ValueRef { unsafe { - let gv = "const".with_c_str(|name| { - llvm::LLVMAddGlobal(cx.llmod(), val_ty(cv).to_ref(), name) - }); + let gv = llvm::LLVMAddGlobal(cx.llmod(), val_ty(cv).to_ref(), + "const\0".as_ptr() as *const _); llvm::LLVMSetInitializer(gv, cv); llvm::LLVMSetGlobalConstant(gv, if mutbl == ast::MutImmutable {True} else {False}); diff --git a/src/librustc_trans/trans/context.rs b/src/librustc_trans/trans/context.rs index e5a0e2e9234d5..f974a6faf4c19 100644 --- a/src/librustc_trans/trans/context.rs +++ b/src/librustc_trans/trans/context.rs @@ -29,8 +29,8 @@ use util::ppaux::Repr; use util::sha2::Sha256; use util::nodemap::{NodeMap, NodeSet, DefIdMap, FnvHashMap, FnvHashSet}; +use std::ffi::CString; use std::cell::{Cell, RefCell}; -use std::c_str::ToCStr; use std::ptr; use std::rc::Rc; use syntax::ast; @@ -221,21 +221,16 @@ impl<'a, 'tcx> Iterator for CrateContextMaybeIterator<'a, 'tcx> { unsafe fn create_context_and_module(sess: &Session, mod_name: &str) -> (ContextRef, ModuleRef) { let llcx = llvm::LLVMContextCreate(); - let llmod = mod_name.with_c_str(|buf| { - llvm::LLVMModuleCreateWithNameInContext(buf, llcx) - }); - sess.target - .target - .data_layout - .with_c_str(|buf| { - llvm::LLVMSetDataLayout(llmod, buf); - }); - sess.target - .target - .llvm_target - .with_c_str(|buf| { - llvm::LLVMRustSetNormalizedTarget(llmod, buf); - }); + let mod_name = CString::from_slice(mod_name.as_bytes()); + let llmod = llvm::LLVMModuleCreateWithNameInContext(mod_name.as_ptr(), llcx); + + let data_layout = sess.target.target.data_layout.as_slice(); + let data_layout = CString::from_slice(data_layout.as_bytes()); + llvm::LLVMSetDataLayout(llmod, data_layout.as_ptr()); + + let llvm_target = sess.target.target.llvm_target.as_slice(); + let llvm_target = CString::from_slice(llvm_target.as_bytes()); + llvm::LLVMRustSetNormalizedTarget(llmod, llvm_target.as_ptr()); (llcx, llmod) } diff --git a/src/librustc_trans/trans/debuginfo.rs b/src/librustc_trans/trans/debuginfo.rs index 916fcbfe13ef7..b871f93ad4806 100644 --- a/src/librustc_trans/trans/debuginfo.rs +++ b/src/librustc_trans/trans/debuginfo.rs @@ -207,7 +207,7 @@ use util::nodemap::{DefIdMap, NodeMap, FnvHashMap, FnvHashSet}; use util::ppaux; use libc::c_uint; -use std::c_str::{CString, ToCStr}; +use std::ffi::CString; use std::cell::{Cell, RefCell}; use std::ptr; use std::rc::{Rc, Weak}; @@ -760,14 +760,15 @@ pub fn finalize(cx: &CrateContext) { // for OS X to understand. For more info see #11352 // This can be overridden using --llvm-opts -dwarf-version,N. if cx.sess().target.target.options.is_like_osx { - "Dwarf Version".with_c_str( - |s| llvm::LLVMRustAddModuleFlag(cx.llmod(), s, 2)); + llvm::LLVMRustAddModuleFlag(cx.llmod(), + "Dwarf Version\0".as_ptr() as *const _, + 2) } // Prevent bitcode readers from deleting the debug info. - "Debug Info Version".with_c_str( - |s| llvm::LLVMRustAddModuleFlag(cx.llmod(), s, - llvm::LLVMRustDebugMetadataVersion)); + let ptr = "Debug Info Version\0".as_ptr(); + llvm::LLVMRustAddModuleFlag(cx.llmod(), ptr as *const _, + llvm::LLVMRustDebugMetadataVersion); }; } @@ -829,22 +830,20 @@ pub fn create_global_var_metadata(cx: &CrateContext, namespace_node.mangled_name_of_contained_item(var_name[]); let var_scope = namespace_node.scope; - var_name.with_c_str(|var_name| { - linkage_name.with_c_str(|linkage_name| { - unsafe { - llvm::LLVMDIBuilderCreateStaticVariable(DIB(cx), - var_scope, - var_name, - linkage_name, - file_metadata, - line_number, - type_metadata, - is_local_to_unit, - global, - ptr::null_mut()); - } - }) - }); + let var_name = CString::from_slice(var_name.as_bytes()); + let linkage_name = CString::from_slice(linkage_name.as_bytes()); + unsafe { + llvm::LLVMDIBuilderCreateStaticVariable(DIB(cx), + var_scope, + var_name.as_ptr(), + linkage_name.as_ptr(), + file_metadata, + line_number, + type_metadata, + is_local_to_unit, + global, + ptr::null_mut()); + } } /// Creates debug information for the given local variable. @@ -1388,28 +1387,26 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, let is_local_to_unit = is_node_local_to_unit(cx, fn_ast_id); - let fn_metadata = function_name.with_c_str(|function_name| { - linkage_name.with_c_str(|linkage_name| { - unsafe { - llvm::LLVMDIBuilderCreateFunction( - DIB(cx), - containing_scope, - function_name, - linkage_name, - file_metadata, - loc.line as c_uint, - function_type_metadata, - is_local_to_unit, - true, - scope_line as c_uint, - FlagPrototyped as c_uint, - cx.sess().opts.optimize != config::No, - llfn, - template_parameters, - ptr::null_mut()) - } - }) - }); + let function_name = CString::from_slice(function_name.as_bytes()); + let linkage_name = CString::from_slice(linkage_name.as_bytes()); + let fn_metadata = unsafe { + llvm::LLVMDIBuilderCreateFunction( + DIB(cx), + containing_scope, + function_name.as_ptr(), + linkage_name.as_ptr(), + file_metadata, + loc.line as c_uint, + function_type_metadata, + is_local_to_unit, + true, + scope_line as c_uint, + FlagPrototyped as c_uint, + cx.sess().opts.optimize != config::No, + llfn, + template_parameters, + ptr::null_mut()) + }; let scope_map = create_scope_map(cx, fn_decl.inputs.as_slice(), @@ -1514,19 +1511,18 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, let ident = special_idents::type_self; - let param_metadata = token::get_ident(ident).get() - .with_c_str(|name| { - unsafe { - llvm::LLVMDIBuilderCreateTemplateTypeParameter( - DIB(cx), - file_metadata, - name, - actual_self_type_metadata, - ptr::null_mut(), - 0, - 0) - } - }); + let ident = token::get_ident(ident); + let name = CString::from_slice(ident.get().as_bytes()); + let param_metadata = unsafe { + llvm::LLVMDIBuilderCreateTemplateTypeParameter( + DIB(cx), + file_metadata, + name.as_ptr(), + actual_self_type_metadata, + ptr::null_mut(), + 0, + 0) + }; template_params.push(param_metadata); } @@ -1549,19 +1545,18 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, // Again, only create type information if full debuginfo is enabled if cx.sess().opts.debuginfo == FullDebugInfo { let actual_type_metadata = type_metadata(cx, actual_type, codemap::DUMMY_SP); - let param_metadata = token::get_ident(ident).get() - .with_c_str(|name| { - unsafe { - llvm::LLVMDIBuilderCreateTemplateTypeParameter( - DIB(cx), - file_metadata, - name, - actual_type_metadata, - ptr::null_mut(), - 0, - 0) - } - }); + let ident = token::get_ident(ident); + let name = CString::from_slice(ident.get().as_bytes()); + let param_metadata = unsafe { + llvm::LLVMDIBuilderCreateTemplateTypeParameter( + DIB(cx), + file_metadata, + name.as_ptr(), + actual_type_metadata, + ptr::null_mut(), + 0, + 0) + }; template_params.push(param_metadata); } } @@ -1606,19 +1601,19 @@ fn compile_unit_metadata(cx: &CrateContext) -> DIDescriptor { } else { match abs_path.path_relative_from(work_dir) { Some(ref p) if p.is_relative() => { - // prepend "./" if necessary - let dotdot = b".."; - let prefix = [dotdot[0], ::std::path::SEP_BYTE]; - let mut path_bytes = p.as_vec().to_vec(); - - if path_bytes.slice_to(2) != prefix && - path_bytes.slice_to(2) != dotdot { - path_bytes.insert(0, prefix[0]); - path_bytes.insert(1, prefix[1]); - } - - path_bytes.to_c_str() + // prepend "./" if necessary + let dotdot = b".."; + let prefix: &[u8] = &[dotdot[0], ::std::path::SEP_BYTE]; + let mut path_bytes = p.as_vec().to_vec(); + + if path_bytes.slice_to(2) != prefix && + path_bytes.slice_to(2) != dotdot { + path_bytes.insert(0, prefix[0]); + path_bytes.insert(1, prefix[1]); } + + CString::from_vec(path_bytes) + } _ => fallback_path(cx) } } @@ -1630,29 +1625,25 @@ fn compile_unit_metadata(cx: &CrateContext) -> DIDescriptor { (option_env!("CFG_VERSION")).expect("CFG_VERSION")); let compile_unit_name = compile_unit_name.as_ptr(); - return work_dir.as_vec().with_c_str(|work_dir| { - producer.with_c_str(|producer| { - "".with_c_str(|flags| { - "".with_c_str(|split_name| { - unsafe { - llvm::LLVMDIBuilderCreateCompileUnit( - debug_context(cx).builder, - DW_LANG_RUST, - compile_unit_name, - work_dir, - producer, - cx.sess().opts.optimize != config::No, - flags, - 0, - split_name) - } - }) - }) - }) - }); + let work_dir = CString::from_slice(work_dir.as_vec()); + let producer = CString::from_slice(producer.as_bytes()); + let flags = "\0"; + let split_name = "\0"; + return unsafe { + llvm::LLVMDIBuilderCreateCompileUnit( + debug_context(cx).builder, + DW_LANG_RUST, + compile_unit_name, + work_dir.as_ptr(), + producer.as_ptr(), + cx.sess().opts.optimize != config::No, + flags.as_ptr() as *const _, + 0, + split_name.as_ptr() as *const _) + }; fn fallback_path(cx: &CrateContext) -> CString { - cx.link_meta().crate_name.to_c_str() + CString::from_slice(cx.link_meta().crate_name.as_bytes()) } } @@ -1678,42 +1669,41 @@ fn declare_local<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, CapturedVariable => (0, DW_TAG_auto_variable) }; - let (var_alloca, var_metadata) = name.get().with_c_str(|name| { - match variable_access { - DirectVariable { alloca } => ( - alloca, - unsafe { - llvm::LLVMDIBuilderCreateLocalVariable( - DIB(cx), - dwarf_tag, - scope_metadata, - name, - file_metadata, - loc.line as c_uint, - type_metadata, - cx.sess().opts.optimize != config::No, - 0, - argument_index) - } - ), - IndirectVariable { alloca, address_operations } => ( - alloca, - unsafe { - llvm::LLVMDIBuilderCreateComplexVariable( - DIB(cx), - dwarf_tag, - scope_metadata, - name, - file_metadata, - loc.line as c_uint, - type_metadata, - address_operations.as_ptr(), - address_operations.len() as c_uint, - argument_index) - } - ) - } - }); + let name = CString::from_slice(name.get().as_bytes()); + let (var_alloca, var_metadata) = match variable_access { + DirectVariable { alloca } => ( + alloca, + unsafe { + llvm::LLVMDIBuilderCreateLocalVariable( + DIB(cx), + dwarf_tag, + scope_metadata, + name.as_ptr(), + file_metadata, + loc.line as c_uint, + type_metadata, + cx.sess().opts.optimize != config::No, + 0, + argument_index) + } + ), + IndirectVariable { alloca, address_operations } => ( + alloca, + unsafe { + llvm::LLVMDIBuilderCreateComplexVariable( + DIB(cx), + dwarf_tag, + scope_metadata, + name.as_ptr(), + file_metadata, + loc.line as c_uint, + type_metadata, + address_operations.as_ptr(), + address_operations.len() as c_uint, + argument_index) + } + ) + }; set_debug_location(cx, DebugLocation::new(scope_metadata, loc.line, @@ -1758,14 +1748,12 @@ fn file_metadata(cx: &CrateContext, full_path: &str) -> DIFile { full_path }; - let file_metadata = - file_name.with_c_str(|file_name| { - work_dir.with_c_str(|work_dir| { - unsafe { - llvm::LLVMDIBuilderCreateFile(DIB(cx), file_name, work_dir) - } - }) - }); + let file_name = CString::from_slice(file_name.as_bytes()); + let work_dir = CString::from_slice(work_dir.as_bytes()); + let file_metadata = unsafe { + llvm::LLVMDIBuilderCreateFile(DIB(cx), file_name.as_ptr(), + work_dir.as_ptr()) + }; let mut created_files = debug_context(cx).created_files.borrow_mut(); created_files.insert(full_path.to_string(), file_metadata); @@ -1793,16 +1781,14 @@ fn scope_metadata(fcx: &FunctionContext, } fn diverging_type_metadata(cx: &CrateContext) -> DIType { - "!".with_c_str(|name| { - unsafe { - llvm::LLVMDIBuilderCreateBasicType( - DIB(cx), - name, - bytes_to_bits(0), - bytes_to_bits(0), - DW_ATE_unsigned) - } - }) + unsafe { + llvm::LLVMDIBuilderCreateBasicType( + DIB(cx), + "!\0".as_ptr() as *const _, + bytes_to_bits(0), + bytes_to_bits(0), + DW_ATE_unsigned) + } } fn basic_type_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, @@ -1838,16 +1824,15 @@ fn basic_type_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, let llvm_type = type_of::type_of(cx, t); let (size, align) = size_and_align_of(cx, llvm_type); - let ty_metadata = name.with_c_str(|name| { - unsafe { - llvm::LLVMDIBuilderCreateBasicType( - DIB(cx), - name, - bytes_to_bits(size), - bytes_to_bits(align), - encoding) - } - }); + let name = CString::from_slice(name.as_bytes()); + let ty_metadata = unsafe { + llvm::LLVMDIBuilderCreateBasicType( + DIB(cx), + name.as_ptr(), + bytes_to_bits(size), + bytes_to_bits(align), + encoding) + }; return ty_metadata; } @@ -1859,16 +1844,15 @@ fn pointer_type_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, let pointer_llvm_type = type_of::type_of(cx, pointer_type); let (pointer_size, pointer_align) = size_and_align_of(cx, pointer_llvm_type); let name = compute_debuginfo_type_name(cx, pointer_type, false); - let ptr_metadata = name.with_c_str(|name| { - unsafe { - llvm::LLVMDIBuilderCreatePointerType( - DIB(cx), - pointee_type_metadata, - bytes_to_bits(pointer_size), - bytes_to_bits(pointer_align), - name) - } - }); + let name = CString::from_slice(name.as_bytes()); + let ptr_metadata = unsafe { + llvm::LLVMDIBuilderCreatePointerType( + DIB(cx), + pointee_type_metadata, + bytes_to_bits(pointer_size), + bytes_to_bits(pointer_align), + name.as_ptr()) + }; return ptr_metadata; } @@ -2478,14 +2462,14 @@ fn prepare_enum_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, let enumerators_metadata: Vec = variants .iter() .map(|v| { - token::get_name(v.name).get().with_c_str(|name| { - unsafe { - llvm::LLVMDIBuilderCreateEnumerator( - DIB(cx), - name, - v.disr_val as u64) - } - }) + let token = token::get_name(v.name); + let name = CString::from_slice(token.get().as_bytes()); + unsafe { + llvm::LLVMDIBuilderCreateEnumerator( + DIB(cx), + name.as_ptr(), + v.disr_val as u64) + } }) .collect(); @@ -2509,20 +2493,19 @@ fn prepare_enum_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, codemap::DUMMY_SP); let discriminant_name = get_enum_discriminant_name(cx, enum_def_id); - let discriminant_type_metadata = discriminant_name.get().with_c_str(|name| { - unsafe { - llvm::LLVMDIBuilderCreateEnumerationType( - DIB(cx), - containing_scope, - name, - UNKNOWN_FILE_METADATA, - UNKNOWN_LINE_NUMBER, - bytes_to_bits(discriminant_size), - bytes_to_bits(discriminant_align), - create_DIArray(DIB(cx), enumerators_metadata[]), - discriminant_base_type_metadata) - } - }); + let name = CString::from_slice(discriminant_name.get().as_bytes()); + let discriminant_type_metadata = unsafe { + llvm::LLVMDIBuilderCreateEnumerationType( + DIB(cx), + containing_scope, + name.as_ptr(), + UNKNOWN_FILE_METADATA, + UNKNOWN_LINE_NUMBER, + bytes_to_bits(discriminant_size), + bytes_to_bits(discriminant_align), + create_DIArray(DIB(cx), enumerators_metadata.as_slice()), + discriminant_base_type_metadata) + }; debug_context(cx).created_enum_disr_types .borrow_mut() @@ -2553,24 +2536,22 @@ fn prepare_enum_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, .borrow() .get_unique_type_id_as_string(unique_type_id); - let enum_metadata = enum_name.with_c_str(|enum_name| { - unique_type_id_str.with_c_str(|unique_type_id_str| { - unsafe { - llvm::LLVMDIBuilderCreateUnionType( - DIB(cx), - containing_scope, - enum_name, - UNKNOWN_FILE_METADATA, - UNKNOWN_LINE_NUMBER, - bytes_to_bits(enum_type_size), - bytes_to_bits(enum_type_align), - 0, // Flags - ptr::null_mut(), - 0, // RuntimeLang - unique_type_id_str) - } - }) - }); + let enum_name = CString::from_slice(enum_name.as_bytes()); + let unique_type_id_str = CString::from_slice(unique_type_id_str.as_bytes()); + let enum_metadata = unsafe { + llvm::LLVMDIBuilderCreateUnionType( + DIB(cx), + containing_scope, + enum_name.as_ptr(), + UNKNOWN_FILE_METADATA, + UNKNOWN_LINE_NUMBER, + bytes_to_bits(enum_type_size), + bytes_to_bits(enum_type_align), + 0, // Flags + ptr::null_mut(), + 0, // RuntimeLang + unique_type_id_str.as_ptr()) + }; return create_and_register_recursive_type_forward_declaration( cx, @@ -2681,21 +2662,20 @@ fn set_members_of_composite_type(cx: &CrateContext, ComputedMemberOffset => machine::llelement_offset(cx, composite_llvm_type, i) }; - member_description.name.with_c_str(|member_name| { - unsafe { - llvm::LLVMDIBuilderCreateMemberType( - DIB(cx), - composite_type_metadata, - member_name, - UNKNOWN_FILE_METADATA, - UNKNOWN_LINE_NUMBER, - bytes_to_bits(member_size), - bytes_to_bits(member_align), - bytes_to_bits(member_offset), - member_description.flags, - member_description.type_metadata) - } - }) + let member_name = CString::from_slice(member_description.name.as_bytes()); + unsafe { + llvm::LLVMDIBuilderCreateMemberType( + DIB(cx), + composite_type_metadata, + member_name.as_ptr(), + UNKNOWN_FILE_METADATA, + UNKNOWN_LINE_NUMBER, + bytes_to_bits(member_size), + bytes_to_bits(member_align), + bytes_to_bits(member_offset), + member_description.flags, + member_description.type_metadata) + } }) .collect(); @@ -2719,30 +2699,28 @@ fn create_struct_stub(cx: &CrateContext, let unique_type_id_str = debug_context(cx).type_map .borrow() .get_unique_type_id_as_string(unique_type_id); + let name = CString::from_slice(struct_type_name.as_bytes()); + let unique_type_id = CString::from_slice(unique_type_id_str.as_bytes()); let metadata_stub = unsafe { - struct_type_name.with_c_str(|name| { - unique_type_id_str.with_c_str(|unique_type_id| { - // LLVMDIBuilderCreateStructType() wants an empty array. A null - // pointer will lead to hard to trace and debug LLVM assertions - // later on in llvm/lib/IR/Value.cpp. - let empty_array = create_DIArray(DIB(cx), &[]); - - llvm::LLVMDIBuilderCreateStructType( - DIB(cx), - containing_scope, - name, - UNKNOWN_FILE_METADATA, - UNKNOWN_LINE_NUMBER, - bytes_to_bits(struct_size), - bytes_to_bits(struct_align), - 0, - ptr::null_mut(), - empty_array, - 0, - ptr::null_mut(), - unique_type_id) - }) - }) + // LLVMDIBuilderCreateStructType() wants an empty array. A null + // pointer will lead to hard to trace and debug LLVM assertions + // later on in llvm/lib/IR/Value.cpp. + let empty_array = create_DIArray(DIB(cx), &[]); + + llvm::LLVMDIBuilderCreateStructType( + DIB(cx), + containing_scope, + name.as_ptr(), + UNKNOWN_FILE_METADATA, + UNKNOWN_LINE_NUMBER, + bytes_to_bits(struct_size), + bytes_to_bits(struct_align), + 0, + ptr::null_mut(), + empty_array, + 0, + ptr::null_mut(), + unique_type_id.as_ptr()) }; return metadata_stub; @@ -3472,7 +3450,7 @@ fn create_scope_map(cx: &CrateContext, } } - ast::PatBox(ref sub_pat) | ast::PatRegion(ref sub_pat) => { + ast::PatBox(ref sub_pat) | ast::PatRegion(ref sub_pat, _) => { scope_map.insert(pat.id, scope_stack.last().unwrap().scope_metadata); walk_pattern(cx, &**sub_pat, scope_stack, scope_map); } @@ -4079,18 +4057,18 @@ fn namespace_for_item(cx: &CrateContext, def_id: ast::DefId) -> Rc ptr::null_mut() }; let namespace_name = token::get_name(name); - let scope = namespace_name.get().with_c_str(|namespace_name| { - unsafe { - llvm::LLVMDIBuilderCreateNameSpace( - DIB(cx), - parent_scope, - namespace_name, - // cannot reconstruct file ... - ptr::null_mut(), - // ... or line information, but that's not so important. - 0) - } - }); + let namespace_name = CString::from_slice(namespace_name + .get().as_bytes()); + let scope = unsafe { + llvm::LLVMDIBuilderCreateNameSpace( + DIB(cx), + parent_scope, + namespace_name.as_ptr(), + // cannot reconstruct file ... + ptr::null_mut(), + // ... or line information, but that's not so important. + 0) + }; let node = Rc::new(NamespaceTreeNode { name: name, @@ -4128,7 +4106,7 @@ fn namespace_for_item(cx: &CrateContext, def_id: ast::DefId) -> Rc llvm::ValueRef { - let section_var_name = b"__rustc_debug_gdb_scripts_section__".to_c_str(); + let section_var_name = b"__rustc_debug_gdb_scripts_section__\0"; let section_var = unsafe { - llvm::LLVMGetNamedGlobal(ccx.llmod(), section_var_name.as_ptr()) + llvm::LLVMGetNamedGlobal(ccx.llmod(), + section_var_name.as_ptr() as *const _) }; if section_var == ptr::null_mut() { - let section_name = b".debug_gdb_scripts".to_c_str(); + let section_name = b".debug_gdb_scripts\0"; let section_contents = b"\x01gdb_load_rust_pretty_printers.py\0"; unsafe { @@ -4160,8 +4139,9 @@ fn get_or_insert_gdb_debug_scripts_section_global(ccx: &CrateContext) section_contents.len() as u64); let section_var = llvm::LLVMAddGlobal(ccx.llmod(), llvm_type.to_ref(), - section_var_name.as_ptr()); - llvm::LLVMSetSection(section_var, section_name.as_ptr()); + section_var_name.as_ptr() + as *const _); + llvm::LLVMSetSection(section_var, section_name.as_ptr() as *const _); llvm::LLVMSetInitializer(section_var, C_bytes(ccx, section_contents)); llvm::LLVMSetGlobalConstant(section_var, llvm::True); llvm::LLVMSetUnnamedAddr(section_var, llvm::True); diff --git a/src/librustc_trans/trans/foreign.rs b/src/librustc_trans/trans/foreign.rs index a4cfec791d817..1c9be6ae4a8ba 100644 --- a/src/librustc_trans/trans/foreign.rs +++ b/src/librustc_trans/trans/foreign.rs @@ -24,9 +24,10 @@ use trans::type_::Type; use trans::type_of::*; use trans::type_of; use middle::ty::{self, Ty}; -use middle::subst::{Substs}; +use middle::subst::Substs; + +use std::ffi::CString; use std::cmp; -use std::c_str::ToCStr; use libc::c_uint; use syntax::abi::{Cdecl, Aapcs, C, Win64, Abi}; use syntax::abi::{RustIntrinsic, Rust, RustCall, Stdcall, Fastcall, System}; @@ -132,9 +133,9 @@ pub fn register_static(ccx: &CrateContext, }; unsafe { // Declare a symbol `foo` with the desired linkage. - let g1 = ident.get().with_c_str(|buf| { - llvm::LLVMAddGlobal(ccx.llmod(), llty2.to_ref(), buf) - }); + let buf = CString::from_slice(ident.get().as_bytes()); + let g1 = llvm::LLVMAddGlobal(ccx.llmod(), llty2.to_ref(), + buf.as_ptr()); llvm::SetLinkage(g1, linkage); // Declare an internal global `extern_with_linkage_foo` which @@ -145,9 +146,9 @@ pub fn register_static(ccx: &CrateContext, // zero. let mut real_name = "_rust_extern_with_linkage_".to_string(); real_name.push_str(ident.get()); - let g2 = real_name.with_c_str(|buf| { - llvm::LLVMAddGlobal(ccx.llmod(), llty.to_ref(), buf) - }); + let real_name = CString::from_vec(real_name.into_bytes()); + let g2 = llvm::LLVMAddGlobal(ccx.llmod(), llty.to_ref(), + real_name.as_ptr()); llvm::SetLinkage(g2, llvm::InternalLinkage); llvm::LLVMSetInitializer(g2, g1); g2 @@ -155,9 +156,8 @@ pub fn register_static(ccx: &CrateContext, } None => unsafe { // Generate an external declaration. - ident.get().with_c_str(|buf| { - llvm::LLVMAddGlobal(ccx.llmod(), llty.to_ref(), buf) - }) + let buf = CString::from_slice(ident.get().as_bytes()); + llvm::LLVMAddGlobal(ccx.llmod(), llty.to_ref(), buf.as_ptr()) } } } @@ -606,9 +606,9 @@ pub fn trans_rust_fn_with_foreign_abi<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, // return r; // } - let the_block = - "the block".with_c_str( - |s| llvm::LLVMAppendBasicBlockInContext(ccx.llcx(), llwrapfn, s)); + let ptr = "the block\0".as_ptr(); + let the_block = llvm::LLVMAppendBasicBlockInContext(ccx.llcx(), llwrapfn, + ptr as *const _); let builder = ccx.builder(); builder.position_at_end(the_block); diff --git a/src/librustc_trans/trans/glue.rs b/src/librustc_trans/trans/glue.rs index c049704181354..2525220c57021 100644 --- a/src/librustc_trans/trans/glue.rs +++ b/src/librustc_trans/trans/glue.rs @@ -40,8 +40,8 @@ use util::ppaux::{ty_to_short_str, Repr}; use util::ppaux; use arena::TypedArena; -use std::c_str::ToCStr; use libc::c_uint; +use std::ffi::CString; use syntax::ast; use syntax::parse::token; @@ -498,11 +498,11 @@ pub fn declare_tydesc<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) let llalign = llalign_of(ccx, llty); let name = mangle_internal_name_by_type_and_seq(ccx, t, "tydesc"); debug!("+++ declare_tydesc {} {}", ppaux::ty_to_string(ccx.tcx(), t), name); - let gvar = name.with_c_str(|buf| { - unsafe { - llvm::LLVMAddGlobal(ccx.llmod(), ccx.tydesc_type().to_ref(), buf) - } - }); + let buf = CString::from_slice(name.as_bytes()); + let gvar = unsafe { + llvm::LLVMAddGlobal(ccx.llmod(), ccx.tydesc_type().to_ref(), + buf.as_ptr()) + }; note_unique_llvm_symbol(ccx, name); let ty_name = token::intern_and_get_ident( diff --git a/src/librustc_trans/trans/llrepr.rs b/src/librustc_trans/trans/llrepr.rs index dcf3a53215788..de0f714276d0d 100644 --- a/src/librustc_trans/trans/llrepr.rs +++ b/src/librustc_trans/trans/llrepr.rs @@ -12,7 +12,7 @@ use trans::context::CrateContext; use trans::type_::Type; use llvm::ValueRef; -pub trait LlvmRepr for Sized? { +pub trait LlvmRepr { fn llrepr(&self, ccx: &CrateContext) -> String; } diff --git a/src/librustc_trans/trans/meth.rs b/src/librustc_trans/trans/meth.rs index c13516134c20c..dec4524e67665 100644 --- a/src/librustc_trans/trans/meth.rs +++ b/src/librustc_trans/trans/meth.rs @@ -34,7 +34,7 @@ use middle::ty::{self, Ty}; use middle::ty::MethodCall; use util::ppaux::Repr; -use std::c_str::ToCStr; +use std::ffi::CString; use std::rc::Rc; use syntax::abi::{Rust, RustCall}; use syntax::parse::token; @@ -742,9 +742,9 @@ pub fn make_vtable>(ccx: &CrateContext, unsafe { let tbl = C_struct(ccx, components[], false); let sym = token::gensym("vtable"); - let vt_gvar = format!("vtable{}", sym.uint()).with_c_str(|buf| { - llvm::LLVMAddGlobal(ccx.llmod(), val_ty(tbl).to_ref(), buf) - }); + let buf = CString::from_vec(format!("vtable{}", sym.uint()).into_bytes()); + let vt_gvar = llvm::LLVMAddGlobal(ccx.llmod(), val_ty(tbl).to_ref(), + buf.as_ptr()); llvm::LLVMSetInitializer(vt_gvar, tbl); llvm::LLVMSetGlobalConstant(vt_gvar, llvm::True); llvm::SetLinkage(vt_gvar, llvm::InternalLinkage); diff --git a/src/librustc_trans/trans/type_.rs b/src/librustc_trans/trans/type_.rs index 5b76f5bb8270e..3785c2fb9bc54 100644 --- a/src/librustc_trans/trans/type_.rs +++ b/src/librustc_trans/trans/type_.rs @@ -19,7 +19,7 @@ use util::nodemap::FnvHashMap; use syntax::ast; -use std::c_str::ToCStr; +use std::ffi::CString; use std::mem; use std::cell::RefCell; use std::iter::repeat; @@ -157,7 +157,8 @@ impl Type { } pub fn named_struct(ccx: &CrateContext, name: &str) -> Type { - ty!(name.with_c_str(|s| llvm::LLVMStructCreateNamed(ccx.llcx(), s))) + let name = CString::from_slice(name.as_bytes()); + ty!(llvm::LLVMStructCreateNamed(ccx.llcx(), name.as_ptr())) } pub fn empty_struct(ccx: &CrateContext) -> Type { diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index 56cf4acc184e5..2b55aefc99999 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -30,7 +30,9 @@ use syntax::print::pprust; use syntax::ptr::P; pub fn check_pat<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, - pat: &ast::Pat, expected: Ty<'tcx>) { + pat: &ast::Pat, + expected: Ty<'tcx>) +{ let fcx = pcx.fcx; let tcx = pcx.fcx.ccx.tcx; @@ -46,6 +48,19 @@ pub fn check_pat<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, check_expr(fcx, &**lt); let expr_ty = fcx.expr_ty(&**lt); fcx.write_ty(pat.id, expr_ty); + + // somewhat surprising: in this case, the subtyping + // relation goes the opposite way as the other + // cases. Actually what we really want is not a subtyping + // relation at all but rather that there exists a LUB (so + // that they can be compared). However, in practice, + // constants are always scalars or strings. For scalars + // subtyping is irrelevant, and for strings `expr_ty` is + // type is `&'static str`, so if we say that + // + // &'static str <: expected + // + // that's equivalent to there existing a LUB. demand::suptype(fcx, pat.span, expected, expr_ty); } ast::PatRange(ref begin, ref end) => { @@ -54,10 +69,16 @@ pub fn check_pat<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, let lhs_ty = fcx.expr_ty(&**begin); let rhs_ty = fcx.expr_ty(&**end); - if require_same_types( - tcx, Some(fcx.infcx()), false, pat.span, lhs_ty, rhs_ty, - || "mismatched types in range".to_string()) - && (ty::type_is_numeric(lhs_ty) || ty::type_is_char(rhs_ty)) { + + let lhs_eq_rhs = + require_same_types( + tcx, Some(fcx.infcx()), false, pat.span, lhs_ty, rhs_ty, + || "mismatched types in range".to_string()); + + let numeric_or_char = + lhs_eq_rhs && (ty::type_is_numeric(lhs_ty) || ty::type_is_char(lhs_ty)); + + if numeric_or_char { match valid_range_bounds(fcx.ccx, &**begin, &**end) { Some(false) => { span_err!(tcx.sess, begin.span, E0030, @@ -71,17 +92,29 @@ pub fn check_pat<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, } } else { span_err!(tcx.sess, begin.span, E0029, - "only char and numeric types are allowed in range"); + "only char and numeric types are allowed in range"); } fcx.write_ty(pat.id, lhs_ty); + + // subtyping doens't matter here, as the value is some kind of scalar demand::eqtype(fcx, pat.span, expected, lhs_ty); } ast::PatEnum(..) | ast::PatIdent(..) if pat_is_const(&tcx.def_map, pat) => { let const_did = tcx.def_map.borrow()[pat.id].clone().def_id(); let const_scheme = ty::lookup_item_type(tcx, const_did); - fcx.write_ty(pat.id, const_scheme.ty); - demand::suptype(fcx, pat.span, expected, const_scheme.ty); + assert!(const_scheme.generics.is_empty()); + let const_ty = pcx.fcx.instantiate_type_scheme(pat.span, + &Substs::empty(), + &const_scheme.ty); + fcx.write_ty(pat.id, const_ty); + + // FIXME(#20489) -- we should limit the types here to scalars or something! + + // As with PatLit, what we really want here is that there + // exist a LUB, but for the cases that can occur, subtype + // is good enough. + demand::suptype(fcx, pat.span, expected, const_ty); } ast::PatIdent(bm, ref path, ref sub) if pat_is_binding(&tcx.def_map, pat) => { let typ = fcx.local_ty(pat.span, pat.id); @@ -89,20 +122,29 @@ pub fn check_pat<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, ast::BindByRef(mutbl) => { // if the binding is like // ref x | ref const x | ref mut x - // then the type of x is &M T where M is the mutability - // and T is the expected type + // then `x` is assigned a value of type `&M T` where M is the mutability + // and T is the expected type. let region_var = fcx.infcx().next_region_var(infer::PatternRegion(pat.span)); let mt = ty::mt { ty: expected, mutbl: mutbl }; let region_ty = ty::mk_rptr(tcx, tcx.mk_region(region_var), mt); + + // `x` is assigned a value of type `&M T`, hence `&M T <: typeof(x)` is + // required. However, we use equality, which is stronger. See (*) for + // an explanation. demand::eqtype(fcx, pat.span, region_ty, typ); } // otherwise the type of x is the expected type T ast::BindByValue(_) => { + // As above, `T <: typeof(x)` is required but we + // use equality, see (*) below. demand::eqtype(fcx, pat.span, expected, typ); } } + fcx.write_ty(pat.id, typ); + // if there are multiple arms, make sure they all agree on + // what the type of the binding `x` ought to be let canon_id = pcx.map[path.node]; if canon_id != pat.id { let ct = fcx.local_ty(pat.span, canon_id); @@ -124,8 +166,9 @@ pub fn check_pat<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, check_pat_struct(pcx, pat, path, fields.as_slice(), etc, expected); } ast::PatTup(ref elements) => { - let element_tys: Vec<_> = range(0, elements.len()).map(|_| fcx.infcx() - .next_ty_var()).collect(); + let element_tys: Vec<_> = + range(0, elements.len()).map(|_| fcx.infcx().next_ty_var()) + .collect(); let pat_ty = ty::mk_tup(tcx, element_tys.clone()); fcx.write_ty(pat.id, pat_ty); demand::eqtype(fcx, pat.span, expected, pat_ty); @@ -138,7 +181,10 @@ pub fn check_pat<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, let uniq_ty = ty::mk_uniq(tcx, inner_ty); if check_dereferencable(pcx, pat.span, expected, &**inner) { - demand::suptype(fcx, pat.span, expected, uniq_ty); + // Here, `demand::subtype` is good enough, but I don't + // think any errors can be introduced by using + // `demand::eqtype`. + demand::eqtype(fcx, pat.span, expected, uniq_ty); fcx.write_ty(pat.id, uniq_ty); check_pat(pcx, &**inner, inner_ty); } else { @@ -146,19 +192,26 @@ pub fn check_pat<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, check_pat(pcx, &**inner, tcx.types.err); } } - ast::PatRegion(ref inner) => { + ast::PatRegion(ref inner, mutbl) => { let inner_ty = fcx.infcx().next_ty_var(); - let mutbl = + // SNAP c894171 remove this `if`-`else` entirely after next snapshot + let mutbl = if mutbl == ast::MutImmutable { ty::deref(fcx.infcx().shallow_resolve(expected), true) - .map_or(ast::MutImmutable, |mt| mt.mutbl); + .map(|mt| mt.mutbl).unwrap_or(ast::MutImmutable) + } else { + mutbl + }; let mt = ty::mt { ty: inner_ty, mutbl: mutbl }; let region = fcx.infcx().next_region_var(infer::PatternRegion(pat.span)); let rptr_ty = ty::mk_rptr(tcx, tcx.mk_region(region), mt); if check_dereferencable(pcx, pat.span, expected, &**inner) { - demand::suptype(fcx, pat.span, expected, rptr_ty); + // `demand::subtype` would be good enough, but using + // `eqtype` turns out to be equally general. See (*) + // below for details. + demand::eqtype(fcx, pat.span, expected, rptr_ty); fcx.write_ty(pat.id, rptr_ty); check_pat(pcx, &**inner, inner_ty); } else { @@ -181,14 +234,18 @@ pub fn check_pat<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, let region = fcx.infcx().next_region_var(infer::PatternRegion(pat.span)); ty::mk_slice(tcx, tcx.mk_region(region), ty::mt { ty: inner_ty, - mutbl: ty::deref(expected_ty, true) - .map_or(ast::MutImmutable, |mt| mt.mutbl) + mutbl: ty::deref(expected_ty, true).map(|mt| mt.mutbl) + .unwrap_or(ast::MutImmutable) }) } }; fcx.write_ty(pat.id, pat_ty); - demand::suptype(fcx, pat.span, expected, pat_ty); + + // `demand::subtype` would be good enough, but using + // `eqtype` turns out to be equally general. See (*) + // below for details. + demand::eqtype(fcx, pat.span, expected, pat_ty); for elt in before.iter() { check_pat(pcx, &**elt, inner_ty); @@ -210,6 +267,56 @@ pub fn check_pat<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, } ast::PatMac(_) => tcx.sess.bug("unexpanded macro") } + + + // (*) In most of the cases above (literals and constants being + // the exception), we relate types using strict equality, evewn + // though subtyping would be sufficient. There are a few reasons + // for this, some of which are fairly subtle and which cost me + // (nmatsakis) an hour or two debugging to remember, so I thought + // I'd write them down this time. + // + // 1. Most importantly, there is no loss of expressiveness + // here. What we are saying is that the type of `x` + // becomes *exactly* what is expected. This might seem + // like it will cause errors in a case like this: + // + // ``` + // fn foo<'x>(x: &'x int) { + // let a = 1; + // let mut z = x; + // z = &a; + // } + // ``` + // + // The reason we might get an error is that `z` might be + // assigned a type like `&'x int`, and then we would have + // a problem when we try to assign `&a` to `z`, because + // the lifetime of `&a` (i.e., the enclosing block) is + // shorter than `'x`. + // + // HOWEVER, this code works fine. The reason is that the + // expected type here is whatever type the user wrote, not + // the initializer's type. In this case the user wrote + // nothing, so we are going to create a type variable `Z`. + // Then we will assign the type of the initializer (`&'x + // int`) as a subtype of `Z`: `&'x int <: Z`. And hence we + // will instantiate `Z` as a type `&'0 int` where `'0` is + // a fresh region variable, with the constraint that `'x : + // '0`. So basically we're all set. + // + // Note that there are two tests to check that this remains true + // (`regions-reassign-{match,let}-bound-pointer.rs`). + // + // 2. Things go horribly wrong if we use subtype. The reason for + // THIS is a fairly subtle case involving bound regions. See the + // `givens` field in `region_inference`, as well as the test + // `regions-relate-bound-regions-on-closures-to-inference-variables.rs`, + // for details. Short version is that we must sometimes detect + // relationships between specific region variables and regions + // bound in a closure signature, and that detection gets thrown + // off when we substitute fresh region variables here to enable + // subtyping. } pub fn check_dereferencable<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, diff --git a/src/librustc_typeck/check/callee.rs b/src/librustc_typeck/check/callee.rs index 153c6463fbebb..0bc76e1baab84 100644 --- a/src/librustc_typeck/check/callee.rs +++ b/src/librustc_typeck/check/callee.rs @@ -22,7 +22,7 @@ use super::TupleArgumentsFlag; use super::write_call; use middle::infer; -use middle::ty::{mod, Ty}; +use middle::ty::{self, Ty}; use syntax::ast; use syntax::codemap::Span; use syntax::parse::token; diff --git a/src/librustc_typeck/check/demand.rs b/src/librustc_typeck/check/demand.rs index 5b586bb0b669a..a51e89c1669de 100644 --- a/src/librustc_typeck/check/demand.rs +++ b/src/librustc_typeck/check/demand.rs @@ -18,14 +18,15 @@ use syntax::ast; use syntax::codemap::Span; use util::ppaux::Repr; -// Requires that the two types unify, and prints an error message if they -// don't. +// Requires that the two types unify, and prints an error message if +// they don't. pub fn suptype<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, sp: Span, - expected: Ty<'tcx>, actual: Ty<'tcx>) { - suptype_with_fn(fcx, sp, false, expected, actual, + ty_expected: Ty<'tcx>, ty_actual: Ty<'tcx>) { + suptype_with_fn(fcx, sp, false, ty_expected, ty_actual, |sp, e, a, s| { fcx.report_mismatched_types(sp, e, a, s) }) } +/// As `suptype`, but call `handle_err` if unification for subtyping fails. pub fn suptype_with_fn<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, sp: Span, b_is_expected: bool, @@ -48,9 +49,7 @@ pub fn eqtype<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, sp: Span, expected: Ty<'tcx>, actual: Ty<'tcx>) { match infer::mk_eqty(fcx.infcx(), false, infer::Misc(sp), actual, expected) { Ok(()) => { /* ok */ } - Err(ref err) => { - fcx.report_mismatched_types(sp, expected, actual, err); - } + Err(ref err) => { fcx.report_mismatched_types(sp, expected, actual, err); } } } diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 854de82351183..d4da0dcfad0a3 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -4555,7 +4555,7 @@ impl<'tcx> Repr<'tcx> for Expectation<'tcx> { pub fn check_decl_initializer(fcx: &FnCtxt, nid: ast::NodeId, init: &ast::Expr) - { +{ let local_ty = fcx.local_ty(init.span, nid); check_expr_coercable_to_type(fcx, init, local_ty) } diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 5f6c62f1d7a68..8df44bf404d3c 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -2234,7 +2234,7 @@ fn name_from_pat(p: &ast::Pat) -> String { PatTup(ref elts) => format!("({})", elts.iter().map(|p| name_from_pat(&**p)) .collect::>().connect(", ")), PatBox(ref p) => name_from_pat(&**p), - PatRegion(ref p) => name_from_pat(&**p), + PatRegion(ref p, _) => name_from_pat(&**p), PatLit(..) => { warn!("tried to get argument name from PatLit, \ which is silly in function arguments"); diff --git a/src/librustdoc/flock.rs b/src/librustdoc/flock.rs index 0f0dbf6a24dff..dcc90117d2660 100644 --- a/src/librustdoc/flock.rs +++ b/src/librustdoc/flock.rs @@ -20,8 +20,8 @@ pub use self::imp::Lock; #[cfg(unix)] mod imp { + use std::ffi::CString; use libc; - use std::c_str::ToCStr; #[cfg(target_os = "linux")] mod os { @@ -111,9 +111,11 @@ mod imp { impl Lock { pub fn new(p: &Path) -> Lock { - let fd = p.with_c_str(|s| unsafe { - libc::open(s, libc::O_RDWR | libc::O_CREAT, libc::S_IRWXU) - }); + let buf = CString::from_slice(p.as_vec()); + let fd = unsafe { + libc::open(buf.as_ptr(), libc::O_RDWR | libc::O_CREAT, + libc::S_IRWXU) + }; assert!(fd > 0); let flock = os::flock { l_start: 0, diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index 9d003eca27f3d..3b9265cf56976 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -29,7 +29,7 @@ use libc; use std::ascii::AsciiExt; -use std::c_str::ToCStr; +use std::ffi::CString; use std::cell::{RefCell, Cell}; use std::collections::HashMap; use std::fmt; @@ -215,7 +215,7 @@ pub fn render(w: &mut fmt::Formatter, s: &str, print_toc: bool) -> fmt::Result { let id = id.as_ref().map(|a| a.as_slice()); s.push_str(highlight::highlight(text.as_slice(), None, id) .as_slice()); - let output = s.to_c_str(); + let output = CString::from_vec(s.into_bytes()); hoedown_buffer_puts(ob, output.as_ptr()); }) } @@ -224,15 +224,16 @@ pub fn render(w: &mut fmt::Formatter, s: &str, print_toc: bool) -> fmt::Result { extern fn header(ob: *mut hoedown_buffer, text: *const hoedown_buffer, level: libc::c_int, opaque: *mut libc::c_void) { // hoedown does this, we may as well too - "\n".with_c_str(|p| unsafe { hoedown_buffer_puts(ob, p) }); + unsafe { hoedown_buffer_puts(ob, "\n\0".as_ptr() as *const _); } // Extract the text provided let s = if text.is_null() { "".to_string() } else { - unsafe { - String::from_raw_buf_len((*text).data, (*text).size as uint) - } + let s = unsafe { + slice::from_raw_buf(&(*text).data, (*text).size as uint) + }; + str::from_utf8(s).unwrap().to_string() }; // Transform the contents of the header into a hyphenated string @@ -273,7 +274,8 @@ pub fn render(w: &mut fmt::Formatter, s: &str, print_toc: bool) -> fmt::Result { format!("{} ", sec) }); - text.with_c_str(|p| unsafe { hoedown_buffer_puts(ob, p) }); + let text = CString::from_vec(text.into_bytes()); + unsafe { hoedown_buffer_puts(ob, text.as_ptr()) } } reset_headers(); diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index 3accbbfb1a2e7..ddb14d6944b9d 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -2253,9 +2253,9 @@ impl<'a> fmt::Show for Source<'a> { cols += 1; tmp /= 10; } - try!(write!(fmt, "
"));
+        try!(write!(fmt, "
"));
         for i in range(1, lines + 1) {
-            try!(write!(fmt, "{0:1$}\n", i, cols));
+            try!(write!(fmt, "{0:1$}\n", i, cols));
         }
         try!(write!(fmt, "
")); try!(write!(fmt, "{}", highlight::highlight(s.as_slice(), None, None))); diff --git a/src/librustdoc/html/static/main.css b/src/librustdoc/html/static/main.css index 9d4f341a30e25..a5a4825414109 100644 --- a/src/librustdoc/html/static/main.css +++ b/src/librustdoc/html/static/main.css @@ -157,6 +157,7 @@ nav.sub { left: 0; top: 0; min-height: 100%; + z-index: -1; } .content, nav { max-width: 960px; } @@ -217,10 +218,18 @@ nav.sub { overflow: auto; padding-left: 0; } -.content pre.line-numbers { float: left; border: none; } -.line-numbers span { color: #c67e2d; } +.content pre.line-numbers { + float: left; + border: none; + + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} +.line-numbers span { color: #c67e2d; cursor: pointer; } .line-numbers .line-highlighted { - background-color: #f6fdb0; + background-color: #f6fdb0 !important; } .content .highlighted { @@ -470,6 +479,7 @@ h1 .stability { .summary.Unmarked { background-color: #BBBBBB; } :target { background: #FDFFD3; } +.line-numbers :target { background-color: transparent; } /* Code highlighting */ pre.rust .kw { color: #8959A8; } diff --git a/src/librustdoc/html/static/main.js b/src/librustdoc/html/static/main.js index 978af31cdc689..2d575c226c5d0 100644 --- a/src/librustdoc/html/static/main.js +++ b/src/librustdoc/html/static/main.js @@ -50,7 +50,7 @@ resizeShortBlocks(); $(window).on('resize', resizeShortBlocks); - function highlightSourceLines() { + function highlightSourceLines(ev) { var i, from, to, match = window.location.hash.match(/^#?(\d+)(?:-(\d+))?$/); if (match) { from = parseInt(match[1], 10); @@ -59,14 +59,14 @@ if ($('#' + from).length === 0) { return; } - $('#' + from)[0].scrollIntoView(); + if (ev === null) $('#' + from)[0].scrollIntoView(); $('.line-numbers span').removeClass('line-highlighted'); for (i = from; i <= to; ++i) { $('#' + i).addClass('line-highlighted'); } } } - highlightSourceLines(); + highlightSourceLines(null); $(window).on('hashchange', highlightSourceLines); $(document).on('keyup', function(e) { @@ -778,4 +778,35 @@ $("#main > .docblock").before(wrapper); }); + $('pre.line-numbers').on('click', 'span', function() { + var prev_id = 0; + + function set_fragment(name) { + if (history.replaceState) { + history.replaceState(null, null, '#' + name); + $(window).trigger('hashchange'); + } else { + location.replace('#' + name); + } + } + + return function(ev) { + var cur_id = parseInt(ev.target.id); + + if (ev.shiftKey && prev_id) { + if (prev_id > cur_id) { + var tmp = prev_id; + prev_id = cur_id; + cur_id = tmp; + } + + set_fragment(prev_id + '-' + cur_id); + } else { + prev_id = cur_id; + + set_fragment(cur_id); + } + }; + }()); + }()); diff --git a/src/libserialize/base64.rs b/src/libserialize/base64.rs index 44bf5f8977870..11a49cd712f25 100644 --- a/src/libserialize/base64.rs +++ b/src/libserialize/base64.rs @@ -70,7 +70,7 @@ static URLSAFE_CHARS: &'static[u8] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZ\ 0123456789-_"; /// A trait for converting a value to base64 encoding. -pub trait ToBase64 for Sized? { +pub trait ToBase64 { /// Converts the value of `self` to a base64 value following the specified /// format configuration, returning the owned string. fn to_base64(&self, config: Config) -> String; @@ -170,7 +170,7 @@ impl ToBase64 for [u8] { } /// A trait for converting from base64 encoded values. -pub trait FromBase64 for Sized? { +pub trait FromBase64 { /// Converts the value of `self`, interpreted as base64 encoded data, into /// an owned vector of bytes, returning the vector. fn from_base64(&self) -> Result, FromBase64Error>; diff --git a/src/libserialize/collection_impls.rs b/src/libserialize/collection_impls.rs index f2d79b1334699..7ba329c518e91 100644 --- a/src/libserialize/collection_impls.rs +++ b/src/libserialize/collection_impls.rs @@ -19,11 +19,9 @@ use std::collections::{DList, RingBuf, BTreeMap, BTreeSet, HashMap, HashSet, Vec use collections::enum_set::{EnumSet, CLike}; impl< - E, - S: Encoder, - T: Encodable -> Encodable for DList { - fn encode(&self, s: &mut S) -> Result<(), E> { + T: Encodable +> Encodable for DList { + fn encode(&self, s: &mut S) -> Result<(), S::Error> { s.emit_seq(self.len(), |s| { for (i, e) in self.iter().enumerate() { try!(s.emit_seq_elt(i, |s| e.encode(s))); @@ -33,8 +31,8 @@ impl< } } -impl,T:Decodable> Decodable for DList { - fn decode(d: &mut D) -> Result, E> { +impl Decodable for DList { + fn decode(d: &mut D) -> Result, D::Error> { d.read_seq(|d, len| { let mut list = DList::new(); for i in range(0u, len) { @@ -45,12 +43,8 @@ impl,T:Decodable> Decodable for DList { } } -impl< - E, - S: Encoder, - T: Encodable -> Encodable for RingBuf { - fn encode(&self, s: &mut S) -> Result<(), E> { +impl Encodable for RingBuf { + fn encode(&self, s: &mut S) -> Result<(), S::Error> { s.emit_seq(self.len(), |s| { for (i, e) in self.iter().enumerate() { try!(s.emit_seq_elt(i, |s| e.encode(s))); @@ -60,8 +54,8 @@ impl< } } -impl,T:Decodable> Decodable for RingBuf { - fn decode(d: &mut D) -> Result, E> { +impl Decodable for RingBuf { + fn decode(d: &mut D) -> Result, D::Error> { d.read_seq(|d, len| { let mut deque: RingBuf = RingBuf::new(); for i in range(0u, len) { @@ -73,12 +67,10 @@ impl,T:Decodable> Decodable for RingBuf { } impl< - E, - S: Encoder, - K: Encodable + PartialEq + Ord, - V: Encodable + PartialEq -> Encodable for BTreeMap { - fn encode(&self, e: &mut S) -> Result<(), E> { + K: Encodable + PartialEq + Ord, + V: Encodable + PartialEq +> Encodable for BTreeMap { + fn encode(&self, e: &mut S) -> Result<(), S::Error> { e.emit_map(self.len(), |e| { let mut i = 0; for (key, val) in self.iter() { @@ -92,12 +84,10 @@ impl< } impl< - E, - D: Decoder, - K: Decodable + PartialEq + Ord, - V: Decodable + PartialEq -> Decodable for BTreeMap { - fn decode(d: &mut D) -> Result, E> { + K: Decodable + PartialEq + Ord, + V: Decodable + PartialEq +> Decodable for BTreeMap { + fn decode(d: &mut D) -> Result, D::Error> { d.read_map(|d, len| { let mut map = BTreeMap::new(); for i in range(0u, len) { @@ -111,11 +101,9 @@ impl< } impl< - E, - S: Encoder, - T: Encodable + PartialEq + Ord -> Encodable for BTreeSet { - fn encode(&self, s: &mut S) -> Result<(), E> { + T: Encodable + PartialEq + Ord +> Encodable for BTreeSet { + fn encode(&self, s: &mut S) -> Result<(), S::Error> { s.emit_seq(self.len(), |s| { let mut i = 0; for e in self.iter() { @@ -128,11 +116,9 @@ impl< } impl< - E, - D: Decoder, - T: Decodable + PartialEq + Ord -> Decodable for BTreeSet { - fn decode(d: &mut D) -> Result, E> { + T: Decodable + PartialEq + Ord +> Decodable for BTreeSet { + fn decode(d: &mut D) -> Result, D::Error> { d.read_seq(|d, len| { let mut set = BTreeSet::new(); for i in range(0u, len) { @@ -144,11 +130,9 @@ impl< } impl< - E, - S: Encoder, - T: Encodable + CLike -> Encodable for EnumSet { - fn encode(&self, s: &mut S) -> Result<(), E> { + T: Encodable + CLike +> Encodable for EnumSet { + fn encode(&self, s: &mut S) -> Result<(), S::Error> { let mut bits = 0; for item in self.iter() { bits |= item.to_uint(); @@ -158,11 +142,9 @@ impl< } impl< - E, - D: Decoder, - T: Decodable + CLike -> Decodable for EnumSet { - fn decode(d: &mut D) -> Result, E> { + T: Decodable + CLike +> Decodable for EnumSet { + fn decode(d: &mut D) -> Result, D::Error> { let bits = try!(d.read_uint()); let mut set = EnumSet::new(); for bit in range(0, uint::BITS) { @@ -175,14 +157,12 @@ impl< } impl< - E, - S: Encoder, - K: Encodable + Hash + Eq, - V: Encodable, + K: Encodable + Hash + Eq, + V: Encodable, X, H: Hasher -> Encodable for HashMap { - fn encode(&self, e: &mut S) -> Result<(), E> { +> Encodable for HashMap { + fn encode(&self, e: &mut S) -> Result<(), S::Error> { e.emit_map(self.len(), |e| { let mut i = 0; for (key, val) in self.iter() { @@ -196,14 +176,12 @@ impl< } impl< - E, - D: Decoder, - K: Decodable + Hash + Eq, - V: Decodable, + K: Decodable + Hash + Eq, + V: Decodable, S, H: Hasher + Default -> Decodable for HashMap { - fn decode(d: &mut D) -> Result, E> { +> Decodable for HashMap { + fn decode(d: &mut D) -> Result, D::Error> { d.read_map(|d, len| { let hasher = Default::default(); let mut map = HashMap::with_capacity_and_hasher(len, hasher); @@ -218,13 +196,11 @@ impl< } impl< - E, - S: Encoder, - T: Encodable + Hash + Eq, + T: Encodable + Hash + Eq, X, H: Hasher -> Encodable for HashSet { - fn encode(&self, s: &mut S) -> Result<(), E> { +> Encodable for HashSet { + fn encode(&self, s: &mut S) -> Result<(), S::Error> { s.emit_seq(self.len(), |s| { let mut i = 0; for e in self.iter() { @@ -237,13 +213,11 @@ impl< } impl< - E, - D: Decoder, - T: Decodable + Hash + Eq, + T: Decodable + Hash + Eq, S, H: Hasher + Default -> Decodable for HashSet { - fn decode(d: &mut D) -> Result, E> { +> Decodable for HashSet { + fn decode(d: &mut D) -> Result, D::Error> { d.read_seq(|d, len| { let mut set = HashSet::with_capacity_and_hasher(len, Default::default()); for i in range(0u, len) { @@ -254,12 +228,8 @@ impl< } } -impl< - E, - S: Encoder, - V: Encodable -> Encodable for VecMap { - fn encode(&self, e: &mut S) -> Result<(), E> { +impl Encodable for VecMap { + fn encode(&self, e: &mut S) -> Result<(), S::Error> { e.emit_map(self.len(), |e| { for (i, (key, val)) in self.iter().enumerate() { try!(e.emit_map_elt_key(i, |e| key.encode(e))); @@ -270,12 +240,8 @@ impl< } } -impl< - E, - D: Decoder, - V: Decodable -> Decodable for VecMap { - fn decode(d: &mut D) -> Result, E> { +impl Decodable for VecMap { + fn decode(d: &mut D) -> Result, D::Error> { d.read_map(|d, len| { let mut map = VecMap::new(); for i in range(0u, len) { diff --git a/src/libserialize/collection_impls_stage0.rs b/src/libserialize/collection_impls_stage0.rs new file mode 100644 index 0000000000000..f2d79b1334699 --- /dev/null +++ b/src/libserialize/collection_impls_stage0.rs @@ -0,0 +1,289 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Implementations of serialization for structures found in libcollections + +use std::uint; +use std::default::Default; +use std::hash::{Hash, Hasher}; + +use {Decodable, Encodable, Decoder, Encoder}; +use std::collections::{DList, RingBuf, BTreeMap, BTreeSet, HashMap, HashSet, VecMap}; +use collections::enum_set::{EnumSet, CLike}; + +impl< + E, + S: Encoder, + T: Encodable +> Encodable for DList { + fn encode(&self, s: &mut S) -> Result<(), E> { + s.emit_seq(self.len(), |s| { + for (i, e) in self.iter().enumerate() { + try!(s.emit_seq_elt(i, |s| e.encode(s))); + } + Ok(()) + }) + } +} + +impl,T:Decodable> Decodable for DList { + fn decode(d: &mut D) -> Result, E> { + d.read_seq(|d, len| { + let mut list = DList::new(); + for i in range(0u, len) { + list.push_back(try!(d.read_seq_elt(i, |d| Decodable::decode(d)))); + } + Ok(list) + }) + } +} + +impl< + E, + S: Encoder, + T: Encodable +> Encodable for RingBuf { + fn encode(&self, s: &mut S) -> Result<(), E> { + s.emit_seq(self.len(), |s| { + for (i, e) in self.iter().enumerate() { + try!(s.emit_seq_elt(i, |s| e.encode(s))); + } + Ok(()) + }) + } +} + +impl,T:Decodable> Decodable for RingBuf { + fn decode(d: &mut D) -> Result, E> { + d.read_seq(|d, len| { + let mut deque: RingBuf = RingBuf::new(); + for i in range(0u, len) { + deque.push_back(try!(d.read_seq_elt(i, |d| Decodable::decode(d)))); + } + Ok(deque) + }) + } +} + +impl< + E, + S: Encoder, + K: Encodable + PartialEq + Ord, + V: Encodable + PartialEq +> Encodable for BTreeMap { + fn encode(&self, e: &mut S) -> Result<(), E> { + e.emit_map(self.len(), |e| { + let mut i = 0; + for (key, val) in self.iter() { + try!(e.emit_map_elt_key(i, |e| key.encode(e))); + try!(e.emit_map_elt_val(i, |e| val.encode(e))); + i += 1; + } + Ok(()) + }) + } +} + +impl< + E, + D: Decoder, + K: Decodable + PartialEq + Ord, + V: Decodable + PartialEq +> Decodable for BTreeMap { + fn decode(d: &mut D) -> Result, E> { + d.read_map(|d, len| { + let mut map = BTreeMap::new(); + for i in range(0u, len) { + let key = try!(d.read_map_elt_key(i, |d| Decodable::decode(d))); + let val = try!(d.read_map_elt_val(i, |d| Decodable::decode(d))); + map.insert(key, val); + } + Ok(map) + }) + } +} + +impl< + E, + S: Encoder, + T: Encodable + PartialEq + Ord +> Encodable for BTreeSet { + fn encode(&self, s: &mut S) -> Result<(), E> { + s.emit_seq(self.len(), |s| { + let mut i = 0; + for e in self.iter() { + try!(s.emit_seq_elt(i, |s| e.encode(s))); + i += 1; + } + Ok(()) + }) + } +} + +impl< + E, + D: Decoder, + T: Decodable + PartialEq + Ord +> Decodable for BTreeSet { + fn decode(d: &mut D) -> Result, E> { + d.read_seq(|d, len| { + let mut set = BTreeSet::new(); + for i in range(0u, len) { + set.insert(try!(d.read_seq_elt(i, |d| Decodable::decode(d)))); + } + Ok(set) + }) + } +} + +impl< + E, + S: Encoder, + T: Encodable + CLike +> Encodable for EnumSet { + fn encode(&self, s: &mut S) -> Result<(), E> { + let mut bits = 0; + for item in self.iter() { + bits |= item.to_uint(); + } + s.emit_uint(bits) + } +} + +impl< + E, + D: Decoder, + T: Decodable + CLike +> Decodable for EnumSet { + fn decode(d: &mut D) -> Result, E> { + let bits = try!(d.read_uint()); + let mut set = EnumSet::new(); + for bit in range(0, uint::BITS) { + if bits & (1 << bit) != 0 { + set.insert(CLike::from_uint(1 << bit)); + } + } + Ok(set) + } +} + +impl< + E, + S: Encoder, + K: Encodable + Hash + Eq, + V: Encodable, + X, + H: Hasher +> Encodable for HashMap { + fn encode(&self, e: &mut S) -> Result<(), E> { + e.emit_map(self.len(), |e| { + let mut i = 0; + for (key, val) in self.iter() { + try!(e.emit_map_elt_key(i, |e| key.encode(e))); + try!(e.emit_map_elt_val(i, |e| val.encode(e))); + i += 1; + } + Ok(()) + }) + } +} + +impl< + E, + D: Decoder, + K: Decodable + Hash + Eq, + V: Decodable, + S, + H: Hasher + Default +> Decodable for HashMap { + fn decode(d: &mut D) -> Result, E> { + d.read_map(|d, len| { + let hasher = Default::default(); + let mut map = HashMap::with_capacity_and_hasher(len, hasher); + for i in range(0u, len) { + let key = try!(d.read_map_elt_key(i, |d| Decodable::decode(d))); + let val = try!(d.read_map_elt_val(i, |d| Decodable::decode(d))); + map.insert(key, val); + } + Ok(map) + }) + } +} + +impl< + E, + S: Encoder, + T: Encodable + Hash + Eq, + X, + H: Hasher +> Encodable for HashSet { + fn encode(&self, s: &mut S) -> Result<(), E> { + s.emit_seq(self.len(), |s| { + let mut i = 0; + for e in self.iter() { + try!(s.emit_seq_elt(i, |s| e.encode(s))); + i += 1; + } + Ok(()) + }) + } +} + +impl< + E, + D: Decoder, + T: Decodable + Hash + Eq, + S, + H: Hasher + Default +> Decodable for HashSet { + fn decode(d: &mut D) -> Result, E> { + d.read_seq(|d, len| { + let mut set = HashSet::with_capacity_and_hasher(len, Default::default()); + for i in range(0u, len) { + set.insert(try!(d.read_seq_elt(i, |d| Decodable::decode(d)))); + } + Ok(set) + }) + } +} + +impl< + E, + S: Encoder, + V: Encodable +> Encodable for VecMap { + fn encode(&self, e: &mut S) -> Result<(), E> { + e.emit_map(self.len(), |e| { + for (i, (key, val)) in self.iter().enumerate() { + try!(e.emit_map_elt_key(i, |e| key.encode(e))); + try!(e.emit_map_elt_val(i, |e| val.encode(e))); + } + Ok(()) + }) + } +} + +impl< + E, + D: Decoder, + V: Decodable +> Decodable for VecMap { + fn decode(d: &mut D) -> Result, E> { + d.read_map(|d, len| { + let mut map = VecMap::new(); + for i in range(0u, len) { + let key = try!(d.read_map_elt_key(i, |d| Decodable::decode(d))); + let val = try!(d.read_map_elt_val(i, |d| Decodable::decode(d))); + map.insert(key, val); + } + Ok(map) + }) + } +} diff --git a/src/libserialize/hex.rs b/src/libserialize/hex.rs index c915ddaaa9c04..542d0678526b9 100644 --- a/src/libserialize/hex.rs +++ b/src/libserialize/hex.rs @@ -18,7 +18,7 @@ use std::fmt; use std::error; /// A trait for converting a value to hexadecimal encoding -pub trait ToHex for Sized? { +pub trait ToHex { /// Converts the value of `self` to a hex value, returning the owned /// string. fn to_hex(&self) -> String; @@ -54,7 +54,7 @@ impl ToHex for [u8] { } /// A trait for converting hexadecimal encoded values -pub trait FromHex for Sized? { +pub trait FromHex { /// Converts the value of `self`, interpreted as hexadecimal encoded data, /// into an owned vector of bytes, returning the vector. fn from_hex(&self) -> Result, FromHexError>; diff --git a/src/libserialize/json.rs b/src/libserialize/json.rs index e31d8157332c9..c8af8e309a39b 100644 --- a/src/libserialize/json.rs +++ b/src/libserialize/json.rs @@ -300,7 +300,7 @@ pub fn error_str(error: ErrorCode) -> &'static str { } /// Shortcut function to decode a JSON `&str` into an object -pub fn decode>(s: &str) -> DecodeResult { +pub fn decode(s: &str) -> DecodeResult { let json = match from_str(s) { Ok(x) => x, Err(e) => return Err(ParseError(e)) @@ -311,9 +311,7 @@ pub fn decode>(s: &str) -> DecodeResult } /// Shortcut function to encode a `T` into a JSON `String` -pub fn encode(object: &T) -> string::String - where T: for<'a> Encodable, fmt::Error> -{ +pub fn encode(object: &T) -> string::String { let mut s = String::new(); { let mut encoder = Encoder::new(&mut s); @@ -444,7 +442,9 @@ impl<'a> Encoder<'a> { } } -impl<'a> ::Encoder for Encoder<'a> { +impl<'a> ::Encoder for Encoder<'a> { + type Error = fmt::Error; + fn emit_nil(&mut self) -> EncodeResult { write!(self.writer, "null") } fn emit_uint(&mut self, v: uint) -> EncodeResult { write!(self.writer, "{}", v) } @@ -664,7 +664,9 @@ impl<'a> PrettyEncoder<'a> { } } -impl<'a> ::Encoder for PrettyEncoder<'a> { +impl<'a> ::Encoder for PrettyEncoder<'a> { + type Error = fmt::Error; + fn emit_nil(&mut self) -> EncodeResult { write!(self.writer, "null") } fn emit_uint(&mut self, v: uint) -> EncodeResult { write!(self.writer, "{}", v) } @@ -909,8 +911,8 @@ impl<'a> ::Encoder for PrettyEncoder<'a> { } } -impl, S> Encodable for Json { - fn encode(&self, e: &mut E) -> Result<(), S> { +impl Encodable for Json { + fn encode(&self, e: &mut E) -> Result<(), E::Error> { match *self { Json::I64(v) => v.encode(e), Json::U64(v) => v.encode(e), @@ -2062,7 +2064,9 @@ macro_rules! read_primitive { } } -impl ::Decoder for Decoder { +impl ::Decoder for Decoder { + type Error = DecoderError; + fn read_nil(&mut self) -> DecodeResult<()> { expect!(self.pop(), Null) } @@ -2319,7 +2323,7 @@ impl ::Decoder for Decoder { } /// A trait for converting values to JSON -pub trait ToJson for Sized? { +pub trait ToJson { /// Converts the value of `self` to an instance of JSON fn to_json(&self) -> Json; } @@ -2474,9 +2478,7 @@ impl<'a> fmt::Show for PrettyJson<'a> { } } -impl<'a, T> fmt::Show for AsJson<'a, T> - where T: for<'b> Encodable, fmt::Error> -{ +impl<'a, T: Encodable> fmt::Show for AsJson<'a, T> { /// Encodes a json value into a string fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let mut shim = FormatShim { inner: f }; @@ -2493,9 +2495,7 @@ impl<'a, T> AsPrettyJson<'a, T> { } } -impl<'a, T> fmt::Show for AsPrettyJson<'a, T> - where T: for<'b> Encodable, fmt::Error> -{ +impl<'a, T: Encodable> fmt::Show for AsPrettyJson<'a, T> { /// Encodes a json value into a string fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let mut shim = FormatShim { inner: f }; @@ -3155,8 +3155,7 @@ mod tests { A(f64), B(string::String) } - fn check_err>(to_parse: &'static str, - expected: DecoderError) { + fn check_err(to_parse: &'static str, expected: DecoderError) { let res: DecodeResult = match from_str(to_parse) { Err(e) => Err(ParseError(e)), Ok(json) => Decodable::decode(&mut Decoder::new(json)) diff --git a/src/libserialize/json_stage0.rs b/src/libserialize/json_stage0.rs new file mode 100644 index 0000000000000..84180159c2be7 --- /dev/null +++ b/src/libserialize/json_stage0.rs @@ -0,0 +1,3883 @@ +// 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. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Rust JSON serialization library +// Copyright (c) 2011 Google Inc. + +#![forbid(non_camel_case_types)] +#![allow(missing_docs)] + +//! JSON parsing and serialization +//! +//! # What is JSON? +//! +//! JSON (JavaScript Object Notation) is a way to write data in Javascript. +//! Like XML, it allows to encode structured data in a text format that can be easily read by humans +//! Its simple syntax and native compatibility with JavaScript have made it a widely used format. +//! +//! Data types that can be encoded are JavaScript types (see the `Json` enum for more details): +//! +//! * `Boolean`: equivalent to rust's `bool` +//! * `Number`: equivalent to rust's `f64` +//! * `String`: equivalent to rust's `String` +//! * `Array`: equivalent to rust's `Vec`, but also allowing objects of different types in the +//! same array +//! * `Object`: equivalent to rust's `BTreeMap` +//! * `Null` +//! +//! An object is a series of string keys mapping to values, in `"key": value` format. +//! Arrays are enclosed in square brackets ([ ... ]) and objects in curly brackets ({ ... }). +//! A simple JSON document encoding a person, his/her age, address and phone numbers could look like +//! +//! ```ignore +//! { +//! "FirstName": "John", +//! "LastName": "Doe", +//! "Age": 43, +//! "Address": { +//! "Street": "Downing Street 10", +//! "City": "London", +//! "Country": "Great Britain" +//! }, +//! "PhoneNumbers": [ +//! "+44 1234567", +//! "+44 2345678" +//! ] +//! } +//! ``` +//! +//! # Rust Type-based Encoding and Decoding +//! +//! Rust provides a mechanism for low boilerplate encoding & decoding of values to and from JSON via +//! the serialization API. +//! To be able to encode a piece of data, it must implement the `serialize::RustcEncodable` trait. +//! To be able to decode a piece of data, it must implement the `serialize::RustcDecodable` trait. +//! The Rust compiler provides an annotation to automatically generate the code for these traits: +//! `#[derive(RustcDecodable, RustcEncodable)]` +//! +//! The JSON API provides an enum `json::Json` and a trait `ToJson` to encode objects. +//! The `ToJson` trait provides a `to_json` method to convert an object into a `json::Json` value. +//! A `json::Json` value can be encoded as a string or buffer using the functions described above. +//! You can also use the `json::Encoder` object, which implements the `Encoder` trait. +//! +//! When using `ToJson` the `RustcEncodable` trait implementation is not mandatory. +//! +//! # Examples of use +//! +//! ## Using Autoserialization +//! +//! Create a struct called `TestStruct` and serialize and deserialize it to and from JSON using the +//! serialization API, using the derived serialization code. +//! +//! ```notrust +//! // FIXME(#19470): this cannot be ```rust``` because it fails orphan checking at the moment +//! extern crate serialize; +//! use serialize::json; +//! +//! // Automatically generate `Decodable` and `Encodable` trait implementations +//! #[derive(RustcDecodable, RustcEncodable)] +//! pub struct TestStruct { +//! data_int: u8, +//! data_str: String, +//! data_vector: Vec, +//! } +//! +//! fn main() { +//! let object = TestStruct { +//! data_int: 1, +//! data_str: "homura".to_string(), +//! data_vector: vec![2,3,4,5], +//! }; +//! +//! // Serialize using `json::encode` +//! let encoded = json::encode(&object); +//! +//! // Deserialize using `json::decode` +//! let decoded: TestStruct = json::decode(encoded.as_slice()).unwrap(); +//! } +//! ``` +//! +//! ## Using the `ToJson` trait +//! +//! The examples above use the `ToJson` trait to generate the JSON string, which is required +//! for custom mappings. +//! +//! ### Simple example of `ToJson` usage +//! +//! ```notrust +//! // FIXME(#19470): this cannot be ```rust``` because it fails orphan checking at the moment +//! extern crate serialize; +//! use serialize::json::{mod, ToJson, Json}; +//! +//! // A custom data structure +//! struct ComplexNum { +//! a: f64, +//! b: f64, +//! } +//! +//! // JSON value representation +//! impl ToJson for ComplexNum { +//! fn to_json(&self) -> Json { +//! Json::String(format!("{}+{}i", self.a, self.b)) +//! } +//! } +//! +//! // Only generate `RustcEncodable` trait implementation +//! #[derive(Encodable)] +//! pub struct ComplexNumRecord { +//! uid: u8, +//! dsc: String, +//! val: Json, +//! } +//! +//! fn main() { +//! let num = ComplexNum { a: 0.0001, b: 12.539 }; +//! let data: String = json::encode(&ComplexNumRecord{ +//! uid: 1, +//! dsc: "test".to_string(), +//! val: num.to_json(), +//! }); +//! println!("data: {}", data); +//! // data: {"uid":1,"dsc":"test","val":"0.0001+12.539j"}; +//! } +//! ``` +//! +//! ### Verbose example of `ToJson` usage +//! +//! ```notrust +//! // FIXME(#19470): this cannot be ```rust``` because it fails orphan checking at the moment +//! extern crate serialize; +//! use std::collections::BTreeMap; +//! use serialize::json::{mod, Json, ToJson}; +//! +//! // Only generate `Decodable` trait implementation +//! #[derive(Decodable)] +//! pub struct TestStruct { +//! data_int: u8, +//! data_str: String, +//! data_vector: Vec, +//! } +//! +//! // Specify encoding method manually +//! impl ToJson for TestStruct { +//! fn to_json(&self) -> Json { +//! let mut d = BTreeMap::new(); +//! // All standard types implement `to_json()`, so use it +//! d.insert("data_int".to_string(), self.data_int.to_json()); +//! d.insert("data_str".to_string(), self.data_str.to_json()); +//! d.insert("data_vector".to_string(), self.data_vector.to_json()); +//! Json::Object(d) +//! } +//! } +//! +//! fn main() { +//! // Serialize using `ToJson` +//! let input_data = TestStruct { +//! data_int: 1, +//! data_str: "madoka".to_string(), +//! data_vector: vec![2,3,4,5], +//! }; +//! let json_obj: Json = input_data.to_json(); +//! let json_str: String = json_obj.to_string(); +//! +//! // Deserialize like before +//! let decoded: TestStruct = json::decode(json_str.as_slice()).unwrap(); +//! } +//! ``` + +use self::JsonEvent::*; +use self::StackElement::*; +use self::ErrorCode::*; +use self::ParserError::*; +use self::DecoderError::*; +use self::ParserState::*; +use self::InternalStackElement::*; + +use std; +use std::collections::{HashMap, BTreeMap}; +use std::{char, f64, fmt, io, num, str}; +use std::mem::{swap, transmute}; +use std::num::{Float, Int}; +use std::num::FpCategory as Fp; +use std::str::FromStr; +use std::string; +use std::ops; +use unicode::str as unicode_str; +use unicode::str::Utf16Item; + +use Encodable; + +/// Represents a json value +#[derive(Clone, PartialEq, PartialOrd)] +pub enum Json { + I64(i64), + U64(u64), + F64(f64), + String(string::String), + Boolean(bool), + Array(self::Array), + Object(self::Object), + Null, +} + +pub type Array = Vec; +pub type Object = BTreeMap; + +pub struct PrettyJson<'a> { inner: &'a Json } + +pub struct AsJson<'a, T: 'a> { inner: &'a T } +pub struct AsPrettyJson<'a, T: 'a> { inner: &'a T, indent: Option } + +/// The errors that can arise while parsing a JSON stream. +#[derive(Clone, Copy, PartialEq)] +pub enum ErrorCode { + InvalidSyntax, + InvalidNumber, + EOFWhileParsingObject, + EOFWhileParsingArray, + EOFWhileParsingValue, + EOFWhileParsingString, + KeyMustBeAString, + ExpectedColon, + TrailingCharacters, + TrailingComma, + InvalidEscape, + InvalidUnicodeCodePoint, + LoneLeadingSurrogateInHexEscape, + UnexpectedEndOfHexEscape, + UnrecognizedHex, + NotFourDigit, + NotUtf8, +} + +#[derive(Clone, Copy, PartialEq, Show)] +pub enum ParserError { + /// msg, line, col + SyntaxError(ErrorCode, uint, uint), + IoError(io::IoErrorKind, &'static str), +} + +// Builder and Parser have the same errors. +pub type BuilderError = ParserError; + +#[derive(Clone, PartialEq, Show)] +pub enum DecoderError { + ParseError(ParserError), + ExpectedError(string::String, string::String), + MissingFieldError(string::String), + UnknownVariantError(string::String), + ApplicationError(string::String) +} + +/// Returns a readable error string for a given error code. +pub fn error_str(error: ErrorCode) -> &'static str { + match error { + InvalidSyntax => "invalid syntax", + InvalidNumber => "invalid number", + EOFWhileParsingObject => "EOF While parsing object", + EOFWhileParsingArray => "EOF While parsing array", + EOFWhileParsingValue => "EOF While parsing value", + EOFWhileParsingString => "EOF While parsing string", + KeyMustBeAString => "key must be a string", + ExpectedColon => "expected `:`", + TrailingCharacters => "trailing characters", + TrailingComma => "trailing comma", + InvalidEscape => "invalid escape", + UnrecognizedHex => "invalid \\u{ esc}ape (unrecognized hex)", + NotFourDigit => "invalid \\u{ esc}ape (not four digits)", + NotUtf8 => "contents not utf-8", + InvalidUnicodeCodePoint => "invalid Unicode code point", + LoneLeadingSurrogateInHexEscape => "lone leading surrogate in hex escape", + UnexpectedEndOfHexEscape => "unexpected end of hex escape", + } +} + +/// Shortcut function to decode a JSON `&str` into an object +pub fn decode>(s: &str) -> DecodeResult { + let json = match from_str(s) { + Ok(x) => x, + Err(e) => return Err(ParseError(e)) + }; + + let mut decoder = Decoder::new(json); + ::Decodable::decode(&mut decoder) +} + +/// Shortcut function to encode a `T` into a JSON `String` +pub fn encode(object: &T) -> string::String + where T: for<'a> Encodable, fmt::Error> +{ + let mut s = String::new(); + { + let mut encoder = Encoder::new(&mut s); + let _ = object.encode(&mut encoder); + } + s +} + +impl fmt::Show for ErrorCode { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + error_str(*self).fmt(f) + } +} + +fn io_error_to_error(io: io::IoError) -> ParserError { + IoError(io.kind, io.desc) +} + +impl std::error::Error for DecoderError { + fn description(&self) -> &str { "decoder error" } + fn detail(&self) -> Option { Some(self.to_string()) } +} + +pub type EncodeResult = fmt::Result; +pub type DecodeResult = Result; + +fn escape_str(wr: &mut fmt::Writer, v: &str) -> fmt::Result { + try!(wr.write_str("\"")); + + let mut start = 0; + + for (i, byte) in v.bytes().enumerate() { + let escaped = match byte { + b'"' => "\\\"", + b'\\' => "\\\\", + b'\x00' => "\\u0000", + b'\x01' => "\\u0001", + b'\x02' => "\\u0002", + b'\x03' => "\\u0003", + b'\x04' => "\\u0004", + b'\x05' => "\\u0005", + b'\x06' => "\\u0006", + b'\x07' => "\\u0007", + b'\x08' => "\\b", + b'\t' => "\\t", + b'\n' => "\\n", + b'\x0b' => "\\u000b", + b'\x0c' => "\\f", + b'\r' => "\\r", + b'\x0e' => "\\u000e", + b'\x0f' => "\\u000f", + b'\x10' => "\\u0010", + b'\x11' => "\\u0011", + b'\x12' => "\\u0012", + b'\x13' => "\\u0013", + b'\x14' => "\\u0014", + b'\x15' => "\\u0015", + b'\x16' => "\\u0016", + b'\x17' => "\\u0017", + b'\x18' => "\\u0018", + b'\x19' => "\\u0019", + b'\x1a' => "\\u001a", + b'\x1b' => "\\u001b", + b'\x1c' => "\\u001c", + b'\x1d' => "\\u001d", + b'\x1e' => "\\u001e", + b'\x1f' => "\\u001f", + b'\x7f' => "\\u007f", + _ => { continue; } + }; + + if start < i { + try!(wr.write_str(v[start..i])); + } + + try!(wr.write_str(escaped)); + + start = i + 1; + } + + if start != v.len() { + try!(wr.write_str(v[start..])); + } + + wr.write_str("\"") +} + +fn escape_char(writer: &mut fmt::Writer, v: char) -> fmt::Result { + let mut buf = [0; 4]; + let n = v.encode_utf8(&mut buf).unwrap(); + let buf = unsafe { str::from_utf8_unchecked(buf[0..n]) }; + escape_str(writer, buf) +} + +fn spaces(wr: &mut fmt::Writer, mut n: uint) -> fmt::Result { + const BUF: &'static str = " "; + + while n >= BUF.len() { + try!(wr.write_str(BUF)); + n -= BUF.len(); + } + + if n > 0 { + wr.write_str(BUF[..n]) + } else { + Ok(()) + } +} + +fn fmt_number_or_null(v: f64) -> string::String { + match v.classify() { + Fp::Nan | Fp::Infinite => string::String::from_str("null"), + _ if v.fract() != 0f64 => f64::to_str_digits(v, 6u), + _ => f64::to_str_digits(v, 6u) + ".0", + } +} + +/// A structure for implementing serialization to JSON. +pub struct Encoder<'a> { + writer: &'a mut (fmt::Writer+'a), +} + +impl<'a> Encoder<'a> { + /// Creates a new JSON encoder whose output will be written to the writer + /// specified. + pub fn new(writer: &'a mut fmt::Writer) -> Encoder<'a> { + Encoder { writer: writer } + } +} + +impl<'a> ::Encoder for Encoder<'a> { + fn emit_nil(&mut self) -> EncodeResult { write!(self.writer, "null") } + + fn emit_uint(&mut self, v: uint) -> EncodeResult { write!(self.writer, "{}", v) } + fn emit_u64(&mut self, v: u64) -> EncodeResult { write!(self.writer, "{}", v) } + fn emit_u32(&mut self, v: u32) -> EncodeResult { write!(self.writer, "{}", v) } + fn emit_u16(&mut self, v: u16) -> EncodeResult { write!(self.writer, "{}", v) } + fn emit_u8(&mut self, v: u8) -> EncodeResult { write!(self.writer, "{}", v) } + + fn emit_int(&mut self, v: int) -> EncodeResult { write!(self.writer, "{}", v) } + fn emit_i64(&mut self, v: i64) -> EncodeResult { write!(self.writer, "{}", v) } + fn emit_i32(&mut self, v: i32) -> EncodeResult { write!(self.writer, "{}", v) } + fn emit_i16(&mut self, v: i16) -> EncodeResult { write!(self.writer, "{}", v) } + fn emit_i8(&mut self, v: i8) -> EncodeResult { write!(self.writer, "{}", v) } + + fn emit_bool(&mut self, v: bool) -> EncodeResult { + if v { + write!(self.writer, "true") + } else { + write!(self.writer, "false") + } + } + + fn emit_f64(&mut self, v: f64) -> EncodeResult { + write!(self.writer, "{}", fmt_number_or_null(v)) + } + fn emit_f32(&mut self, v: f32) -> EncodeResult { + self.emit_f64(v as f64) + } + + fn emit_char(&mut self, v: char) -> EncodeResult { + escape_char(self.writer, v) + } + fn emit_str(&mut self, v: &str) -> EncodeResult { + escape_str(self.writer, v) + } + + fn emit_enum(&mut self, _name: &str, f: F) -> EncodeResult where + F: FnOnce(&mut Encoder<'a>) -> EncodeResult, + { + f(self) + } + + fn emit_enum_variant(&mut self, + name: &str, + _id: uint, + cnt: uint, + f: F) -> EncodeResult where + F: FnOnce(&mut Encoder<'a>) -> EncodeResult, + { + // enums are encoded as strings or objects + // Bunny => "Bunny" + // Kangaroo(34,"William") => {"variant": "Kangaroo", "fields": [34,"William"]} + if cnt == 0 { + escape_str(self.writer, name) + } else { + try!(write!(self.writer, "{{\"variant\":")); + try!(escape_str(self.writer, name)); + try!(write!(self.writer, ",\"fields\":[")); + try!(f(self)); + write!(self.writer, "]}}") + } + } + + fn emit_enum_variant_arg(&mut self, idx: uint, f: F) -> EncodeResult where + F: FnOnce(&mut Encoder<'a>) -> EncodeResult, + { + if idx != 0 { + try!(write!(self.writer, ",")); + } + f(self) + } + + fn emit_enum_struct_variant(&mut self, + name: &str, + id: uint, + cnt: uint, + f: F) -> EncodeResult where + F: FnOnce(&mut Encoder<'a>) -> EncodeResult, + { + self.emit_enum_variant(name, id, cnt, f) + } + + fn emit_enum_struct_variant_field(&mut self, + _: &str, + idx: uint, + f: F) -> EncodeResult where + F: FnOnce(&mut Encoder<'a>) -> EncodeResult, + { + self.emit_enum_variant_arg(idx, f) + } + + fn emit_struct(&mut self, _: &str, _: uint, f: F) -> EncodeResult where + F: FnOnce(&mut Encoder<'a>) -> EncodeResult, + { + try!(write!(self.writer, "{{")); + try!(f(self)); + write!(self.writer, "}}") + } + + fn emit_struct_field(&mut self, name: &str, idx: uint, f: F) -> EncodeResult where + F: FnOnce(&mut Encoder<'a>) -> EncodeResult, + { + if idx != 0 { try!(write!(self.writer, ",")); } + try!(escape_str(self.writer, name)); + try!(write!(self.writer, ":")); + f(self) + } + + fn emit_tuple(&mut self, len: uint, f: F) -> EncodeResult where + F: FnOnce(&mut Encoder<'a>) -> EncodeResult, + { + self.emit_seq(len, f) + } + fn emit_tuple_arg(&mut self, idx: uint, f: F) -> EncodeResult where + F: FnOnce(&mut Encoder<'a>) -> EncodeResult, + { + self.emit_seq_elt(idx, f) + } + + fn emit_tuple_struct(&mut self, _name: &str, len: uint, f: F) -> EncodeResult where + F: FnOnce(&mut Encoder<'a>) -> EncodeResult, + { + self.emit_seq(len, f) + } + fn emit_tuple_struct_arg(&mut self, idx: uint, f: F) -> EncodeResult where + F: FnOnce(&mut Encoder<'a>) -> EncodeResult, + { + self.emit_seq_elt(idx, f) + } + + fn emit_option(&mut self, f: F) -> EncodeResult where + F: FnOnce(&mut Encoder<'a>) -> EncodeResult, + { + f(self) + } + fn emit_option_none(&mut self) -> EncodeResult { self.emit_nil() } + fn emit_option_some(&mut self, f: F) -> EncodeResult where + F: FnOnce(&mut Encoder<'a>) -> EncodeResult, + { + f(self) + } + + fn emit_seq(&mut self, _len: uint, f: F) -> EncodeResult where + F: FnOnce(&mut Encoder<'a>) -> EncodeResult, + { + try!(write!(self.writer, "[")); + try!(f(self)); + write!(self.writer, "]") + } + + fn emit_seq_elt(&mut self, idx: uint, f: F) -> EncodeResult where + F: FnOnce(&mut Encoder<'a>) -> EncodeResult, + { + if idx != 0 { + try!(write!(self.writer, ",")); + } + f(self) + } + + fn emit_map(&mut self, _len: uint, f: F) -> EncodeResult where + F: FnOnce(&mut Encoder<'a>) -> EncodeResult, + { + try!(write!(self.writer, "{{")); + try!(f(self)); + write!(self.writer, "}}") + } + + fn emit_map_elt_key(&mut self, idx: uint, mut f: F) -> EncodeResult where + F: FnMut(&mut Encoder<'a>) -> EncodeResult, + { + if idx != 0 { try!(write!(self.writer, ",")) } + // ref #12967, make sure to wrap a key in double quotes, + // in the event that its of a type that omits them (eg numbers) + let mut buf = Vec::new(); + // FIXME(14302) remove the transmute and unsafe block. + unsafe { + let mut check_encoder = Encoder::new(&mut buf); + try!(f(transmute(&mut check_encoder))); + } + let out = str::from_utf8(buf[]).unwrap(); + let needs_wrapping = out.char_at(0) != '"' && out.char_at_reverse(out.len()) != '"'; + if needs_wrapping { try!(write!(self.writer, "\"")); } + try!(f(self)); + if needs_wrapping { try!(write!(self.writer, "\"")); } + Ok(()) + } + + fn emit_map_elt_val(&mut self, _idx: uint, f: F) -> EncodeResult where + F: FnOnce(&mut Encoder<'a>) -> EncodeResult, + { + try!(write!(self.writer, ":")); + f(self) + } +} + +/// Another encoder for JSON, but prints out human-readable JSON instead of +/// compact data +pub struct PrettyEncoder<'a> { + writer: &'a mut (fmt::Writer+'a), + curr_indent: uint, + indent: uint, +} + +impl<'a> PrettyEncoder<'a> { + /// Creates a new encoder whose output will be written to the specified writer + pub fn new(writer: &'a mut fmt::Writer) -> PrettyEncoder<'a> { + PrettyEncoder { writer: writer, curr_indent: 0, indent: 2, } + } + + /// Set the number of spaces to indent for each level. + /// This is safe to set during encoding. + pub fn set_indent(&mut self, indent: uint) { + // self.indent very well could be 0 so we need to use checked division. + let level = self.curr_indent.checked_div(self.indent).unwrap_or(0); + self.indent = indent; + self.curr_indent = level * self.indent; + } +} + +impl<'a> ::Encoder for PrettyEncoder<'a> { + fn emit_nil(&mut self) -> EncodeResult { write!(self.writer, "null") } + + fn emit_uint(&mut self, v: uint) -> EncodeResult { write!(self.writer, "{}", v) } + fn emit_u64(&mut self, v: u64) -> EncodeResult { write!(self.writer, "{}", v) } + fn emit_u32(&mut self, v: u32) -> EncodeResult { write!(self.writer, "{}", v) } + fn emit_u16(&mut self, v: u16) -> EncodeResult { write!(self.writer, "{}", v) } + fn emit_u8(&mut self, v: u8) -> EncodeResult { write!(self.writer, "{}", v) } + + fn emit_int(&mut self, v: int) -> EncodeResult { write!(self.writer, "{}", v) } + fn emit_i64(&mut self, v: i64) -> EncodeResult { write!(self.writer, "{}", v) } + fn emit_i32(&mut self, v: i32) -> EncodeResult { write!(self.writer, "{}", v) } + fn emit_i16(&mut self, v: i16) -> EncodeResult { write!(self.writer, "{}", v) } + fn emit_i8(&mut self, v: i8) -> EncodeResult { write!(self.writer, "{}", v) } + + fn emit_bool(&mut self, v: bool) -> EncodeResult { + if v { + write!(self.writer, "true") + } else { + write!(self.writer, "false") + } + } + + fn emit_f64(&mut self, v: f64) -> EncodeResult { + write!(self.writer, "{}", fmt_number_or_null(v)) + } + fn emit_f32(&mut self, v: f32) -> EncodeResult { + self.emit_f64(v as f64) + } + + fn emit_char(&mut self, v: char) -> EncodeResult { + escape_char(self.writer, v) + } + fn emit_str(&mut self, v: &str) -> EncodeResult { + escape_str(self.writer, v) + } + + fn emit_enum(&mut self, _name: &str, f: F) -> EncodeResult where + F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult, + { + f(self) + } + + fn emit_enum_variant(&mut self, + name: &str, + _id: uint, + cnt: uint, + f: F) + -> EncodeResult where + F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult, + { + if cnt == 0 { + escape_str(self.writer, name) + } else { + try!(write!(self.writer, "{{\n")); + self.curr_indent += self.indent; + try!(spaces(self.writer, self.curr_indent)); + try!(write!(self.writer, "\"variant\": ")); + try!(escape_str(self.writer, name)); + try!(write!(self.writer, ",\n")); + try!(spaces(self.writer, self.curr_indent)); + try!(write!(self.writer, "\"fields\": [\n")); + self.curr_indent += self.indent; + try!(f(self)); + self.curr_indent -= self.indent; + try!(write!(self.writer, "\n")); + try!(spaces(self.writer, self.curr_indent)); + self.curr_indent -= self.indent; + try!(write!(self.writer, "]\n")); + try!(spaces(self.writer, self.curr_indent)); + write!(self.writer, "}}") + } + } + + fn emit_enum_variant_arg(&mut self, idx: uint, f: F) -> EncodeResult where + F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult, + { + if idx != 0 { + try!(write!(self.writer, ",\n")); + } + try!(spaces(self.writer, self.curr_indent)); + f(self) + } + + fn emit_enum_struct_variant(&mut self, + name: &str, + id: uint, + cnt: uint, + f: F) -> EncodeResult where + F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult, + { + self.emit_enum_variant(name, id, cnt, f) + } + + fn emit_enum_struct_variant_field(&mut self, + _: &str, + idx: uint, + f: F) -> EncodeResult where + F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult, + { + self.emit_enum_variant_arg(idx, f) + } + + + fn emit_struct(&mut self, _: &str, len: uint, f: F) -> EncodeResult where + F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult, + { + if len == 0 { + write!(self.writer, "{{}}") + } else { + try!(write!(self.writer, "{{")); + self.curr_indent += self.indent; + try!(f(self)); + self.curr_indent -= self.indent; + try!(write!(self.writer, "\n")); + try!(spaces(self.writer, self.curr_indent)); + write!(self.writer, "}}") + } + } + + fn emit_struct_field(&mut self, name: &str, idx: uint, f: F) -> EncodeResult where + F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult, + { + if idx == 0 { + try!(write!(self.writer, "\n")); + } else { + try!(write!(self.writer, ",\n")); + } + try!(spaces(self.writer, self.curr_indent)); + try!(escape_str(self.writer, name)); + try!(write!(self.writer, ": ")); + f(self) + } + + fn emit_tuple(&mut self, len: uint, f: F) -> EncodeResult where + F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult, + { + self.emit_seq(len, f) + } + fn emit_tuple_arg(&mut self, idx: uint, f: F) -> EncodeResult where + F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult, + { + self.emit_seq_elt(idx, f) + } + + fn emit_tuple_struct(&mut self, _: &str, len: uint, f: F) -> EncodeResult where + F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult, + { + self.emit_seq(len, f) + } + fn emit_tuple_struct_arg(&mut self, idx: uint, f: F) -> EncodeResult where + F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult, + { + self.emit_seq_elt(idx, f) + } + + fn emit_option(&mut self, f: F) -> EncodeResult where + F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult, + { + f(self) + } + fn emit_option_none(&mut self) -> EncodeResult { self.emit_nil() } + fn emit_option_some(&mut self, f: F) -> EncodeResult where + F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult, + { + f(self) + } + + fn emit_seq(&mut self, len: uint, f: F) -> EncodeResult where + F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult, + { + if len == 0 { + write!(self.writer, "[]") + } else { + try!(write!(self.writer, "[")); + self.curr_indent += self.indent; + try!(f(self)); + self.curr_indent -= self.indent; + try!(write!(self.writer, "\n")); + try!(spaces(self.writer, self.curr_indent)); + write!(self.writer, "]") + } + } + + fn emit_seq_elt(&mut self, idx: uint, f: F) -> EncodeResult where + F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult, + { + if idx == 0 { + try!(write!(self.writer, "\n")); + } else { + try!(write!(self.writer, ",\n")); + } + try!(spaces(self.writer, self.curr_indent)); + f(self) + } + + fn emit_map(&mut self, len: uint, f: F) -> EncodeResult where + F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult, + { + if len == 0 { + write!(self.writer, "{{}}") + } else { + try!(write!(self.writer, "{{")); + self.curr_indent += self.indent; + try!(f(self)); + self.curr_indent -= self.indent; + try!(write!(self.writer, "\n")); + try!(spaces(self.writer, self.curr_indent)); + write!(self.writer, "}}") + } + } + + fn emit_map_elt_key(&mut self, idx: uint, mut f: F) -> EncodeResult where + F: FnMut(&mut PrettyEncoder<'a>) -> EncodeResult, + { + if idx == 0 { + try!(write!(self.writer, "\n")); + } else { + try!(write!(self.writer, ",\n")); + } + try!(spaces(self.writer, self.curr_indent)); + // ref #12967, make sure to wrap a key in double quotes, + // in the event that its of a type that omits them (eg numbers) + let mut buf = Vec::new(); + // FIXME(14302) remove the transmute and unsafe block. + unsafe { + let mut check_encoder = PrettyEncoder::new(&mut buf); + try!(f(transmute(&mut check_encoder))); + } + let out = str::from_utf8(buf[]).unwrap(); + let needs_wrapping = out.char_at(0) != '"' && out.char_at_reverse(out.len()) != '"'; + if needs_wrapping { try!(write!(self.writer, "\"")); } + try!(f(self)); + if needs_wrapping { try!(write!(self.writer, "\"")); } + Ok(()) + } + + fn emit_map_elt_val(&mut self, _idx: uint, f: F) -> EncodeResult where + F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult, + { + try!(write!(self.writer, ": ")); + f(self) + } +} + +impl, S> Encodable for Json { + fn encode(&self, e: &mut E) -> Result<(), S> { + match *self { + Json::I64(v) => v.encode(e), + Json::U64(v) => v.encode(e), + Json::F64(v) => v.encode(e), + Json::String(ref v) => v.encode(e), + Json::Boolean(v) => v.encode(e), + Json::Array(ref v) => v.encode(e), + Json::Object(ref v) => v.encode(e), + Json::Null => e.emit_nil(), + } + } +} + +/// Create an `AsJson` wrapper which can be used to print a value as JSON +/// on-the-fly via `write!` +pub fn as_json(t: &T) -> AsJson { + AsJson { inner: t } +} + +/// Create an `AsPrettyJson` wrapper which can be used to print a value as JSON +/// on-the-fly via `write!` +pub fn as_pretty_json(t: &T) -> AsPrettyJson { + AsPrettyJson { inner: t, indent: None } +} + +impl Json { + /// Borrow this json object as a pretty object to generate a pretty + /// representation for it via `Show`. + pub fn pretty(&self) -> PrettyJson { + PrettyJson { inner: self } + } + + /// If the Json value is an Object, returns the value associated with the provided key. + /// Otherwise, returns None. + pub fn find<'a>(&'a self, key: &str) -> Option<&'a Json>{ + match self { + &Json::Object(ref map) => map.get(key), + _ => None + } + } + + /// Attempts to get a nested Json Object for each key in `keys`. + /// If any key is found not to exist, find_path will return None. + /// Otherwise, it will return the Json value associated with the final key. + pub fn find_path<'a>(&'a self, keys: &[&str]) -> Option<&'a Json>{ + let mut target = self; + for key in keys.iter() { + match target.find(*key) { + Some(t) => { target = t; }, + None => return None + } + } + Some(target) + } + + /// If the Json value is an Object, performs a depth-first search until + /// a value associated with the provided key is found. If no value is found + /// or the Json value is not an Object, returns None. + pub fn search<'a>(&'a self, key: &str) -> Option<&'a Json> { + match self { + &Json::Object(ref map) => { + match map.get(key) { + Some(json_value) => Some(json_value), + None => { + for (_, v) in map.iter() { + match v.search(key) { + x if x.is_some() => return x, + _ => () + } + } + None + } + } + }, + _ => None + } + } + + /// Returns true if the Json value is an Object. Returns false otherwise. + pub fn is_object<'a>(&'a self) -> bool { + self.as_object().is_some() + } + + /// If the Json value is an Object, returns the associated BTreeMap. + /// Returns None otherwise. + pub fn as_object<'a>(&'a self) -> Option<&'a Object> { + match self { + &Json::Object(ref map) => Some(map), + _ => None + } + } + + /// Returns true if the Json value is an Array. Returns false otherwise. + pub fn is_array<'a>(&'a self) -> bool { + self.as_array().is_some() + } + + /// If the Json value is an Array, returns the associated vector. + /// Returns None otherwise. + pub fn as_array<'a>(&'a self) -> Option<&'a Array> { + match self { + &Json::Array(ref array) => Some(&*array), + _ => None + } + } + + /// Returns true if the Json value is a String. Returns false otherwise. + pub fn is_string<'a>(&'a self) -> bool { + self.as_string().is_some() + } + + /// If the Json value is a String, returns the associated str. + /// Returns None otherwise. + pub fn as_string<'a>(&'a self) -> Option<&'a str> { + match *self { + Json::String(ref s) => Some(s[]), + _ => None + } + } + + /// Returns true if the Json value is a Number. Returns false otherwise. + pub fn is_number(&self) -> bool { + match *self { + Json::I64(_) | Json::U64(_) | Json::F64(_) => true, + _ => false, + } + } + + /// Returns true if the Json value is a i64. Returns false otherwise. + pub fn is_i64(&self) -> bool { + match *self { + Json::I64(_) => true, + _ => false, + } + } + + /// Returns true if the Json value is a u64. Returns false otherwise. + pub fn is_u64(&self) -> bool { + match *self { + Json::U64(_) => true, + _ => false, + } + } + + /// Returns true if the Json value is a f64. Returns false otherwise. + pub fn is_f64(&self) -> bool { + match *self { + Json::F64(_) => true, + _ => false, + } + } + + /// If the Json value is a number, return or cast it to a i64. + /// Returns None otherwise. + pub fn as_i64(&self) -> Option { + match *self { + Json::I64(n) => Some(n), + Json::U64(n) => num::cast(n), + _ => None + } + } + + /// If the Json value is a number, return or cast it to a u64. + /// Returns None otherwise. + pub fn as_u64(&self) -> Option { + match *self { + Json::I64(n) => num::cast(n), + Json::U64(n) => Some(n), + _ => None + } + } + + /// If the Json value is a number, return or cast it to a f64. + /// Returns None otherwise. + pub fn as_f64(&self) -> Option { + match *self { + Json::I64(n) => num::cast(n), + Json::U64(n) => num::cast(n), + Json::F64(n) => Some(n), + _ => None + } + } + + /// Returns true if the Json value is a Boolean. Returns false otherwise. + pub fn is_boolean(&self) -> bool { + self.as_boolean().is_some() + } + + /// If the Json value is a Boolean, returns the associated bool. + /// Returns None otherwise. + pub fn as_boolean(&self) -> Option { + match self { + &Json::Boolean(b) => Some(b), + _ => None + } + } + + /// Returns true if the Json value is a Null. Returns false otherwise. + pub fn is_null(&self) -> bool { + self.as_null().is_some() + } + + /// If the Json value is a Null, returns (). + /// Returns None otherwise. + pub fn as_null(&self) -> Option<()> { + match self { + &Json::Null => Some(()), + _ => None + } + } +} + +// NOTE(stage0): remove impl after a snapshot +#[cfg(stage0)] +impl<'a> ops::Index<&'a str, Json> for Json { + fn index(&self, idx: & &str) -> &Json { + self.find(*idx).unwrap() + } +} + +#[cfg(not(stage0))] // NOTE(stage0): remove cfg after a snapshot +impl<'a> ops::Index<&'a str> for Json { + type Output = Json; + + fn index(&self, idx: & &str) -> &Json { + self.find(*idx).unwrap() + } +} + +// NOTE(stage0): remove impl after a snapshot +#[cfg(stage0)] +impl ops::Index for Json { + fn index<'a>(&'a self, idx: &uint) -> &'a Json { + match self { + &Json::Array(ref v) => v.index(idx), + _ => panic!("can only index Json with uint if it is an array") + } + } +} + +#[cfg(not(stage0))] // NOTE(stage0): remove cfg after a snapshot +impl ops::Index for Json { + type Output = Json; + + fn index<'a>(&'a self, idx: &uint) -> &'a Json { + match self { + &Json::Array(ref v) => v.index(idx), + _ => panic!("can only index Json with uint if it is an array") + } + } +} + +/// The output of the streaming parser. +#[derive(PartialEq, Clone, Show)] +pub enum JsonEvent { + ObjectStart, + ObjectEnd, + ArrayStart, + ArrayEnd, + BooleanValue(bool), + I64Value(i64), + U64Value(u64), + F64Value(f64), + StringValue(string::String), + NullValue, + Error(ParserError), +} + +#[derive(PartialEq, Show)] +enum ParserState { + // Parse a value in an array, true means first element. + ParseArray(bool), + // Parse ',' or ']' after an element in an array. + ParseArrayComma, + // Parse a key:value in an object, true means first element. + ParseObject(bool), + // Parse ',' or ']' after an element in an object. + ParseObjectComma, + // Initial state. + ParseStart, + // Expecting the stream to end. + ParseBeforeFinish, + // Parsing can't continue. + ParseFinished, +} + +/// A Stack represents the current position of the parser in the logical +/// structure of the JSON stream. +/// For example foo.bar[3].x +pub struct Stack { + stack: Vec, + str_buffer: Vec, +} + +/// StackElements compose a Stack. +/// For example, Key("foo"), Key("bar"), Index(3) and Key("x") are the +/// StackElements compositing the stack that represents foo.bar[3].x +#[derive(PartialEq, Clone, Show)] +pub enum StackElement<'l> { + Index(u32), + Key(&'l str), +} + +// Internally, Key elements are stored as indices in a buffer to avoid +// allocating a string for every member of an object. +#[derive(PartialEq, Clone, Show)] +enum InternalStackElement { + InternalIndex(u32), + InternalKey(u16, u16), // start, size +} + +impl Stack { + pub fn new() -> Stack { + Stack { stack: Vec::new(), str_buffer: Vec::new() } + } + + /// Returns The number of elements in the Stack. + pub fn len(&self) -> uint { self.stack.len() } + + /// Returns true if the stack is empty. + pub fn is_empty(&self) -> bool { self.stack.is_empty() } + + /// Provides access to the StackElement at a given index. + /// lower indices are at the bottom of the stack while higher indices are + /// at the top. + pub fn get<'l>(&'l self, idx: uint) -> StackElement<'l> { + match self.stack[idx] { + InternalIndex(i) => Index(i), + InternalKey(start, size) => { + Key(str::from_utf8( + self.str_buffer[start as uint .. start as uint + size as uint]).unwrap()) + } + } + } + + /// Compares this stack with an array of StackElements. + pub fn is_equal_to(&self, rhs: &[StackElement]) -> bool { + if self.stack.len() != rhs.len() { return false; } + for i in range(0, rhs.len()) { + if self.get(i) != rhs[i] { return false; } + } + return true; + } + + /// Returns true if the bottom-most elements of this stack are the same as + /// the ones passed as parameter. + pub fn starts_with(&self, rhs: &[StackElement]) -> bool { + if self.stack.len() < rhs.len() { return false; } + for i in range(0, rhs.len()) { + if self.get(i) != rhs[i] { return false; } + } + return true; + } + + /// Returns true if the top-most elements of this stack are the same as + /// the ones passed as parameter. + pub fn ends_with(&self, rhs: &[StackElement]) -> bool { + if self.stack.len() < rhs.len() { return false; } + let offset = self.stack.len() - rhs.len(); + for i in range(0, rhs.len()) { + if self.get(i + offset) != rhs[i] { return false; } + } + return true; + } + + /// Returns the top-most element (if any). + pub fn top<'l>(&'l self) -> Option> { + return match self.stack.last() { + None => None, + Some(&InternalIndex(i)) => Some(Index(i)), + Some(&InternalKey(start, size)) => { + Some(Key(str::from_utf8( + self.str_buffer[start as uint .. (start+size) as uint] + ).unwrap())) + } + } + } + + // Used by Parser to insert Key elements at the top of the stack. + fn push_key(&mut self, key: string::String) { + self.stack.push(InternalKey(self.str_buffer.len() as u16, key.len() as u16)); + for c in key.as_bytes().iter() { + self.str_buffer.push(*c); + } + } + + // Used by Parser to insert Index elements at the top of the stack. + fn push_index(&mut self, index: u32) { + self.stack.push(InternalIndex(index)); + } + + // Used by Parser to remove the top-most element of the stack. + fn pop(&mut self) { + assert!(!self.is_empty()); + match *self.stack.last().unwrap() { + InternalKey(_, sz) => { + let new_size = self.str_buffer.len() - sz as uint; + self.str_buffer.truncate(new_size); + } + InternalIndex(_) => {} + } + self.stack.pop(); + } + + // Used by Parser to test whether the top-most element is an index. + fn last_is_index(&self) -> bool { + if self.is_empty() { return false; } + return match *self.stack.last().unwrap() { + InternalIndex(_) => true, + _ => false, + } + } + + // Used by Parser to increment the index of the top-most element. + fn bump_index(&mut self) { + let len = self.stack.len(); + let idx = match *self.stack.last().unwrap() { + InternalIndex(i) => { i + 1 } + _ => { panic!(); } + }; + self.stack[len - 1] = InternalIndex(idx); + } +} + +/// A streaming JSON parser implemented as an iterator of JsonEvent, consuming +/// an iterator of char. +pub struct Parser { + rdr: T, + ch: Option, + line: uint, + col: uint, + // We maintain a stack representing where we are in the logical structure + // of the JSON stream. + stack: Stack, + // A state machine is kept to make it possible to interrupt and resume parsing. + state: ParserState, +} + +impl> Iterator for Parser { + type Item = JsonEvent; + + fn next(&mut self) -> Option { + if self.state == ParseFinished { + return None; + } + + if self.state == ParseBeforeFinish { + self.parse_whitespace(); + // Make sure there is no trailing characters. + if self.eof() { + self.state = ParseFinished; + return None; + } else { + return Some(self.error_event(TrailingCharacters)); + } + } + + return Some(self.parse()); + } +} + +impl> Parser { + /// Creates the JSON parser. + pub fn new(rdr: T) -> Parser { + let mut p = Parser { + rdr: rdr, + ch: Some('\x00'), + line: 1, + col: 0, + stack: Stack::new(), + state: ParseStart, + }; + p.bump(); + return p; + } + + /// Provides access to the current position in the logical structure of the + /// JSON stream. + pub fn stack<'l>(&'l self) -> &'l Stack { + return &self.stack; + } + + fn eof(&self) -> bool { self.ch.is_none() } + fn ch_or_null(&self) -> char { self.ch.unwrap_or('\x00') } + fn bump(&mut self) { + self.ch = self.rdr.next(); + + if self.ch_is('\n') { + self.line += 1u; + self.col = 1u; + } else { + self.col += 1u; + } + } + + fn next_char(&mut self) -> Option { + self.bump(); + self.ch + } + fn ch_is(&self, c: char) -> bool { + self.ch == Some(c) + } + + fn error(&self, reason: ErrorCode) -> Result { + Err(SyntaxError(reason, self.line, self.col)) + } + + fn parse_whitespace(&mut self) { + while self.ch_is(' ') || + self.ch_is('\n') || + self.ch_is('\t') || + self.ch_is('\r') { self.bump(); } + } + + fn parse_number(&mut self) -> JsonEvent { + let mut neg = false; + + if self.ch_is('-') { + self.bump(); + neg = true; + } + + let res = match self.parse_u64() { + Ok(res) => res, + Err(e) => { return Error(e); } + }; + + if self.ch_is('.') || self.ch_is('e') || self.ch_is('E') { + let mut res = res as f64; + + if self.ch_is('.') { + res = match self.parse_decimal(res) { + Ok(res) => res, + Err(e) => { return Error(e); } + }; + } + + if self.ch_is('e') || self.ch_is('E') { + res = match self.parse_exponent(res) { + Ok(res) => res, + Err(e) => { return Error(e); } + }; + } + + if neg { + res *= -1.0; + } + + F64Value(res) + } else { + if neg { + let res = -(res as i64); + + // Make sure we didn't underflow. + if res > 0 { + Error(SyntaxError(InvalidNumber, self.line, self.col)) + } else { + I64Value(res) + } + } else { + U64Value(res) + } + } + } + + fn parse_u64(&mut self) -> Result { + let mut accum = 0; + let last_accum = 0; // necessary to detect overflow. + + match self.ch_or_null() { + '0' => { + self.bump(); + + // A leading '0' must be the only digit before the decimal point. + match self.ch_or_null() { + '0' ... '9' => return self.error(InvalidNumber), + _ => () + } + }, + '1' ... '9' => { + while !self.eof() { + match self.ch_or_null() { + c @ '0' ... '9' => { + accum *= 10; + accum += (c as u64) - ('0' as u64); + + // Detect overflow by comparing to the last value. + if accum <= last_accum { return self.error(InvalidNumber); } + + self.bump(); + } + _ => break, + } + } + } + _ => return self.error(InvalidNumber), + } + + Ok(accum) + } + + fn parse_decimal(&mut self, mut res: f64) -> Result { + self.bump(); + + // Make sure a digit follows the decimal place. + match self.ch_or_null() { + '0' ... '9' => (), + _ => return self.error(InvalidNumber) + } + + let mut dec = 1.0; + while !self.eof() { + match self.ch_or_null() { + c @ '0' ... '9' => { + dec /= 10.0; + res += (((c as int) - ('0' as int)) as f64) * dec; + self.bump(); + } + _ => break, + } + } + + Ok(res) + } + + fn parse_exponent(&mut self, mut res: f64) -> Result { + self.bump(); + + let mut exp = 0u; + let mut neg_exp = false; + + if self.ch_is('+') { + self.bump(); + } else if self.ch_is('-') { + self.bump(); + neg_exp = true; + } + + // Make sure a digit follows the exponent place. + match self.ch_or_null() { + '0' ... '9' => (), + _ => return self.error(InvalidNumber) + } + while !self.eof() { + match self.ch_or_null() { + c @ '0' ... '9' => { + exp *= 10; + exp += (c as uint) - ('0' as uint); + + self.bump(); + } + _ => break + } + } + + let exp = 10_f64.powi(exp as i32); + if neg_exp { + res /= exp; + } else { + res *= exp; + } + + Ok(res) + } + + fn decode_hex_escape(&mut self) -> Result { + let mut i = 0u; + let mut n = 0u16; + while i < 4 && !self.eof() { + self.bump(); + n = match self.ch_or_null() { + c @ '0' ... '9' => n * 16 + ((c as u16) - ('0' as u16)), + 'a' | 'A' => n * 16 + 10, + 'b' | 'B' => n * 16 + 11, + 'c' | 'C' => n * 16 + 12, + 'd' | 'D' => n * 16 + 13, + 'e' | 'E' => n * 16 + 14, + 'f' | 'F' => n * 16 + 15, + _ => return self.error(InvalidEscape) + }; + + i += 1u; + } + + // Error out if we didn't parse 4 digits. + if i != 4 { + return self.error(InvalidEscape); + } + + Ok(n) + } + + fn parse_str(&mut self) -> Result { + let mut escape = false; + let mut res = string::String::new(); + + loop { + self.bump(); + if self.eof() { + return self.error(EOFWhileParsingString); + } + + if escape { + match self.ch_or_null() { + '"' => res.push('"'), + '\\' => res.push('\\'), + '/' => res.push('/'), + 'b' => res.push('\x08'), + 'f' => res.push('\x0c'), + 'n' => res.push('\n'), + 'r' => res.push('\r'), + 't' => res.push('\t'), + 'u' => match try!(self.decode_hex_escape()) { + 0xDC00 ... 0xDFFF => { + return self.error(LoneLeadingSurrogateInHexEscape) + } + + // Non-BMP characters are encoded as a sequence of + // two hex escapes, representing UTF-16 surrogates. + n1 @ 0xD800 ... 0xDBFF => { + match (self.next_char(), self.next_char()) { + (Some('\\'), Some('u')) => (), + _ => return self.error(UnexpectedEndOfHexEscape), + } + + let buf = [n1, try!(self.decode_hex_escape())]; + match unicode_str::utf16_items(&buf).next() { + Some(Utf16Item::ScalarValue(c)) => res.push(c), + _ => return self.error(LoneLeadingSurrogateInHexEscape), + } + } + + n => match char::from_u32(n as u32) { + Some(c) => res.push(c), + None => return self.error(InvalidUnicodeCodePoint), + }, + }, + _ => return self.error(InvalidEscape), + } + escape = false; + } else if self.ch_is('\\') { + escape = true; + } else { + match self.ch { + Some('"') => { + self.bump(); + return Ok(res); + }, + Some(c) => res.push(c), + None => unreachable!() + } + } + } + } + + // Invoked at each iteration, consumes the stream until it has enough + // information to return a JsonEvent. + // Manages an internal state so that parsing can be interrupted and resumed. + // Also keeps track of the position in the logical structure of the json + // stream int the form of a stack that can be queried by the user using the + // stack() method. + fn parse(&mut self) -> JsonEvent { + loop { + // The only paths where the loop can spin a new iteration + // are in the cases ParseArrayComma and ParseObjectComma if ',' + // is parsed. In these cases the state is set to (respectively) + // ParseArray(false) and ParseObject(false), which always return, + // so there is no risk of getting stuck in an infinite loop. + // All other paths return before the end of the loop's iteration. + self.parse_whitespace(); + + match self.state { + ParseStart => { + return self.parse_start(); + } + ParseArray(first) => { + return self.parse_array(first); + } + ParseArrayComma => { + match self.parse_array_comma_or_end() { + Some(evt) => { return evt; } + None => {} + } + } + ParseObject(first) => { + return self.parse_object(first); + } + ParseObjectComma => { + self.stack.pop(); + if self.ch_is(',') { + self.state = ParseObject(false); + self.bump(); + } else { + return self.parse_object_end(); + } + } + _ => { + return self.error_event(InvalidSyntax); + } + } + } + } + + fn parse_start(&mut self) -> JsonEvent { + let val = self.parse_value(); + self.state = match val { + Error(_) => ParseFinished, + ArrayStart => ParseArray(true), + ObjectStart => ParseObject(true), + _ => ParseBeforeFinish, + }; + return val; + } + + fn parse_array(&mut self, first: bool) -> JsonEvent { + if self.ch_is(']') { + if !first { + self.error_event(InvalidSyntax) + } else { + self.state = if self.stack.is_empty() { + ParseBeforeFinish + } else if self.stack.last_is_index() { + ParseArrayComma + } else { + ParseObjectComma + }; + self.bump(); + ArrayEnd + } + } else { + if first { + self.stack.push_index(0); + } + let val = self.parse_value(); + self.state = match val { + Error(_) => ParseFinished, + ArrayStart => ParseArray(true), + ObjectStart => ParseObject(true), + _ => ParseArrayComma, + }; + val + } + } + + fn parse_array_comma_or_end(&mut self) -> Option { + if self.ch_is(',') { + self.stack.bump_index(); + self.state = ParseArray(false); + self.bump(); + None + } else if self.ch_is(']') { + self.stack.pop(); + self.state = if self.stack.is_empty() { + ParseBeforeFinish + } else if self.stack.last_is_index() { + ParseArrayComma + } else { + ParseObjectComma + }; + self.bump(); + Some(ArrayEnd) + } else if self.eof() { + Some(self.error_event(EOFWhileParsingArray)) + } else { + Some(self.error_event(InvalidSyntax)) + } + } + + fn parse_object(&mut self, first: bool) -> JsonEvent { + if self.ch_is('}') { + if !first { + if self.stack.is_empty() { + return self.error_event(TrailingComma); + } else { + self.stack.pop(); + } + } + self.state = if self.stack.is_empty() { + ParseBeforeFinish + } else if self.stack.last_is_index() { + ParseArrayComma + } else { + ParseObjectComma + }; + self.bump(); + return ObjectEnd; + } + if self.eof() { + return self.error_event(EOFWhileParsingObject); + } + if !self.ch_is('"') { + return self.error_event(KeyMustBeAString); + } + let s = match self.parse_str() { + Ok(s) => s, + Err(e) => { + self.state = ParseFinished; + return Error(e); + } + }; + self.parse_whitespace(); + if self.eof() { + return self.error_event(EOFWhileParsingObject); + } else if self.ch_or_null() != ':' { + return self.error_event(ExpectedColon); + } + self.stack.push_key(s); + self.bump(); + self.parse_whitespace(); + + let val = self.parse_value(); + + self.state = match val { + Error(_) => ParseFinished, + ArrayStart => ParseArray(true), + ObjectStart => ParseObject(true), + _ => ParseObjectComma, + }; + return val; + } + + fn parse_object_end(&mut self) -> JsonEvent { + if self.ch_is('}') { + self.state = if self.stack.is_empty() { + ParseBeforeFinish + } else if self.stack.last_is_index() { + ParseArrayComma + } else { + ParseObjectComma + }; + self.bump(); + ObjectEnd + } else if self.eof() { + self.error_event(EOFWhileParsingObject) + } else { + self.error_event(InvalidSyntax) + } + } + + fn parse_value(&mut self) -> JsonEvent { + if self.eof() { return self.error_event(EOFWhileParsingValue); } + match self.ch_or_null() { + 'n' => { self.parse_ident("ull", NullValue) } + 't' => { self.parse_ident("rue", BooleanValue(true)) } + 'f' => { self.parse_ident("alse", BooleanValue(false)) } + '0' ... '9' | '-' => self.parse_number(), + '"' => match self.parse_str() { + Ok(s) => StringValue(s), + Err(e) => Error(e), + }, + '[' => { + self.bump(); + ArrayStart + } + '{' => { + self.bump(); + ObjectStart + } + _ => { self.error_event(InvalidSyntax) } + } + } + + fn parse_ident(&mut self, ident: &str, value: JsonEvent) -> JsonEvent { + if ident.chars().all(|c| Some(c) == self.next_char()) { + self.bump(); + value + } else { + Error(SyntaxError(InvalidSyntax, self.line, self.col)) + } + } + + fn error_event(&mut self, reason: ErrorCode) -> JsonEvent { + self.state = ParseFinished; + Error(SyntaxError(reason, self.line, self.col)) + } +} + +/// A Builder consumes a json::Parser to create a generic Json structure. +pub struct Builder { + parser: Parser, + token: Option, +} + +impl> Builder { + /// Create a JSON Builder. + pub fn new(src: T) -> Builder { + Builder { parser: Parser::new(src), token: None, } + } + + // Decode a Json value from a Parser. + pub fn build(&mut self) -> Result { + self.bump(); + let result = self.build_value(); + self.bump(); + match self.token { + None => {} + Some(Error(e)) => { return Err(e); } + ref tok => { panic!("unexpected token {}", tok.clone()); } + } + result + } + + fn bump(&mut self) { + self.token = self.parser.next(); + } + + fn build_value(&mut self) -> Result { + return match self.token { + Some(NullValue) => Ok(Json::Null), + Some(I64Value(n)) => Ok(Json::I64(n)), + Some(U64Value(n)) => Ok(Json::U64(n)), + Some(F64Value(n)) => Ok(Json::F64(n)), + Some(BooleanValue(b)) => Ok(Json::Boolean(b)), + Some(StringValue(ref mut s)) => { + let mut temp = string::String::new(); + swap(s, &mut temp); + Ok(Json::String(temp)) + } + Some(Error(e)) => Err(e), + Some(ArrayStart) => self.build_array(), + Some(ObjectStart) => self.build_object(), + Some(ObjectEnd) => self.parser.error(InvalidSyntax), + Some(ArrayEnd) => self.parser.error(InvalidSyntax), + None => self.parser.error(EOFWhileParsingValue), + } + } + + fn build_array(&mut self) -> Result { + self.bump(); + let mut values = Vec::new(); + + loop { + if self.token == Some(ArrayEnd) { + return Ok(Json::Array(values.into_iter().collect())); + } + match self.build_value() { + Ok(v) => values.push(v), + Err(e) => { return Err(e) } + } + self.bump(); + } + } + + fn build_object(&mut self) -> Result { + self.bump(); + + let mut values = BTreeMap::new(); + + loop { + match self.token { + Some(ObjectEnd) => { return Ok(Json::Object(values)); } + Some(Error(e)) => { return Err(e); } + None => { break; } + _ => {} + } + let key = match self.parser.stack().top() { + Some(Key(k)) => { k.to_string() } + _ => { panic!("invalid state"); } + }; + match self.build_value() { + Ok(value) => { values.insert(key, value); } + Err(e) => { return Err(e); } + } + self.bump(); + } + return self.parser.error(EOFWhileParsingObject); + } +} + +/// Decodes a json value from an `&mut io::Reader` +pub fn from_reader(rdr: &mut io::Reader) -> Result { + let contents = match rdr.read_to_end() { + Ok(c) => c, + Err(e) => return Err(io_error_to_error(e)) + }; + let s = match str::from_utf8(contents.as_slice()).ok() { + Some(s) => s, + _ => return Err(SyntaxError(NotUtf8, 0, 0)) + }; + let mut builder = Builder::new(s.chars()); + builder.build() +} + +/// Decodes a json value from a string +pub fn from_str(s: &str) -> Result { + let mut builder = Builder::new(s.chars()); + builder.build() +} + +/// A structure to decode JSON to values in rust. +pub struct Decoder { + stack: Vec, +} + +impl Decoder { + /// Creates a new decoder instance for decoding the specified JSON value. + pub fn new(json: Json) -> Decoder { + Decoder { stack: vec![json] } + } +} + +impl Decoder { + fn pop(&mut self) -> Json { + self.stack.pop().unwrap() + } +} + +macro_rules! expect { + ($e:expr, Null) => ({ + match $e { + Json::Null => Ok(()), + other => Err(ExpectedError("Null".to_string(), + format!("{}", other))) + } + }); + ($e:expr, $t:ident) => ({ + match $e { + Json::$t(v) => Ok(v), + other => { + Err(ExpectedError(stringify!($t).to_string(), + format!("{}", other))) + } + } + }) +} + +macro_rules! read_primitive { + ($name:ident, $ty:ty) => { + fn $name(&mut self) -> DecodeResult<$ty> { + match self.pop() { + Json::I64(f) => match num::cast(f) { + Some(f) => Ok(f), + None => Err(ExpectedError("Number".to_string(), format!("{}", f))), + }, + Json::U64(f) => match num::cast(f) { + Some(f) => Ok(f), + None => Err(ExpectedError("Number".to_string(), format!("{}", f))), + }, + Json::F64(f) => Err(ExpectedError("Integer".to_string(), format!("{}", f))), + // re: #12967.. a type w/ numeric keys (ie HashMap etc) + // is going to have a string here, as per JSON spec. + Json::String(s) => match s.parse() { + Some(f) => Ok(f), + None => Err(ExpectedError("Number".to_string(), s)), + }, + value => Err(ExpectedError("Number".to_string(), format!("{}", value))), + } + } + } +} + +impl ::Decoder for Decoder { + fn read_nil(&mut self) -> DecodeResult<()> { + expect!(self.pop(), Null) + } + + read_primitive! { read_uint, uint } + read_primitive! { read_u8, u8 } + read_primitive! { read_u16, u16 } + read_primitive! { read_u32, u32 } + read_primitive! { read_u64, u64 } + read_primitive! { read_int, int } + read_primitive! { read_i8, i8 } + read_primitive! { read_i16, i16 } + read_primitive! { read_i32, i32 } + read_primitive! { read_i64, i64 } + + fn read_f32(&mut self) -> DecodeResult { self.read_f64().map(|x| x as f32) } + + fn read_f64(&mut self) -> DecodeResult { + match self.pop() { + Json::I64(f) => Ok(f as f64), + Json::U64(f) => Ok(f as f64), + Json::F64(f) => Ok(f), + Json::String(s) => { + // re: #12967.. a type w/ numeric keys (ie HashMap etc) + // is going to have a string here, as per JSON spec. + match s.parse() { + Some(f) => Ok(f), + None => Err(ExpectedError("Number".to_string(), s)), + } + }, + Json::Null => Ok(f64::NAN), + value => Err(ExpectedError("Number".to_string(), format!("{}", value))) + } + } + + fn read_bool(&mut self) -> DecodeResult { + expect!(self.pop(), Boolean) + } + + fn read_char(&mut self) -> DecodeResult { + let s = try!(self.read_str()); + { + let mut it = s.chars(); + match (it.next(), it.next()) { + // exactly one character + (Some(c), None) => return Ok(c), + _ => () + } + } + Err(ExpectedError("single character string".to_string(), format!("{}", s))) + } + + fn read_str(&mut self) -> DecodeResult { + expect!(self.pop(), String) + } + + fn read_enum(&mut self, _name: &str, f: F) -> DecodeResult where + F: FnOnce(&mut Decoder) -> DecodeResult, + { + f(self) + } + + fn read_enum_variant(&mut self, names: &[&str], + mut f: F) -> DecodeResult + where F: FnMut(&mut Decoder, uint) -> DecodeResult, + { + let name = match self.pop() { + Json::String(s) => s, + Json::Object(mut o) => { + let n = match o.remove(&"variant".to_string()) { + Some(Json::String(s)) => s, + Some(val) => { + return Err(ExpectedError("String".to_string(), format!("{}", val))) + } + None => { + return Err(MissingFieldError("variant".to_string())) + } + }; + match o.remove(&"fields".to_string()) { + Some(Json::Array(l)) => { + for field in l.into_iter().rev() { + self.stack.push(field); + } + }, + Some(val) => { + return Err(ExpectedError("Array".to_string(), format!("{}", val))) + } + None => { + return Err(MissingFieldError("fields".to_string())) + } + } + n + } + json => { + return Err(ExpectedError("String or Object".to_string(), format!("{}", json))) + } + }; + let idx = match names.iter().position(|n| *n == name[]) { + Some(idx) => idx, + None => return Err(UnknownVariantError(name)) + }; + f(self, idx) + } + + fn read_enum_variant_arg(&mut self, _idx: uint, f: F) -> DecodeResult where + F: FnOnce(&mut Decoder) -> DecodeResult, + { + f(self) + } + + fn read_enum_struct_variant(&mut self, names: &[&str], f: F) -> DecodeResult where + F: FnMut(&mut Decoder, uint) -> DecodeResult, + { + self.read_enum_variant(names, f) + } + + + fn read_enum_struct_variant_field(&mut self, + _name: &str, + idx: uint, + f: F) + -> DecodeResult where + F: FnOnce(&mut Decoder) -> DecodeResult, + { + self.read_enum_variant_arg(idx, f) + } + + fn read_struct(&mut self, _name: &str, _len: uint, f: F) -> DecodeResult where + F: FnOnce(&mut Decoder) -> DecodeResult, + { + let value = try!(f(self)); + self.pop(); + Ok(value) + } + + fn read_struct_field(&mut self, + name: &str, + _idx: uint, + f: F) + -> DecodeResult where + F: FnOnce(&mut Decoder) -> DecodeResult, + { + let mut obj = try!(expect!(self.pop(), Object)); + + let value = match obj.remove(&name.to_string()) { + None => { + // Add a Null and try to parse it as an Option<_> + // to get None as a default value. + self.stack.push(Json::Null); + match f(self) { + Ok(x) => x, + Err(_) => return Err(MissingFieldError(name.to_string())), + } + }, + Some(json) => { + self.stack.push(json); + try!(f(self)) + } + }; + self.stack.push(Json::Object(obj)); + Ok(value) + } + + fn read_tuple(&mut self, tuple_len: uint, f: F) -> DecodeResult where + F: FnOnce(&mut Decoder) -> DecodeResult, + { + self.read_seq(move |d, len| { + if len == tuple_len { + f(d) + } else { + Err(ExpectedError(format!("Tuple{}", tuple_len), format!("Tuple{}", len))) + } + }) + } + + fn read_tuple_arg(&mut self, idx: uint, f: F) -> DecodeResult where + F: FnOnce(&mut Decoder) -> DecodeResult, + { + self.read_seq_elt(idx, f) + } + + fn read_tuple_struct(&mut self, + _name: &str, + len: uint, + f: F) + -> DecodeResult where + F: FnOnce(&mut Decoder) -> DecodeResult, + { + self.read_tuple(len, f) + } + + fn read_tuple_struct_arg(&mut self, + idx: uint, + f: F) + -> DecodeResult where + F: FnOnce(&mut Decoder) -> DecodeResult, + { + self.read_tuple_arg(idx, f) + } + + fn read_option(&mut self, mut f: F) -> DecodeResult where + F: FnMut(&mut Decoder, bool) -> DecodeResult, + { + match self.pop() { + Json::Null => f(self, false), + value => { self.stack.push(value); f(self, true) } + } + } + + fn read_seq(&mut self, f: F) -> DecodeResult where + F: FnOnce(&mut Decoder, uint) -> DecodeResult, + { + let array = try!(expect!(self.pop(), Array)); + let len = array.len(); + for v in array.into_iter().rev() { + self.stack.push(v); + } + f(self, len) + } + + fn read_seq_elt(&mut self, _idx: uint, f: F) -> DecodeResult where + F: FnOnce(&mut Decoder) -> DecodeResult, + { + f(self) + } + + fn read_map(&mut self, f: F) -> DecodeResult where + F: FnOnce(&mut Decoder, uint) -> DecodeResult, + { + let obj = try!(expect!(self.pop(), Object)); + let len = obj.len(); + for (key, value) in obj.into_iter() { + self.stack.push(value); + self.stack.push(Json::String(key)); + } + f(self, len) + } + + fn read_map_elt_key(&mut self, _idx: uint, f: F) -> DecodeResult where + F: FnOnce(&mut Decoder) -> DecodeResult, + { + f(self) + } + + fn read_map_elt_val(&mut self, _idx: uint, f: F) -> DecodeResult where + F: FnOnce(&mut Decoder) -> DecodeResult, + { + f(self) + } + + fn error(&mut self, err: &str) -> DecoderError { + ApplicationError(err.to_string()) + } +} + +/// A trait for converting values to JSON +pub trait ToJson for Sized? { + /// Converts the value of `self` to an instance of JSON + fn to_json(&self) -> Json; +} + +macro_rules! to_json_impl_i64 { + ($($t:ty), +) => ( + $(impl ToJson for $t { + fn to_json(&self) -> Json { Json::I64(*self as i64) } + })+ + ) +} + +to_json_impl_i64! { int, i8, i16, i32, i64 } + +macro_rules! to_json_impl_u64 { + ($($t:ty), +) => ( + $(impl ToJson for $t { + fn to_json(&self) -> Json { Json::U64(*self as u64) } + })+ + ) +} + +to_json_impl_u64! { uint, u8, u16, u32, u64 } + +impl ToJson for Json { + fn to_json(&self) -> Json { self.clone() } +} + +impl ToJson for f32 { + fn to_json(&self) -> Json { (*self as f64).to_json() } +} + +impl ToJson for f64 { + fn to_json(&self) -> Json { + match self.classify() { + Fp::Nan | Fp::Infinite => Json::Null, + _ => Json::F64(*self) + } + } +} + +impl ToJson for () { + fn to_json(&self) -> Json { Json::Null } +} + +impl ToJson for bool { + fn to_json(&self) -> Json { Json::Boolean(*self) } +} + +impl ToJson for str { + fn to_json(&self) -> Json { Json::String(self.to_string()) } +} + +impl ToJson for string::String { + fn to_json(&self) -> Json { Json::String((*self).clone()) } +} + +macro_rules! tuple_impl { + // use variables to indicate the arity of the tuple + ($($tyvar:ident),* ) => { + // the trailing commas are for the 1 tuple + impl< + $( $tyvar : ToJson ),* + > ToJson for ( $( $tyvar ),* , ) { + + #[inline] + #[allow(non_snake_case)] + fn to_json(&self) -> Json { + match *self { + ($(ref $tyvar),*,) => Json::Array(vec![$($tyvar.to_json()),*]) + } + } + } + } +} + +tuple_impl!{A} +tuple_impl!{A, B} +tuple_impl!{A, B, C} +tuple_impl!{A, B, C, D} +tuple_impl!{A, B, C, D, E} +tuple_impl!{A, B, C, D, E, F} +tuple_impl!{A, B, C, D, E, F, G} +tuple_impl!{A, B, C, D, E, F, G, H} +tuple_impl!{A, B, C, D, E, F, G, H, I} +tuple_impl!{A, B, C, D, E, F, G, H, I, J} +tuple_impl!{A, B, C, D, E, F, G, H, I, J, K} +tuple_impl!{A, B, C, D, E, F, G, H, I, J, K, L} + +impl ToJson for [A] { + fn to_json(&self) -> Json { Json::Array(self.iter().map(|elt| elt.to_json()).collect()) } +} + +impl ToJson for Vec { + fn to_json(&self) -> Json { Json::Array(self.iter().map(|elt| elt.to_json()).collect()) } +} + +impl ToJson for BTreeMap { + fn to_json(&self) -> Json { + let mut d = BTreeMap::new(); + for (key, value) in self.iter() { + d.insert((*key).clone(), value.to_json()); + } + Json::Object(d) + } +} + +impl ToJson for HashMap { + fn to_json(&self) -> Json { + let mut d = BTreeMap::new(); + for (key, value) in self.iter() { + d.insert((*key).clone(), value.to_json()); + } + Json::Object(d) + } +} + +impl ToJson for Option { + fn to_json(&self) -> Json { + match *self { + None => Json::Null, + Some(ref value) => value.to_json() + } + } +} + +struct FormatShim<'a, 'b: 'a> { + inner: &'a mut fmt::Formatter<'b>, +} + +impl<'a, 'b> fmt::Writer for FormatShim<'a, 'b> { + fn write_str(&mut self, s: &str) -> fmt::Result { + self.inner.write_str(s) + } +} + +impl fmt::Show for Json { + /// Encodes a json value into a string + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let mut shim = FormatShim { inner: f }; + let mut encoder = Encoder::new(&mut shim); + self.encode(&mut encoder) + } +} + +impl<'a> fmt::Show for PrettyJson<'a> { + /// Encodes a json value into a string + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let mut shim = FormatShim { inner: f }; + let mut encoder = PrettyEncoder::new(&mut shim); + self.inner.encode(&mut encoder) + } +} + +impl<'a, T> fmt::Show for AsJson<'a, T> + where T: for<'b> Encodable, fmt::Error> +{ + /// Encodes a json value into a string + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let mut shim = FormatShim { inner: f }; + let mut encoder = Encoder::new(&mut shim); + self.inner.encode(&mut encoder) + } +} + +impl<'a, T> AsPrettyJson<'a, T> { + /// Set the indentation level for the emitted JSON + pub fn indent(mut self, indent: uint) -> AsPrettyJson<'a, T> { + self.indent = Some(indent); + self + } +} + +impl<'a, T> fmt::Show for AsPrettyJson<'a, T> + where T: for<'b> Encodable, fmt::Error> +{ + /// Encodes a json value into a string + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let mut shim = FormatShim { inner: f }; + let mut encoder = PrettyEncoder::new(&mut shim); + match self.indent { + Some(n) => encoder.set_indent(n), + None => {} + } + self.inner.encode(&mut encoder) + } +} + +impl FromStr for Json { + fn from_str(s: &str) -> Option { + from_str(s).ok() + } +} + +#[cfg(test)] +mod tests { + extern crate test; + use self::Animal::*; + use self::DecodeEnum::*; + use self::test::Bencher; + use {Encodable, Decodable}; + use super::Json::*; + use super::ErrorCode::*; + use super::ParserError::*; + use super::DecoderError::*; + use super::JsonEvent::*; + use super::StackElement::*; + use super::{Json, from_str, DecodeResult, DecoderError, JsonEvent, Parser, + StackElement, Stack, Decoder}; + use std::{i64, u64, f32, f64}; + use std::collections::BTreeMap; + use std::num::Float; + use std::string; + + #[derive(RustcDecodable, Eq, PartialEq, Show)] + struct OptionData { + opt: Option, + } + + #[test] + fn test_decode_option_none() { + let s ="{}"; + let obj: OptionData = super::decode(s).unwrap(); + assert_eq!(obj, OptionData { opt: None }); + } + + #[test] + fn test_decode_option_some() { + let s = "{ \"opt\": 10 }"; + let obj: OptionData = super::decode(s).unwrap(); + assert_eq!(obj, OptionData { opt: Some(10u) }); + } + + #[test] + fn test_decode_option_malformed() { + check_err::("{ \"opt\": [] }", + ExpectedError("Number".to_string(), "[]".to_string())); + check_err::("{ \"opt\": false }", + ExpectedError("Number".to_string(), "false".to_string())); + } + + #[derive(PartialEq, RustcEncodable, RustcDecodable, Show)] + enum Animal { + Dog, + Frog(string::String, int) + } + + #[derive(PartialEq, RustcEncodable, RustcDecodable, Show)] + struct Inner { + a: (), + b: uint, + c: Vec, + } + + #[derive(PartialEq, RustcEncodable, RustcDecodable, Show)] + struct Outer { + inner: Vec, + } + + fn mk_object(items: &[(string::String, Json)]) -> Json { + let mut d = BTreeMap::new(); + + for item in items.iter() { + match *item { + (ref key, ref value) => { d.insert((*key).clone(), (*value).clone()); }, + } + }; + + Object(d) + } + + #[test] + fn test_from_str_trait() { + let s = "null"; + assert!(s.parse::().unwrap() == s.parse().unwrap()); + } + + #[test] + fn test_write_null() { + assert_eq!(Null.to_string(), "null"); + assert_eq!(Null.pretty().to_string(), "null"); + } + + #[test] + fn test_write_i64() { + assert_eq!(U64(0).to_string(), "0"); + assert_eq!(U64(0).pretty().to_string(), "0"); + + assert_eq!(U64(1234).to_string(), "1234"); + assert_eq!(U64(1234).pretty().to_string(), "1234"); + + assert_eq!(I64(-5678).to_string(), "-5678"); + assert_eq!(I64(-5678).pretty().to_string(), "-5678"); + + assert_eq!(U64(7650007200025252000).to_string(), "7650007200025252000"); + assert_eq!(U64(7650007200025252000).pretty().to_string(), "7650007200025252000"); + } + + #[test] + fn test_write_f64() { + assert_eq!(F64(3.0).to_string(), "3.0"); + assert_eq!(F64(3.0).pretty().to_string(), "3.0"); + + assert_eq!(F64(3.1).to_string(), "3.1"); + assert_eq!(F64(3.1).pretty().to_string(), "3.1"); + + assert_eq!(F64(-1.5).to_string(), "-1.5"); + assert_eq!(F64(-1.5).pretty().to_string(), "-1.5"); + + assert_eq!(F64(0.5).to_string(), "0.5"); + assert_eq!(F64(0.5).pretty().to_string(), "0.5"); + + assert_eq!(F64(f64::NAN).to_string(), "null"); + assert_eq!(F64(f64::NAN).pretty().to_string(), "null"); + + assert_eq!(F64(f64::INFINITY).to_string(), "null"); + assert_eq!(F64(f64::INFINITY).pretty().to_string(), "null"); + + assert_eq!(F64(f64::NEG_INFINITY).to_string(), "null"); + assert_eq!(F64(f64::NEG_INFINITY).pretty().to_string(), "null"); + } + + #[test] + fn test_write_str() { + assert_eq!(String("".to_string()).to_string(), "\"\""); + assert_eq!(String("".to_string()).pretty().to_string(), "\"\""); + + assert_eq!(String("homura".to_string()).to_string(), "\"homura\""); + assert_eq!(String("madoka".to_string()).pretty().to_string(), "\"madoka\""); + } + + #[test] + fn test_write_bool() { + assert_eq!(Boolean(true).to_string(), "true"); + assert_eq!(Boolean(true).pretty().to_string(), "true"); + + assert_eq!(Boolean(false).to_string(), "false"); + assert_eq!(Boolean(false).pretty().to_string(), "false"); + } + + #[test] + fn test_write_array() { + assert_eq!(Array(vec![]).to_string(), "[]"); + assert_eq!(Array(vec![]).pretty().to_string(), "[]"); + + assert_eq!(Array(vec![Boolean(true)]).to_string(), "[true]"); + assert_eq!( + Array(vec![Boolean(true)]).pretty().to_string(), + "\ + [\n \ + true\n\ + ]" + ); + + let long_test_array = Array(vec![ + Boolean(false), + Null, + Array(vec![String("foo\nbar".to_string()), F64(3.5)])]); + + assert_eq!(long_test_array.to_string(), + "[false,null,[\"foo\\nbar\",3.5]]"); + assert_eq!( + long_test_array.pretty().to_string(), + "\ + [\n \ + false,\n \ + null,\n \ + [\n \ + \"foo\\nbar\",\n \ + 3.5\n \ + ]\n\ + ]" + ); + } + + #[test] + fn test_write_object() { + assert_eq!(mk_object(&[]).to_string(), "{}"); + assert_eq!(mk_object(&[]).pretty().to_string(), "{}"); + + assert_eq!( + mk_object(&[ + ("a".to_string(), Boolean(true)) + ]).to_string(), + "{\"a\":true}" + ); + assert_eq!( + mk_object(&[("a".to_string(), Boolean(true))]).pretty().to_string(), + "\ + {\n \ + \"a\": true\n\ + }" + ); + + let complex_obj = mk_object(&[ + ("b".to_string(), Array(vec![ + mk_object(&[("c".to_string(), String("\x0c\r".to_string()))]), + mk_object(&[("d".to_string(), String("".to_string()))]) + ])) + ]); + + assert_eq!( + complex_obj.to_string(), + "{\ + \"b\":[\ + {\"c\":\"\\f\\r\"},\ + {\"d\":\"\"}\ + ]\ + }" + ); + assert_eq!( + complex_obj.pretty().to_string(), + "\ + {\n \ + \"b\": [\n \ + {\n \ + \"c\": \"\\f\\r\"\n \ + },\n \ + {\n \ + \"d\": \"\"\n \ + }\n \ + ]\n\ + }" + ); + + let a = mk_object(&[ + ("a".to_string(), Boolean(true)), + ("b".to_string(), Array(vec![ + mk_object(&[("c".to_string(), String("\x0c\r".to_string()))]), + mk_object(&[("d".to_string(), String("".to_string()))]) + ])) + ]); + + // We can't compare the strings directly because the object fields be + // printed in a different order. + assert_eq!(a.clone(), a.to_string().parse().unwrap()); + assert_eq!(a.clone(), a.pretty().to_string().parse().unwrap()); + } + + #[test] + fn test_write_enum() { + let animal = Dog; + assert_eq!( + format!("{}", super::as_json(&animal)), + "\"Dog\"" + ); + assert_eq!( + format!("{}", super::as_pretty_json(&animal)), + "\"Dog\"" + ); + + let animal = Frog("Henry".to_string(), 349); + assert_eq!( + format!("{}", super::as_json(&animal)), + "{\"variant\":\"Frog\",\"fields\":[\"Henry\",349]}" + ); + assert_eq!( + format!("{}", super::as_pretty_json(&animal)), + "{\n \ + \"variant\": \"Frog\",\n \ + \"fields\": [\n \ + \"Henry\",\n \ + 349\n \ + ]\n\ + }" + ); + } + + macro_rules! check_encoder_for_simple { + ($value:expr, $expected:expr) => ({ + let s = format!("{}", super::as_json(&$value)); + assert_eq!(s, $expected); + + let s = format!("{}", super::as_pretty_json(&$value)); + assert_eq!(s, $expected); + }) + } + + #[test] + fn test_write_some() { + check_encoder_for_simple!(Some("jodhpurs".to_string()), "\"jodhpurs\""); + } + + #[test] + fn test_write_none() { + check_encoder_for_simple!(None::, "null"); + } + + #[test] + fn test_write_char() { + check_encoder_for_simple!('a', "\"a\""); + check_encoder_for_simple!('\t', "\"\\t\""); + check_encoder_for_simple!('\u{0000}', "\"\\u0000\""); + check_encoder_for_simple!('\u{001b}', "\"\\u001b\""); + check_encoder_for_simple!('\u{007f}', "\"\\u007f\""); + check_encoder_for_simple!('\u{00a0}', "\"\u{00a0}\""); + check_encoder_for_simple!('\u{abcd}', "\"\u{abcd}\""); + check_encoder_for_simple!('\u{10ffff}', "\"\u{10ffff}\""); + } + + #[test] + fn test_trailing_characters() { + assert_eq!(from_str("nulla"), Err(SyntaxError(TrailingCharacters, 1, 5))); + assert_eq!(from_str("truea"), Err(SyntaxError(TrailingCharacters, 1, 5))); + assert_eq!(from_str("falsea"), Err(SyntaxError(TrailingCharacters, 1, 6))); + assert_eq!(from_str("1a"), Err(SyntaxError(TrailingCharacters, 1, 2))); + assert_eq!(from_str("[]a"), Err(SyntaxError(TrailingCharacters, 1, 3))); + assert_eq!(from_str("{}a"), Err(SyntaxError(TrailingCharacters, 1, 3))); + } + + #[test] + fn test_read_identifiers() { + assert_eq!(from_str("n"), Err(SyntaxError(InvalidSyntax, 1, 2))); + assert_eq!(from_str("nul"), Err(SyntaxError(InvalidSyntax, 1, 4))); + assert_eq!(from_str("t"), Err(SyntaxError(InvalidSyntax, 1, 2))); + assert_eq!(from_str("truz"), Err(SyntaxError(InvalidSyntax, 1, 4))); + assert_eq!(from_str("f"), Err(SyntaxError(InvalidSyntax, 1, 2))); + assert_eq!(from_str("faz"), Err(SyntaxError(InvalidSyntax, 1, 3))); + + assert_eq!(from_str("null"), Ok(Null)); + assert_eq!(from_str("true"), Ok(Boolean(true))); + assert_eq!(from_str("false"), Ok(Boolean(false))); + assert_eq!(from_str(" null "), Ok(Null)); + assert_eq!(from_str(" true "), Ok(Boolean(true))); + assert_eq!(from_str(" false "), Ok(Boolean(false))); + } + + #[test] + fn test_decode_identifiers() { + let v: () = super::decode("null").unwrap(); + assert_eq!(v, ()); + + let v: bool = super::decode("true").unwrap(); + assert_eq!(v, true); + + let v: bool = super::decode("false").unwrap(); + assert_eq!(v, false); + } + + #[test] + fn test_read_number() { + assert_eq!(from_str("+"), Err(SyntaxError(InvalidSyntax, 1, 1))); + assert_eq!(from_str("."), Err(SyntaxError(InvalidSyntax, 1, 1))); + assert_eq!(from_str("NaN"), Err(SyntaxError(InvalidSyntax, 1, 1))); + assert_eq!(from_str("-"), Err(SyntaxError(InvalidNumber, 1, 2))); + assert_eq!(from_str("00"), Err(SyntaxError(InvalidNumber, 1, 2))); + assert_eq!(from_str("1."), Err(SyntaxError(InvalidNumber, 1, 3))); + assert_eq!(from_str("1e"), Err(SyntaxError(InvalidNumber, 1, 3))); + assert_eq!(from_str("1e+"), Err(SyntaxError(InvalidNumber, 1, 4))); + + assert_eq!(from_str("18446744073709551616"), Err(SyntaxError(InvalidNumber, 1, 20))); + assert_eq!(from_str("-9223372036854775809"), Err(SyntaxError(InvalidNumber, 1, 21))); + + assert_eq!(from_str("3"), Ok(U64(3))); + assert_eq!(from_str("3.1"), Ok(F64(3.1))); + assert_eq!(from_str("-1.2"), Ok(F64(-1.2))); + assert_eq!(from_str("0.4"), Ok(F64(0.4))); + assert_eq!(from_str("0.4e5"), Ok(F64(0.4e5))); + assert_eq!(from_str("0.4e+15"), Ok(F64(0.4e15))); + assert_eq!(from_str("0.4e-01"), Ok(F64(0.4e-01))); + assert_eq!(from_str(" 3 "), Ok(U64(3))); + + assert_eq!(from_str("-9223372036854775808"), Ok(I64(i64::MIN))); + assert_eq!(from_str("9223372036854775807"), Ok(U64(i64::MAX as u64))); + assert_eq!(from_str("18446744073709551615"), Ok(U64(u64::MAX))); + } + + #[test] + fn test_decode_numbers() { + let v: f64 = super::decode("3").unwrap(); + assert_eq!(v, 3.0); + + let v: f64 = super::decode("3.1").unwrap(); + assert_eq!(v, 3.1); + + let v: f64 = super::decode("-1.2").unwrap(); + assert_eq!(v, -1.2); + + let v: f64 = super::decode("0.4").unwrap(); + assert_eq!(v, 0.4); + + let v: f64 = super::decode("0.4e5").unwrap(); + assert_eq!(v, 0.4e5); + + let v: f64 = super::decode("0.4e15").unwrap(); + assert_eq!(v, 0.4e15); + + let v: f64 = super::decode("0.4e-01").unwrap(); + assert_eq!(v, 0.4e-01); + + let v: u64 = super::decode("0").unwrap(); + assert_eq!(v, 0); + + let v: u64 = super::decode("18446744073709551615").unwrap(); + assert_eq!(v, u64::MAX); + + let v: i64 = super::decode("-9223372036854775808").unwrap(); + assert_eq!(v, i64::MIN); + + let v: i64 = super::decode("9223372036854775807").unwrap(); + assert_eq!(v, i64::MAX); + + let res: DecodeResult = super::decode("765.25252"); + assert_eq!(res, Err(ExpectedError("Integer".to_string(), "765.25252".to_string()))); + } + + #[test] + fn test_read_str() { + assert_eq!(from_str("\""), Err(SyntaxError(EOFWhileParsingString, 1, 2))); + assert_eq!(from_str("\"lol"), Err(SyntaxError(EOFWhileParsingString, 1, 5))); + + assert_eq!(from_str("\"\""), Ok(String("".to_string()))); + assert_eq!(from_str("\"foo\""), Ok(String("foo".to_string()))); + assert_eq!(from_str("\"\\\"\""), Ok(String("\"".to_string()))); + assert_eq!(from_str("\"\\b\""), Ok(String("\x08".to_string()))); + assert_eq!(from_str("\"\\n\""), Ok(String("\n".to_string()))); + assert_eq!(from_str("\"\\r\""), Ok(String("\r".to_string()))); + assert_eq!(from_str("\"\\t\""), Ok(String("\t".to_string()))); + assert_eq!(from_str(" \"foo\" "), Ok(String("foo".to_string()))); + assert_eq!(from_str("\"\\u12ab\""), Ok(String("\u{12ab}".to_string()))); + assert_eq!(from_str("\"\\uAB12\""), Ok(String("\u{AB12}".to_string()))); + } + + #[test] + fn test_decode_str() { + let s = [("\"\"", ""), + ("\"foo\"", "foo"), + ("\"\\\"\"", "\""), + ("\"\\b\"", "\x08"), + ("\"\\n\"", "\n"), + ("\"\\r\"", "\r"), + ("\"\\t\"", "\t"), + ("\"\\u12ab\"", "\u{12ab}"), + ("\"\\uAB12\"", "\u{AB12}")]; + + for &(i, o) in s.iter() { + let v: string::String = super::decode(i).unwrap(); + assert_eq!(v, o); + } + } + + #[test] + fn test_read_array() { + assert_eq!(from_str("["), Err(SyntaxError(EOFWhileParsingValue, 1, 2))); + assert_eq!(from_str("[1"), Err(SyntaxError(EOFWhileParsingArray, 1, 3))); + assert_eq!(from_str("[1,"), Err(SyntaxError(EOFWhileParsingValue, 1, 4))); + assert_eq!(from_str("[1,]"), Err(SyntaxError(InvalidSyntax, 1, 4))); + assert_eq!(from_str("[6 7]"), Err(SyntaxError(InvalidSyntax, 1, 4))); + + assert_eq!(from_str("[]"), Ok(Array(vec![]))); + assert_eq!(from_str("[ ]"), Ok(Array(vec![]))); + assert_eq!(from_str("[true]"), Ok(Array(vec![Boolean(true)]))); + assert_eq!(from_str("[ false ]"), Ok(Array(vec![Boolean(false)]))); + assert_eq!(from_str("[null]"), Ok(Array(vec![Null]))); + assert_eq!(from_str("[3, 1]"), + Ok(Array(vec![U64(3), U64(1)]))); + assert_eq!(from_str("\n[3, 2]\n"), + Ok(Array(vec![U64(3), U64(2)]))); + assert_eq!(from_str("[2, [4, 1]]"), + Ok(Array(vec![U64(2), Array(vec![U64(4), U64(1)])]))); + } + + #[test] + fn test_decode_array() { + let v: Vec<()> = super::decode("[]").unwrap(); + assert_eq!(v, vec![]); + + let v: Vec<()> = super::decode("[null]").unwrap(); + assert_eq!(v, vec![()]); + + let v: Vec = super::decode("[true]").unwrap(); + assert_eq!(v, vec![true]); + + let v: Vec = super::decode("[3, 1]").unwrap(); + assert_eq!(v, vec![3, 1]); + + let v: Vec> = super::decode("[[3], [1, 2]]").unwrap(); + assert_eq!(v, vec![vec![3], vec![1, 2]]); + } + + #[test] + fn test_decode_tuple() { + let t: (uint, uint, uint) = super::decode("[1, 2, 3]").unwrap(); + assert_eq!(t, (1u, 2, 3)); + + let t: (uint, string::String) = super::decode("[1, \"two\"]").unwrap(); + assert_eq!(t, (1u, "two".to_string())); + } + + #[test] + fn test_decode_tuple_malformed_types() { + assert!(super::decode::<(uint, string::String)>("[1, 2]").is_err()); + } + + #[test] + fn test_decode_tuple_malformed_length() { + assert!(super::decode::<(uint, uint)>("[1, 2, 3]").is_err()); + } + + #[test] + fn test_read_object() { + assert_eq!(from_str("{"), Err(SyntaxError(EOFWhileParsingObject, 1, 2))); + assert_eq!(from_str("{ "), Err(SyntaxError(EOFWhileParsingObject, 1, 3))); + assert_eq!(from_str("{1"), Err(SyntaxError(KeyMustBeAString, 1, 2))); + assert_eq!(from_str("{ \"a\""), Err(SyntaxError(EOFWhileParsingObject, 1, 6))); + assert_eq!(from_str("{\"a\""), Err(SyntaxError(EOFWhileParsingObject, 1, 5))); + assert_eq!(from_str("{\"a\" "), Err(SyntaxError(EOFWhileParsingObject, 1, 6))); + + assert_eq!(from_str("{\"a\" 1"), Err(SyntaxError(ExpectedColon, 1, 6))); + assert_eq!(from_str("{\"a\":"), Err(SyntaxError(EOFWhileParsingValue, 1, 6))); + assert_eq!(from_str("{\"a\":1"), Err(SyntaxError(EOFWhileParsingObject, 1, 7))); + assert_eq!(from_str("{\"a\":1 1"), Err(SyntaxError(InvalidSyntax, 1, 8))); + assert_eq!(from_str("{\"a\":1,"), Err(SyntaxError(EOFWhileParsingObject, 1, 8))); + + assert_eq!(from_str("{}").unwrap(), mk_object(&[])); + assert_eq!(from_str("{\"a\": 3}").unwrap(), + mk_object(&[("a".to_string(), U64(3))])); + + assert_eq!(from_str( + "{ \"a\": null, \"b\" : true }").unwrap(), + mk_object(&[ + ("a".to_string(), Null), + ("b".to_string(), Boolean(true))])); + assert_eq!(from_str("\n{ \"a\": null, \"b\" : true }\n").unwrap(), + mk_object(&[ + ("a".to_string(), Null), + ("b".to_string(), Boolean(true))])); + assert_eq!(from_str( + "{\"a\" : 1.0 ,\"b\": [ true ]}").unwrap(), + mk_object(&[ + ("a".to_string(), F64(1.0)), + ("b".to_string(), Array(vec![Boolean(true)])) + ])); + assert_eq!(from_str( + "{\ + \"a\": 1.0, \ + \"b\": [\ + true,\ + \"foo\\nbar\", \ + { \"c\": {\"d\": null} } \ + ]\ + }").unwrap(), + mk_object(&[ + ("a".to_string(), F64(1.0)), + ("b".to_string(), Array(vec![ + Boolean(true), + String("foo\nbar".to_string()), + mk_object(&[ + ("c".to_string(), mk_object(&[("d".to_string(), Null)])) + ]) + ])) + ])); + } + + #[test] + fn test_decode_struct() { + let s = "{ + \"inner\": [ + { \"a\": null, \"b\": 2, \"c\": [\"abc\", \"xyz\"] } + ] + }"; + + let v: Outer = super::decode(s).unwrap(); + assert_eq!( + v, + Outer { + inner: vec![ + Inner { a: (), b: 2, c: vec!["abc".to_string(), "xyz".to_string()] } + ] + } + ); + } + + #[derive(RustcDecodable)] + struct FloatStruct { + f: f64, + a: Vec + } + #[test] + fn test_decode_struct_with_nan() { + let s = "{\"f\":null,\"a\":[null,123]}"; + let obj: FloatStruct = super::decode(s).unwrap(); + assert!(obj.f.is_nan()); + assert!(obj.a[0].is_nan()); + assert_eq!(obj.a[1], 123f64); + } + + #[test] + fn test_decode_option() { + let value: Option = super::decode("null").unwrap(); + assert_eq!(value, None); + + let value: Option = super::decode("\"jodhpurs\"").unwrap(); + assert_eq!(value, Some("jodhpurs".to_string())); + } + + #[test] + fn test_decode_enum() { + let value: Animal = super::decode("\"Dog\"").unwrap(); + assert_eq!(value, Dog); + + let s = "{\"variant\":\"Frog\",\"fields\":[\"Henry\",349]}"; + let value: Animal = super::decode(s).unwrap(); + assert_eq!(value, Frog("Henry".to_string(), 349)); + } + + #[test] + fn test_decode_map() { + let s = "{\"a\": \"Dog\", \"b\": {\"variant\":\"Frog\",\ + \"fields\":[\"Henry\", 349]}}"; + let mut map: BTreeMap = super::decode(s).unwrap(); + + assert_eq!(map.remove(&"a".to_string()), Some(Dog)); + assert_eq!(map.remove(&"b".to_string()), Some(Frog("Henry".to_string(), 349))); + } + + #[test] + fn test_multiline_errors() { + assert_eq!(from_str("{\n \"foo\":\n \"bar\""), + Err(SyntaxError(EOFWhileParsingObject, 3u, 8u))); + } + + #[derive(RustcDecodable)] + #[allow(dead_code)] + struct DecodeStruct { + x: f64, + y: bool, + z: string::String, + w: Vec + } + #[derive(RustcDecodable)] + enum DecodeEnum { + A(f64), + B(string::String) + } + fn check_err>(to_parse: &'static str, + expected: DecoderError) { + let res: DecodeResult = match from_str(to_parse) { + Err(e) => Err(ParseError(e)), + Ok(json) => Decodable::decode(&mut Decoder::new(json)) + }; + match res { + Ok(_) => panic!("`{}` parsed & decoded ok, expecting error `{}`", + to_parse, expected), + Err(ParseError(e)) => panic!("`{}` is not valid json: {}", + to_parse, e), + Err(e) => { + assert_eq!(e, expected); + } + } + } + #[test] + fn test_decode_errors_struct() { + check_err::("[]", ExpectedError("Object".to_string(), "[]".to_string())); + check_err::("{\"x\": true, \"y\": true, \"z\": \"\", \"w\": []}", + ExpectedError("Number".to_string(), "true".to_string())); + check_err::("{\"x\": 1, \"y\": [], \"z\": \"\", \"w\": []}", + ExpectedError("Boolean".to_string(), "[]".to_string())); + check_err::("{\"x\": 1, \"y\": true, \"z\": {}, \"w\": []}", + ExpectedError("String".to_string(), "{}".to_string())); + check_err::("{\"x\": 1, \"y\": true, \"z\": \"\", \"w\": null}", + ExpectedError("Array".to_string(), "null".to_string())); + check_err::("{\"x\": 1, \"y\": true, \"z\": \"\"}", + MissingFieldError("w".to_string())); + } + #[test] + fn test_decode_errors_enum() { + check_err::("{}", + MissingFieldError("variant".to_string())); + check_err::("{\"variant\": 1}", + ExpectedError("String".to_string(), "1".to_string())); + check_err::("{\"variant\": \"A\"}", + MissingFieldError("fields".to_string())); + check_err::("{\"variant\": \"A\", \"fields\": null}", + ExpectedError("Array".to_string(), "null".to_string())); + check_err::("{\"variant\": \"C\", \"fields\": []}", + UnknownVariantError("C".to_string())); + } + + #[test] + fn test_find(){ + let json_value = from_str("{\"dog\" : \"cat\"}").unwrap(); + let found_str = json_value.find("dog"); + assert!(found_str.unwrap().as_string().unwrap() == "cat"); + } + + #[test] + fn test_find_path(){ + let json_value = from_str("{\"dog\":{\"cat\": {\"mouse\" : \"cheese\"}}}").unwrap(); + let found_str = json_value.find_path(&["dog", "cat", "mouse"]); + assert!(found_str.unwrap().as_string().unwrap() == "cheese"); + } + + #[test] + fn test_search(){ + let json_value = from_str("{\"dog\":{\"cat\": {\"mouse\" : \"cheese\"}}}").unwrap(); + let found_str = json_value.search("mouse").and_then(|j| j.as_string()); + assert!(found_str.unwrap() == "cheese"); + } + + #[test] + fn test_index(){ + let json_value = from_str("{\"animals\":[\"dog\",\"cat\",\"mouse\"]}").unwrap(); + let ref array = json_value["animals"]; + assert_eq!(array[0].as_string().unwrap(), "dog"); + assert_eq!(array[1].as_string().unwrap(), "cat"); + assert_eq!(array[2].as_string().unwrap(), "mouse"); + } + + #[test] + fn test_is_object(){ + let json_value = from_str("{}").unwrap(); + assert!(json_value.is_object()); + } + + #[test] + fn test_as_object(){ + let json_value = from_str("{}").unwrap(); + let json_object = json_value.as_object(); + assert!(json_object.is_some()); + } + + #[test] + fn test_is_array(){ + let json_value = from_str("[1, 2, 3]").unwrap(); + assert!(json_value.is_array()); + } + + #[test] + fn test_as_array(){ + let json_value = from_str("[1, 2, 3]").unwrap(); + let json_array = json_value.as_array(); + let expected_length = 3; + assert!(json_array.is_some() && json_array.unwrap().len() == expected_length); + } + + #[test] + fn test_is_string(){ + let json_value = from_str("\"dog\"").unwrap(); + assert!(json_value.is_string()); + } + + #[test] + fn test_as_string(){ + let json_value = from_str("\"dog\"").unwrap(); + let json_str = json_value.as_string(); + let expected_str = "dog"; + assert_eq!(json_str, Some(expected_str)); + } + + #[test] + fn test_is_number(){ + let json_value = from_str("12").unwrap(); + assert!(json_value.is_number()); + } + + #[test] + fn test_is_i64(){ + let json_value = from_str("-12").unwrap(); + assert!(json_value.is_i64()); + + let json_value = from_str("12").unwrap(); + assert!(!json_value.is_i64()); + + let json_value = from_str("12.0").unwrap(); + assert!(!json_value.is_i64()); + } + + #[test] + fn test_is_u64(){ + let json_value = from_str("12").unwrap(); + assert!(json_value.is_u64()); + + let json_value = from_str("-12").unwrap(); + assert!(!json_value.is_u64()); + + let json_value = from_str("12.0").unwrap(); + assert!(!json_value.is_u64()); + } + + #[test] + fn test_is_f64(){ + let json_value = from_str("12").unwrap(); + assert!(!json_value.is_f64()); + + let json_value = from_str("-12").unwrap(); + assert!(!json_value.is_f64()); + + let json_value = from_str("12.0").unwrap(); + assert!(json_value.is_f64()); + + let json_value = from_str("-12.0").unwrap(); + assert!(json_value.is_f64()); + } + + #[test] + fn test_as_i64(){ + let json_value = from_str("-12").unwrap(); + let json_num = json_value.as_i64(); + assert_eq!(json_num, Some(-12)); + } + + #[test] + fn test_as_u64(){ + let json_value = from_str("12").unwrap(); + let json_num = json_value.as_u64(); + assert_eq!(json_num, Some(12)); + } + + #[test] + fn test_as_f64(){ + let json_value = from_str("12.0").unwrap(); + let json_num = json_value.as_f64(); + assert_eq!(json_num, Some(12f64)); + } + + #[test] + fn test_is_boolean(){ + let json_value = from_str("false").unwrap(); + assert!(json_value.is_boolean()); + } + + #[test] + fn test_as_boolean(){ + let json_value = from_str("false").unwrap(); + let json_bool = json_value.as_boolean(); + let expected_bool = false; + assert!(json_bool.is_some() && json_bool.unwrap() == expected_bool); + } + + #[test] + fn test_is_null(){ + let json_value = from_str("null").unwrap(); + assert!(json_value.is_null()); + } + + #[test] + fn test_as_null(){ + let json_value = from_str("null").unwrap(); + let json_null = json_value.as_null(); + let expected_null = (); + assert!(json_null.is_some() && json_null.unwrap() == expected_null); + } + + #[test] + fn test_encode_hashmap_with_numeric_key() { + use std::str::from_utf8; + use std::io::Writer; + use std::collections::HashMap; + let mut hm: HashMap = HashMap::new(); + hm.insert(1, true); + let mut mem_buf = Vec::new(); + write!(&mut mem_buf, "{}", super::as_pretty_json(&hm)).unwrap(); + let json_str = from_utf8(mem_buf[]).unwrap(); + match from_str(json_str) { + Err(_) => panic!("Unable to parse json_str: {}", json_str), + _ => {} // it parsed and we are good to go + } + } + + #[test] + fn test_prettyencode_hashmap_with_numeric_key() { + use std::str::from_utf8; + use std::io::Writer; + use std::collections::HashMap; + let mut hm: HashMap = HashMap::new(); + hm.insert(1, true); + let mut mem_buf = Vec::new(); + write!(&mut mem_buf, "{}", super::as_pretty_json(&hm)).unwrap(); + let json_str = from_utf8(mem_buf[]).unwrap(); + match from_str(json_str) { + Err(_) => panic!("Unable to parse json_str: {}", json_str), + _ => {} // it parsed and we are good to go + } + } + + #[test] + fn test_prettyencoder_indent_level_param() { + use std::str::from_utf8; + use std::collections::BTreeMap; + + let mut tree = BTreeMap::new(); + + tree.insert("hello".to_string(), String("guten tag".to_string())); + tree.insert("goodbye".to_string(), String("sayonara".to_string())); + + let json = Array( + // The following layout below should look a lot like + // the pretty-printed JSON (indent * x) + vec! + ( // 0x + String("greetings".to_string()), // 1x + Object(tree), // 1x + 2x + 2x + 1x + ) // 0x + // End JSON array (7 lines) + ); + + // Helper function for counting indents + fn indents(source: &str) -> uint { + let trimmed = source.trim_left_matches(' '); + source.len() - trimmed.len() + } + + // Test up to 4 spaces of indents (more?) + for i in range(0, 4u) { + let mut writer = Vec::new(); + write!(&mut writer, "{}", + super::as_pretty_json(&json).indent(i)).unwrap(); + + let printed = from_utf8(writer[]).unwrap(); + + // Check for indents at each line + let lines: Vec<&str> = printed.lines().collect(); + assert_eq!(lines.len(), 7); // JSON should be 7 lines + + assert_eq!(indents(lines[0]), 0 * i); // [ + assert_eq!(indents(lines[1]), 1 * i); // "greetings", + assert_eq!(indents(lines[2]), 1 * i); // { + assert_eq!(indents(lines[3]), 2 * i); // "hello": "guten tag", + assert_eq!(indents(lines[4]), 2 * i); // "goodbye": "sayonara" + assert_eq!(indents(lines[5]), 1 * i); // }, + assert_eq!(indents(lines[6]), 0 * i); // ] + + // Finally, test that the pretty-printed JSON is valid + from_str(printed).ok().expect("Pretty-printed JSON is invalid!"); + } + } + + #[test] + fn test_hashmap_with_numeric_key_can_handle_double_quote_delimited_key() { + use std::collections::HashMap; + use Decodable; + let json_str = "{\"1\":true}"; + let json_obj = match from_str(json_str) { + Err(_) => panic!("Unable to parse json_str: {}", json_str), + Ok(o) => o + }; + let mut decoder = Decoder::new(json_obj); + let _hm: HashMap = Decodable::decode(&mut decoder).unwrap(); + } + + #[test] + fn test_hashmap_with_numeric_key_will_error_with_string_keys() { + use std::collections::HashMap; + use Decodable; + let json_str = "{\"a\":true}"; + let json_obj = match from_str(json_str) { + Err(_) => panic!("Unable to parse json_str: {}", json_str), + Ok(o) => o + }; + let mut decoder = Decoder::new(json_obj); + let result: Result, DecoderError> = Decodable::decode(&mut decoder); + assert_eq!(result, Err(ExpectedError("Number".to_string(), "a".to_string()))); + } + + fn assert_stream_equal(src: &str, + expected: Vec<(JsonEvent, Vec)>) { + let mut parser = Parser::new(src.chars()); + let mut i = 0; + loop { + let evt = match parser.next() { + Some(e) => e, + None => { break; } + }; + let (ref expected_evt, ref expected_stack) = expected[i]; + if !parser.stack().is_equal_to(expected_stack.as_slice()) { + panic!("Parser stack is not equal to {}", expected_stack); + } + assert_eq!(&evt, expected_evt); + i+=1; + } + } + #[test] + #[cfg_attr(target_word_size = "32", ignore)] // FIXME(#14064) + fn test_streaming_parser() { + assert_stream_equal( + r#"{ "foo":"bar", "array" : [0, 1, 2, 3, 4, 5], "idents":[null,true,false]}"#, + vec![ + (ObjectStart, vec![]), + (StringValue("bar".to_string()), vec![Key("foo")]), + (ArrayStart, vec![Key("array")]), + (U64Value(0), vec![Key("array"), Index(0)]), + (U64Value(1), vec![Key("array"), Index(1)]), + (U64Value(2), vec![Key("array"), Index(2)]), + (U64Value(3), vec![Key("array"), Index(3)]), + (U64Value(4), vec![Key("array"), Index(4)]), + (U64Value(5), vec![Key("array"), Index(5)]), + (ArrayEnd, vec![Key("array")]), + (ArrayStart, vec![Key("idents")]), + (NullValue, vec![Key("idents"), Index(0)]), + (BooleanValue(true), vec![Key("idents"), Index(1)]), + (BooleanValue(false), vec![Key("idents"), Index(2)]), + (ArrayEnd, vec![Key("idents")]), + (ObjectEnd, vec![]), + ] + ); + } + fn last_event(src: &str) -> JsonEvent { + let mut parser = Parser::new(src.chars()); + let mut evt = NullValue; + loop { + evt = match parser.next() { + Some(e) => e, + None => return evt, + } + } + } + + #[test] + #[cfg_attr(target_word_size = "32", ignore)] // FIXME(#14064) + fn test_read_object_streaming() { + assert_eq!(last_event("{ "), Error(SyntaxError(EOFWhileParsingObject, 1, 3))); + assert_eq!(last_event("{1"), Error(SyntaxError(KeyMustBeAString, 1, 2))); + assert_eq!(last_event("{ \"a\""), Error(SyntaxError(EOFWhileParsingObject, 1, 6))); + assert_eq!(last_event("{\"a\""), Error(SyntaxError(EOFWhileParsingObject, 1, 5))); + assert_eq!(last_event("{\"a\" "), Error(SyntaxError(EOFWhileParsingObject, 1, 6))); + + assert_eq!(last_event("{\"a\" 1"), Error(SyntaxError(ExpectedColon, 1, 6))); + assert_eq!(last_event("{\"a\":"), Error(SyntaxError(EOFWhileParsingValue, 1, 6))); + assert_eq!(last_event("{\"a\":1"), Error(SyntaxError(EOFWhileParsingObject, 1, 7))); + assert_eq!(last_event("{\"a\":1 1"), Error(SyntaxError(InvalidSyntax, 1, 8))); + assert_eq!(last_event("{\"a\":1,"), Error(SyntaxError(EOFWhileParsingObject, 1, 8))); + assert_eq!(last_event("{\"a\":1,}"), Error(SyntaxError(TrailingComma, 1, 8))); + + assert_stream_equal( + "{}", + vec![(ObjectStart, vec![]), (ObjectEnd, vec![])] + ); + assert_stream_equal( + "{\"a\": 3}", + vec![ + (ObjectStart, vec![]), + (U64Value(3), vec![Key("a")]), + (ObjectEnd, vec![]), + ] + ); + assert_stream_equal( + "{ \"a\": null, \"b\" : true }", + vec![ + (ObjectStart, vec![]), + (NullValue, vec![Key("a")]), + (BooleanValue(true), vec![Key("b")]), + (ObjectEnd, vec![]), + ] + ); + assert_stream_equal( + "{\"a\" : 1.0 ,\"b\": [ true ]}", + vec![ + (ObjectStart, vec![]), + (F64Value(1.0), vec![Key("a")]), + (ArrayStart, vec![Key("b")]), + (BooleanValue(true),vec![Key("b"), Index(0)]), + (ArrayEnd, vec![Key("b")]), + (ObjectEnd, vec![]), + ] + ); + assert_stream_equal( + r#"{ + "a": 1.0, + "b": [ + true, + "foo\nbar", + { "c": {"d": null} } + ] + }"#, + vec![ + (ObjectStart, vec![]), + (F64Value(1.0), vec![Key("a")]), + (ArrayStart, vec![Key("b")]), + (BooleanValue(true), vec![Key("b"), Index(0)]), + (StringValue("foo\nbar".to_string()), vec![Key("b"), Index(1)]), + (ObjectStart, vec![Key("b"), Index(2)]), + (ObjectStart, vec![Key("b"), Index(2), Key("c")]), + (NullValue, vec![Key("b"), Index(2), Key("c"), Key("d")]), + (ObjectEnd, vec![Key("b"), Index(2), Key("c")]), + (ObjectEnd, vec![Key("b"), Index(2)]), + (ArrayEnd, vec![Key("b")]), + (ObjectEnd, vec![]), + ] + ); + } + #[test] + #[cfg_attr(target_word_size = "32", ignore)] // FIXME(#14064) + fn test_read_array_streaming() { + assert_stream_equal( + "[]", + vec![ + (ArrayStart, vec![]), + (ArrayEnd, vec![]), + ] + ); + assert_stream_equal( + "[ ]", + vec![ + (ArrayStart, vec![]), + (ArrayEnd, vec![]), + ] + ); + assert_stream_equal( + "[true]", + vec![ + (ArrayStart, vec![]), + (BooleanValue(true), vec![Index(0)]), + (ArrayEnd, vec![]), + ] + ); + assert_stream_equal( + "[ false ]", + vec![ + (ArrayStart, vec![]), + (BooleanValue(false), vec![Index(0)]), + (ArrayEnd, vec![]), + ] + ); + assert_stream_equal( + "[null]", + vec![ + (ArrayStart, vec![]), + (NullValue, vec![Index(0)]), + (ArrayEnd, vec![]), + ] + ); + assert_stream_equal( + "[3, 1]", + vec![ + (ArrayStart, vec![]), + (U64Value(3), vec![Index(0)]), + (U64Value(1), vec![Index(1)]), + (ArrayEnd, vec![]), + ] + ); + assert_stream_equal( + "\n[3, 2]\n", + vec![ + (ArrayStart, vec![]), + (U64Value(3), vec![Index(0)]), + (U64Value(2), vec![Index(1)]), + (ArrayEnd, vec![]), + ] + ); + assert_stream_equal( + "[2, [4, 1]]", + vec![ + (ArrayStart, vec![]), + (U64Value(2), vec![Index(0)]), + (ArrayStart, vec![Index(1)]), + (U64Value(4), vec![Index(1), Index(0)]), + (U64Value(1), vec![Index(1), Index(1)]), + (ArrayEnd, vec![Index(1)]), + (ArrayEnd, vec![]), + ] + ); + + assert_eq!(last_event("["), Error(SyntaxError(EOFWhileParsingValue, 1, 2))); + + assert_eq!(from_str("["), Err(SyntaxError(EOFWhileParsingValue, 1, 2))); + assert_eq!(from_str("[1"), Err(SyntaxError(EOFWhileParsingArray, 1, 3))); + assert_eq!(from_str("[1,"), Err(SyntaxError(EOFWhileParsingValue, 1, 4))); + assert_eq!(from_str("[1,]"), Err(SyntaxError(InvalidSyntax, 1, 4))); + assert_eq!(from_str("[6 7]"), Err(SyntaxError(InvalidSyntax, 1, 4))); + + } + #[test] + fn test_trailing_characters_streaming() { + assert_eq!(last_event("nulla"), Error(SyntaxError(TrailingCharacters, 1, 5))); + assert_eq!(last_event("truea"), Error(SyntaxError(TrailingCharacters, 1, 5))); + assert_eq!(last_event("falsea"), Error(SyntaxError(TrailingCharacters, 1, 6))); + assert_eq!(last_event("1a"), Error(SyntaxError(TrailingCharacters, 1, 2))); + assert_eq!(last_event("[]a"), Error(SyntaxError(TrailingCharacters, 1, 3))); + assert_eq!(last_event("{}a"), Error(SyntaxError(TrailingCharacters, 1, 3))); + } + #[test] + fn test_read_identifiers_streaming() { + assert_eq!(Parser::new("null".chars()).next(), Some(NullValue)); + assert_eq!(Parser::new("true".chars()).next(), Some(BooleanValue(true))); + assert_eq!(Parser::new("false".chars()).next(), Some(BooleanValue(false))); + + assert_eq!(last_event("n"), Error(SyntaxError(InvalidSyntax, 1, 2))); + assert_eq!(last_event("nul"), Error(SyntaxError(InvalidSyntax, 1, 4))); + assert_eq!(last_event("t"), Error(SyntaxError(InvalidSyntax, 1, 2))); + assert_eq!(last_event("truz"), Error(SyntaxError(InvalidSyntax, 1, 4))); + assert_eq!(last_event("f"), Error(SyntaxError(InvalidSyntax, 1, 2))); + assert_eq!(last_event("faz"), Error(SyntaxError(InvalidSyntax, 1, 3))); + } + + #[test] + fn test_stack() { + let mut stack = Stack::new(); + + assert!(stack.is_empty()); + assert!(stack.len() == 0); + assert!(!stack.last_is_index()); + + stack.push_index(0); + stack.bump_index(); + + assert!(stack.len() == 1); + assert!(stack.is_equal_to(&[Index(1)])); + assert!(stack.starts_with(&[Index(1)])); + assert!(stack.ends_with(&[Index(1)])); + assert!(stack.last_is_index()); + assert!(stack.get(0) == Index(1)); + + stack.push_key("foo".to_string()); + + assert!(stack.len() == 2); + assert!(stack.is_equal_to(&[Index(1), Key("foo")])); + assert!(stack.starts_with(&[Index(1), Key("foo")])); + assert!(stack.starts_with(&[Index(1)])); + assert!(stack.ends_with(&[Index(1), Key("foo")])); + assert!(stack.ends_with(&[Key("foo")])); + assert!(!stack.last_is_index()); + assert!(stack.get(0) == Index(1)); + assert!(stack.get(1) == Key("foo")); + + stack.push_key("bar".to_string()); + + assert!(stack.len() == 3); + assert!(stack.is_equal_to(&[Index(1), Key("foo"), Key("bar")])); + assert!(stack.starts_with(&[Index(1)])); + assert!(stack.starts_with(&[Index(1), Key("foo")])); + assert!(stack.starts_with(&[Index(1), Key("foo"), Key("bar")])); + assert!(stack.ends_with(&[Key("bar")])); + assert!(stack.ends_with(&[Key("foo"), Key("bar")])); + assert!(stack.ends_with(&[Index(1), Key("foo"), Key("bar")])); + assert!(!stack.last_is_index()); + assert!(stack.get(0) == Index(1)); + assert!(stack.get(1) == Key("foo")); + assert!(stack.get(2) == Key("bar")); + + stack.pop(); + + assert!(stack.len() == 2); + assert!(stack.is_equal_to(&[Index(1), Key("foo")])); + assert!(stack.starts_with(&[Index(1), Key("foo")])); + assert!(stack.starts_with(&[Index(1)])); + assert!(stack.ends_with(&[Index(1), Key("foo")])); + assert!(stack.ends_with(&[Key("foo")])); + assert!(!stack.last_is_index()); + assert!(stack.get(0) == Index(1)); + assert!(stack.get(1) == Key("foo")); + } + + #[test] + fn test_to_json() { + use std::collections::{HashMap,BTreeMap}; + use super::ToJson; + + let array2 = Array(vec!(U64(1), U64(2))); + let array3 = Array(vec!(U64(1), U64(2), U64(3))); + let object = { + let mut tree_map = BTreeMap::new(); + tree_map.insert("a".to_string(), U64(1)); + tree_map.insert("b".to_string(), U64(2)); + Object(tree_map) + }; + + assert_eq!(array2.to_json(), array2); + assert_eq!(object.to_json(), object); + assert_eq!(3_i.to_json(), I64(3)); + assert_eq!(4_i8.to_json(), I64(4)); + assert_eq!(5_i16.to_json(), I64(5)); + assert_eq!(6_i32.to_json(), I64(6)); + assert_eq!(7_i64.to_json(), I64(7)); + assert_eq!(8_u.to_json(), U64(8)); + assert_eq!(9_u8.to_json(), U64(9)); + assert_eq!(10_u16.to_json(), U64(10)); + assert_eq!(11_u32.to_json(), U64(11)); + assert_eq!(12_u64.to_json(), U64(12)); + assert_eq!(13.0_f32.to_json(), F64(13.0_f64)); + assert_eq!(14.0_f64.to_json(), F64(14.0_f64)); + assert_eq!(().to_json(), Null); + assert_eq!(f32::INFINITY.to_json(), Null); + assert_eq!(f64::NAN.to_json(), Null); + assert_eq!(true.to_json(), Boolean(true)); + assert_eq!(false.to_json(), Boolean(false)); + assert_eq!("abc".to_json(), String("abc".to_string())); + assert_eq!("abc".to_string().to_json(), String("abc".to_string())); + assert_eq!((1u, 2u).to_json(), array2); + assert_eq!((1u, 2u, 3u).to_json(), array3); + assert_eq!([1u, 2].to_json(), array2); + assert_eq!((&[1u, 2, 3]).to_json(), array3); + assert_eq!((vec![1u, 2]).to_json(), array2); + assert_eq!(vec!(1u, 2, 3).to_json(), array3); + let mut tree_map = BTreeMap::new(); + tree_map.insert("a".to_string(), 1u); + tree_map.insert("b".to_string(), 2); + assert_eq!(tree_map.to_json(), object); + let mut hash_map = HashMap::new(); + hash_map.insert("a".to_string(), 1u); + hash_map.insert("b".to_string(), 2); + assert_eq!(hash_map.to_json(), object); + assert_eq!(Some(15i).to_json(), I64(15)); + assert_eq!(Some(15u).to_json(), U64(15)); + assert_eq!(None::.to_json(), Null); + } + + #[bench] + fn bench_streaming_small(b: &mut Bencher) { + b.iter( || { + let mut parser = Parser::new( + r#"{ + "a": 1.0, + "b": [ + true, + "foo\nbar", + { "c": {"d": null} } + ] + }"#.chars() + ); + loop { + match parser.next() { + None => return, + _ => {} + } + } + }); + } + #[bench] + fn bench_small(b: &mut Bencher) { + b.iter( || { + let _ = from_str(r#"{ + "a": 1.0, + "b": [ + true, + "foo\nbar", + { "c": {"d": null} } + ] + }"#); + }); + } + + fn big_json() -> string::String { + let mut src = "[\n".to_string(); + for _ in range(0i, 500) { + src.push_str(r#"{ "a": true, "b": null, "c":3.1415, "d": "Hello world", "e": \ + [1,2,3]},"#); + } + src.push_str("{}]"); + return src; + } + + #[bench] + fn bench_streaming_large(b: &mut Bencher) { + let src = big_json(); + b.iter( || { + let mut parser = Parser::new(src.chars()); + loop { + match parser.next() { + None => return, + _ => {} + } + } + }); + } + #[bench] + fn bench_large(b: &mut Bencher) { + let src = big_json(); + b.iter( || { let _ = from_str(src.as_slice()); }); + } +} diff --git a/src/libserialize/lib.rs b/src/libserialize/lib.rs index 1ec6a2af309a7..8ad2013f9368f 100644 --- a/src/libserialize/lib.rs +++ b/src/libserialize/lib.rs @@ -40,11 +40,25 @@ extern crate collections; pub use self::serialize::{Decoder, Encoder, Decodable, Encodable, DecoderHelpers, EncoderHelpers}; +#[cfg(stage0)] +#[path = "serialize_stage0.rs"] mod serialize; +#[cfg(not(stage0))] +mod serialize; + +#[cfg(stage0)] +#[path = "collection_impls_stage0.rs"] +mod collection_impls; +#[cfg(not(stage0))] mod collection_impls; pub mod base64; pub mod hex; + +#[cfg(stage0)] +#[path = "json_stage0.rs"] +pub mod json; +#[cfg(not(stage0))] pub mod json; mod rustc_serialize { diff --git a/src/libserialize/serialize.rs b/src/libserialize/serialize.rs index 558f9e603e159..943843c6cc837 100644 --- a/src/libserialize/serialize.rs +++ b/src/libserialize/serialize.rs @@ -19,406 +19,424 @@ use std::rc::Rc; use std::cell::{Cell, RefCell}; use std::sync::Arc; -pub trait Encoder { +pub trait Encoder { + type Error; + // Primitive types: - fn emit_nil(&mut self) -> Result<(), E>; - fn emit_uint(&mut self, v: uint) -> Result<(), E>; - fn emit_u64(&mut self, v: u64) -> Result<(), E>; - fn emit_u32(&mut self, v: u32) -> Result<(), E>; - fn emit_u16(&mut self, v: u16) -> Result<(), E>; - fn emit_u8(&mut self, v: u8) -> Result<(), E>; - fn emit_int(&mut self, v: int) -> Result<(), E>; - fn emit_i64(&mut self, v: i64) -> Result<(), E>; - fn emit_i32(&mut self, v: i32) -> Result<(), E>; - fn emit_i16(&mut self, v: i16) -> Result<(), E>; - fn emit_i8(&mut self, v: i8) -> Result<(), E>; - fn emit_bool(&mut self, v: bool) -> Result<(), E>; - fn emit_f64(&mut self, v: f64) -> Result<(), E>; - fn emit_f32(&mut self, v: f32) -> Result<(), E>; - fn emit_char(&mut self, v: char) -> Result<(), E>; - fn emit_str(&mut self, v: &str) -> Result<(), E>; + fn emit_nil(&mut self) -> Result<(), Self::Error>; + fn emit_uint(&mut self, v: uint) -> Result<(), Self::Error>; + fn emit_u64(&mut self, v: u64) -> Result<(), Self::Error>; + fn emit_u32(&mut self, v: u32) -> Result<(), Self::Error>; + fn emit_u16(&mut self, v: u16) -> Result<(), Self::Error>; + fn emit_u8(&mut self, v: u8) -> Result<(), Self::Error>; + fn emit_int(&mut self, v: int) -> Result<(), Self::Error>; + fn emit_i64(&mut self, v: i64) -> Result<(), Self::Error>; + fn emit_i32(&mut self, v: i32) -> Result<(), Self::Error>; + fn emit_i16(&mut self, v: i16) -> Result<(), Self::Error>; + fn emit_i8(&mut self, v: i8) -> Result<(), Self::Error>; + fn emit_bool(&mut self, v: bool) -> Result<(), Self::Error>; + fn emit_f64(&mut self, v: f64) -> Result<(), Self::Error>; + fn emit_f32(&mut self, v: f32) -> Result<(), Self::Error>; + fn emit_char(&mut self, v: char) -> Result<(), Self::Error>; + fn emit_str(&mut self, v: &str) -> Result<(), Self::Error>; // Compound types: - fn emit_enum(&mut self, name: &str, f: F) -> Result<(), E> where - F: FnOnce(&mut Self) -> Result<(), E>; + fn emit_enum(&mut self, name: &str, f: F) -> Result<(), Self::Error> + where F: FnOnce(&mut Self) -> Result<(), Self::Error>; fn emit_enum_variant(&mut self, v_name: &str, v_id: uint, len: uint, - f: F) -> Result<(), E> where - F: FnOnce(&mut Self) -> Result<(), E>; - fn emit_enum_variant_arg(&mut self, a_idx: uint, f: F) -> Result<(), E> where - F: FnOnce(&mut Self) -> Result<(), E>; + f: F) -> Result<(), Self::Error> + where F: FnOnce(&mut Self) -> Result<(), Self::Error>; + fn emit_enum_variant_arg(&mut self, a_idx: uint, f: F) + -> Result<(), Self::Error> + where F: FnOnce(&mut Self) -> Result<(), Self::Error>; fn emit_enum_struct_variant(&mut self, v_name: &str, v_id: uint, len: uint, - f: F) -> Result<(), E> where - F: FnOnce(&mut Self) -> Result<(), E>; + f: F) -> Result<(), Self::Error> + where F: FnOnce(&mut Self) -> Result<(), Self::Error>; fn emit_enum_struct_variant_field(&mut self, f_name: &str, f_idx: uint, - f: F) -> Result<(), E> where - F: FnOnce(&mut Self) -> Result<(), E>; + f: F) -> Result<(), Self::Error> + where F: FnOnce(&mut Self) -> Result<(), Self::Error>; + + fn emit_struct(&mut self, name: &str, len: uint, f: F) + -> Result<(), Self::Error> + where F: FnOnce(&mut Self) -> Result<(), Self::Error>; + fn emit_struct_field(&mut self, f_name: &str, f_idx: uint, f: F) + -> Result<(), Self::Error> + where F: FnOnce(&mut Self) -> Result<(), Self::Error>; + + fn emit_tuple(&mut self, len: uint, f: F) -> Result<(), Self::Error> + where F: FnOnce(&mut Self) -> Result<(), Self::Error>; + fn emit_tuple_arg(&mut self, idx: uint, f: F) -> Result<(), Self::Error> + where F: FnOnce(&mut Self) -> Result<(), Self::Error>; + + fn emit_tuple_struct(&mut self, name: &str, len: uint, f: F) + -> Result<(), Self::Error> + where F: FnOnce(&mut Self) -> Result<(), Self::Error>; + fn emit_tuple_struct_arg(&mut self, f_idx: uint, f: F) + -> Result<(), Self::Error> + where F: FnOnce(&mut Self) -> Result<(), Self::Error>; + + // Specialized types: + fn emit_option(&mut self, f: F) -> Result<(), Self::Error> + where F: FnOnce(&mut Self) -> Result<(), Self::Error>; + fn emit_option_none(&mut self) -> Result<(), Self::Error>; + fn emit_option_some(&mut self, f: F) -> Result<(), Self::Error> + where F: FnOnce(&mut Self) -> Result<(), Self::Error>; - fn emit_struct(&mut self, name: &str, len: uint, f: F) -> Result<(), E> where - F: FnOnce(&mut Self) -> Result<(), E>; - fn emit_struct_field(&mut self, f_name: &str, f_idx: uint, f: F) -> Result<(), E> where - F: FnOnce(&mut Self) -> Result<(), E>; + fn emit_seq(&mut self, len: uint, f: F) -> Result<(), Self::Error> + where F: FnOnce(&mut Self) -> Result<(), Self::Error>; + fn emit_seq_elt(&mut self, idx: uint, f: F) -> Result<(), Self::Error> + where F: FnOnce(&mut Self) -> Result<(), Self::Error>; - fn emit_tuple(&mut self, len: uint, f: F) -> Result<(), E> where - F: FnOnce(&mut Self) -> Result<(), E>; - fn emit_tuple_arg(&mut self, idx: uint, f: F) -> Result<(), E> where - F: FnOnce(&mut Self) -> Result<(), E>; + fn emit_map(&mut self, len: uint, f: F) -> Result<(), Self::Error> + where F: FnOnce(&mut Self) -> Result<(), Self::Error>; + fn emit_map_elt_key(&mut self, idx: uint, f: F) -> Result<(), Self::Error> + where F: FnMut(&mut Self) -> Result<(), Self::Error>; + fn emit_map_elt_val(&mut self, idx: uint, f: F) -> Result<(), Self::Error> + where F: FnOnce(&mut Self) -> Result<(), Self::Error>; +} - fn emit_tuple_struct(&mut self, name: &str, len: uint, f: F) -> Result<(), E> where - F: FnOnce(&mut Self) -> Result<(), E>; - fn emit_tuple_struct_arg(&mut self, f_idx: uint, f: F) -> Result<(), E> where - F: FnOnce(&mut Self) -> Result<(), E>; +pub trait Decoder { + type Error; - // Specialized types: - fn emit_option(&mut self, f: F) -> Result<(), E> where - F: FnOnce(&mut Self) -> Result<(), E>; - fn emit_option_none(&mut self) -> Result<(), E>; - fn emit_option_some(&mut self, f: F) -> Result<(), E> where - F: FnOnce(&mut Self) -> Result<(), E>; - - fn emit_seq(&mut self, len: uint, f: F) -> Result<(), E> where - F: FnOnce(&mut Self) -> Result<(), E>; - fn emit_seq_elt(&mut self, idx: uint, f: F) -> Result<(), E> where - F: FnOnce(&mut Self) -> Result<(), E>; - - fn emit_map(&mut self, len: uint, f: F) -> Result<(), E> where - F: FnOnce(&mut Self) -> Result<(), E>; - fn emit_map_elt_key(&mut self, idx: uint, f: F) -> Result<(), E> where - F: FnMut(&mut Self) -> Result<(), E>; - fn emit_map_elt_val(&mut self, idx: uint, f: F) -> Result<(), E> where - F: FnOnce(&mut Self) -> Result<(), E>; -} - -pub trait Decoder { // Primitive types: - fn read_nil(&mut self) -> Result<(), E>; - fn read_uint(&mut self) -> Result; - fn read_u64(&mut self) -> Result; - fn read_u32(&mut self) -> Result; - fn read_u16(&mut self) -> Result; - fn read_u8(&mut self) -> Result; - fn read_int(&mut self) -> Result; - fn read_i64(&mut self) -> Result; - fn read_i32(&mut self) -> Result; - fn read_i16(&mut self) -> Result; - fn read_i8(&mut self) -> Result; - fn read_bool(&mut self) -> Result; - fn read_f64(&mut self) -> Result; - fn read_f32(&mut self) -> Result; - fn read_char(&mut self) -> Result; - fn read_str(&mut self) -> Result; + fn read_nil(&mut self) -> Result<(), Self::Error>; + fn read_uint(&mut self) -> Result; + fn read_u64(&mut self) -> Result; + fn read_u32(&mut self) -> Result; + fn read_u16(&mut self) -> Result; + fn read_u8(&mut self) -> Result; + fn read_int(&mut self) -> Result; + fn read_i64(&mut self) -> Result; + fn read_i32(&mut self) -> Result; + fn read_i16(&mut self) -> Result; + fn read_i8(&mut self) -> Result; + fn read_bool(&mut self) -> Result; + fn read_f64(&mut self) -> Result; + fn read_f32(&mut self) -> Result; + fn read_char(&mut self) -> Result; + fn read_str(&mut self) -> Result; // Compound types: - fn read_enum(&mut self, name: &str, f: F) -> Result where - F: FnOnce(&mut Self) -> Result; - - fn read_enum_variant(&mut self, names: &[&str], f: F) -> Result where - F: FnMut(&mut Self, uint) -> Result; - fn read_enum_variant_arg(&mut self, a_idx: uint, f: F) -> Result where - F: FnOnce(&mut Self) -> Result; - - fn read_enum_struct_variant(&mut self, names: &[&str], f: F) -> Result where - F: FnMut(&mut Self, uint) -> Result; + fn read_enum(&mut self, name: &str, f: F) -> Result + where F: FnOnce(&mut Self) -> Result; + + fn read_enum_variant(&mut self, names: &[&str], f: F) + -> Result + where F: FnMut(&mut Self, uint) -> Result; + fn read_enum_variant_arg(&mut self, a_idx: uint, f: F) + -> Result + where F: FnOnce(&mut Self) -> Result; + + fn read_enum_struct_variant(&mut self, names: &[&str], f: F) + -> Result + where F: FnMut(&mut Self, uint) -> Result; fn read_enum_struct_variant_field(&mut self, &f_name: &str, f_idx: uint, f: F) - -> Result where - F: FnOnce(&mut Self) -> Result; + -> Result + where F: FnOnce(&mut Self) -> Result; - fn read_struct(&mut self, s_name: &str, len: uint, f: F) -> Result where - F: FnOnce(&mut Self) -> Result; + fn read_struct(&mut self, s_name: &str, len: uint, f: F) + -> Result + where F: FnOnce(&mut Self) -> Result; fn read_struct_field(&mut self, f_name: &str, f_idx: uint, f: F) - -> Result where - F: FnOnce(&mut Self) -> Result; - - fn read_tuple(&mut self, len: uint, f: F) -> Result where - F: FnOnce(&mut Self) -> Result; - fn read_tuple_arg(&mut self, a_idx: uint, f: F) -> Result where - F: FnOnce(&mut Self) -> Result; - - fn read_tuple_struct(&mut self, s_name: &str, len: uint, f: F) -> Result where - F: FnOnce(&mut Self) -> Result; - fn read_tuple_struct_arg(&mut self, a_idx: uint, f: F) -> Result where - F: FnOnce(&mut Self) -> Result; + -> Result + where F: FnOnce(&mut Self) -> Result; + + fn read_tuple(&mut self, len: uint, f: F) -> Result + where F: FnOnce(&mut Self) -> Result; + fn read_tuple_arg(&mut self, a_idx: uint, f: F) + -> Result + where F: FnOnce(&mut Self) -> Result; + + fn read_tuple_struct(&mut self, s_name: &str, len: uint, f: F) + -> Result + where F: FnOnce(&mut Self) -> Result; + fn read_tuple_struct_arg(&mut self, a_idx: uint, f: F) + -> Result + where F: FnOnce(&mut Self) -> Result; // Specialized types: - fn read_option(&mut self, f: F) -> Result where - F: FnMut(&mut Self, bool) -> Result; - - fn read_seq(&mut self, f: F) -> Result where - F: FnOnce(&mut Self, uint) -> Result; - fn read_seq_elt(&mut self, idx: uint, f: F) -> Result where - F: FnOnce(&mut Self) -> Result; - - fn read_map(&mut self, f: F) -> Result where - F: FnOnce(&mut Self, uint) -> Result; - fn read_map_elt_key(&mut self, idx: uint, f: F) -> Result where - F: FnOnce(&mut Self) -> Result; - fn read_map_elt_val(&mut self, idx: uint, f: F) -> Result where - F: FnOnce(&mut Self) -> Result; + fn read_option(&mut self, f: F) -> Result + where F: FnMut(&mut Self, bool) -> Result; + + fn read_seq(&mut self, f: F) -> Result + where F: FnOnce(&mut Self, uint) -> Result; + fn read_seq_elt(&mut self, idx: uint, f: F) -> Result + where F: FnOnce(&mut Self) -> Result; + + fn read_map(&mut self, f: F) -> Result + where F: FnOnce(&mut Self, uint) -> Result; + fn read_map_elt_key(&mut self, idx: uint, f: F) + -> Result + where F: FnOnce(&mut Self) -> Result; + fn read_map_elt_val(&mut self, idx: uint, f: F) + -> Result + where F: FnOnce(&mut Self) -> Result; // Failure - fn error(&mut self, err: &str) -> E; + fn error(&mut self, err: &str) -> Self::Error; } -pub trait Encodable, E> for Sized? { - fn encode(&self, s: &mut S) -> Result<(), E>; +pub trait Encodable { + fn encode(&self, s: &mut S) -> Result<(), S::Error>; } -pub trait Decodable, E> { - fn decode(d: &mut D) -> Result; +pub trait Decodable { + fn decode(d: &mut D) -> Result; } -impl> Encodable for uint { - fn encode(&self, s: &mut S) -> Result<(), E> { +impl Encodable for uint { + fn encode(&self, s: &mut S) -> Result<(), S::Error> { s.emit_uint(*self) } } -impl> Decodable for uint { - fn decode(d: &mut D) -> Result { +impl Decodable for uint { + fn decode(d: &mut D) -> Result { d.read_uint() } } -impl> Encodable for u8 { - fn encode(&self, s: &mut S) -> Result<(), E> { +impl Encodable for u8 { + fn encode(&self, s: &mut S) -> Result<(), S::Error> { s.emit_u8(*self) } } -impl> Decodable for u8 { - fn decode(d: &mut D) -> Result { +impl Decodable for u8 { + fn decode(d: &mut D) -> Result { d.read_u8() } } -impl> Encodable for u16 { - fn encode(&self, s: &mut S) -> Result<(), E> { +impl Encodable for u16 { + fn encode(&self, s: &mut S) -> Result<(), S::Error> { s.emit_u16(*self) } } -impl> Decodable for u16 { - fn decode(d: &mut D) -> Result { +impl Decodable for u16 { + fn decode(d: &mut D) -> Result { d.read_u16() } } -impl> Encodable for u32 { - fn encode(&self, s: &mut S) -> Result<(), E> { +impl Encodable for u32 { + fn encode(&self, s: &mut S) -> Result<(), S::Error> { s.emit_u32(*self) } } -impl> Decodable for u32 { - fn decode(d: &mut D) -> Result { +impl Decodable for u32 { + fn decode(d: &mut D) -> Result { d.read_u32() } } -impl> Encodable for u64 { - fn encode(&self, s: &mut S) -> Result<(), E> { +impl Encodable for u64 { + fn encode(&self, s: &mut S) -> Result<(), S::Error> { s.emit_u64(*self) } } -impl> Decodable for u64 { - fn decode(d: &mut D) -> Result { +impl Decodable for u64 { + fn decode(d: &mut D) -> Result { d.read_u64() } } -impl> Encodable for int { - fn encode(&self, s: &mut S) -> Result<(), E> { +impl Encodable for int { + fn encode(&self, s: &mut S) -> Result<(), S::Error> { s.emit_int(*self) } } -impl> Decodable for int { - fn decode(d: &mut D) -> Result { +impl Decodable for int { + fn decode(d: &mut D) -> Result { d.read_int() } } -impl> Encodable for i8 { - fn encode(&self, s: &mut S) -> Result<(), E> { +impl Encodable for i8 { + fn encode(&self, s: &mut S) -> Result<(), S::Error> { s.emit_i8(*self) } } -impl> Decodable for i8 { - fn decode(d: &mut D) -> Result { +impl Decodable for i8 { + fn decode(d: &mut D) -> Result { d.read_i8() } } -impl> Encodable for i16 { - fn encode(&self, s: &mut S) -> Result<(), E> { +impl Encodable for i16 { + fn encode(&self, s: &mut S) -> Result<(), S::Error> { s.emit_i16(*self) } } -impl> Decodable for i16 { - fn decode(d: &mut D) -> Result { +impl Decodable for i16 { + fn decode(d: &mut D) -> Result { d.read_i16() } } -impl> Encodable for i32 { - fn encode(&self, s: &mut S) -> Result<(), E> { +impl Encodable for i32 { + fn encode(&self, s: &mut S) -> Result<(), S::Error> { s.emit_i32(*self) } } -impl> Decodable for i32 { - fn decode(d: &mut D) -> Result { +impl Decodable for i32 { + fn decode(d: &mut D) -> Result { d.read_i32() } } -impl> Encodable for i64 { - fn encode(&self, s: &mut S) -> Result<(), E> { +impl Encodable for i64 { + fn encode(&self, s: &mut S) -> Result<(), S::Error> { s.emit_i64(*self) } } -impl> Decodable for i64 { - fn decode(d: &mut D) -> Result { +impl Decodable for i64 { + fn decode(d: &mut D) -> Result { d.read_i64() } } -impl> Encodable for str { - fn encode(&self, s: &mut S) -> Result<(), E> { +impl Encodable for str { + fn encode(&self, s: &mut S) -> Result<(), S::Error> { s.emit_str(self) } } -impl> Encodable for String { - fn encode(&self, s: &mut S) -> Result<(), E> { +impl Encodable for String { + fn encode(&self, s: &mut S) -> Result<(), S::Error> { s.emit_str(self[]) } } -impl> Decodable for String { - fn decode(d: &mut D) -> Result { +impl Decodable for String { + fn decode(d: &mut D) -> Result { d.read_str() } } -impl> Encodable for f32 { - fn encode(&self, s: &mut S) -> Result<(), E> { +impl Encodable for f32 { + fn encode(&self, s: &mut S) -> Result<(), S::Error> { s.emit_f32(*self) } } -impl> Decodable for f32 { - fn decode(d: &mut D) -> Result { +impl Decodable for f32 { + fn decode(d: &mut D) -> Result { d.read_f32() } } -impl> Encodable for f64 { - fn encode(&self, s: &mut S) -> Result<(), E> { +impl Encodable for f64 { + fn encode(&self, s: &mut S) -> Result<(), S::Error> { s.emit_f64(*self) } } -impl> Decodable for f64 { - fn decode(d: &mut D) -> Result { +impl Decodable for f64 { + fn decode(d: &mut D) -> Result { d.read_f64() } } -impl> Encodable for bool { - fn encode(&self, s: &mut S) -> Result<(), E> { +impl Encodable for bool { + fn encode(&self, s: &mut S) -> Result<(), S::Error> { s.emit_bool(*self) } } -impl> Decodable for bool { - fn decode(d: &mut D) -> Result { +impl Decodable for bool { + fn decode(d: &mut D) -> Result { d.read_bool() } } -impl> Encodable for char { - fn encode(&self, s: &mut S) -> Result<(), E> { +impl Encodable for char { + fn encode(&self, s: &mut S) -> Result<(), S::Error> { s.emit_char(*self) } } -impl> Decodable for char { - fn decode(d: &mut D) -> Result { +impl Decodable for char { + fn decode(d: &mut D) -> Result { d.read_char() } } -impl> Encodable for () { - fn encode(&self, s: &mut S) -> Result<(), E> { +impl Encodable for () { + fn encode(&self, s: &mut S) -> Result<(), S::Error> { s.emit_nil() } } -impl> Decodable for () { - fn decode(d: &mut D) -> Result<(), E> { +impl Decodable for () { + fn decode(d: &mut D) -> Result<(), D::Error> { d.read_nil() } } -impl<'a, E, S: Encoder, Sized? T: Encodable> Encodable for &'a T { - fn encode(&self, s: &mut S) -> Result<(), E> { +impl<'a, Sized? T: Encodable> Encodable for &'a T { + fn encode(&self, s: &mut S) -> Result<(), S::Error> { (**self).encode(s) } } -impl, Sized? T: Encodable> Encodable for Box { - fn encode(&self, s: &mut S) -> Result<(), E> { +impl Encodable for Box { + fn encode(&self, s: &mut S) -> Result<(), S::Error> { (**self).encode(s) } } -impl, T: Decodable> Decodable for Box { - fn decode(d: &mut D) -> Result, E> { +impl< T: Decodable> Decodable for Box { + fn decode(d: &mut D) -> Result, D::Error> { Ok(box try!(Decodable::decode(d))) } } -impl, T: Decodable> Decodable for Box<[T]> { - fn decode(d: &mut D) -> Result, E> { +impl< T: Decodable> Decodable for Box<[T]> { + fn decode(d: &mut D) -> Result, D::Error> { let v: Vec = try!(Decodable::decode(d)); Ok(v.into_boxed_slice()) } } -impl,T:Encodable> Encodable for Rc { +impl Encodable for Rc { #[inline] - fn encode(&self, s: &mut S) -> Result<(), E> { + fn encode(&self, s: &mut S) -> Result<(), S::Error> { (**self).encode(s) } } -impl,T:Decodable> Decodable for Rc { +impl Decodable for Rc { #[inline] - fn decode(d: &mut D) -> Result, E> { + fn decode(d: &mut D) -> Result, D::Error> { Ok(Rc::new(try!(Decodable::decode(d)))) } } -impl,T:Encodable> Encodable for [T] { - fn encode(&self, s: &mut S) -> Result<(), E> { +impl Encodable for [T] { + fn encode(&self, s: &mut S) -> Result<(), S::Error> { s.emit_seq(self.len(), |s| { for (i, e) in self.iter().enumerate() { try!(s.emit_seq_elt(i, |s| e.encode(s))) @@ -428,8 +446,8 @@ impl,T:Encodable> Encodable for [T] { } } -impl,T:Encodable> Encodable for Vec { - fn encode(&self, s: &mut S) -> Result<(), E> { +impl Encodable for Vec { + fn encode(&self, s: &mut S) -> Result<(), S::Error> { s.emit_seq(self.len(), |s| { for (i, e) in self.iter().enumerate() { try!(s.emit_seq_elt(i, |s| e.encode(s))) @@ -439,8 +457,8 @@ impl,T:Encodable> Encodable for Vec { } } -impl,T:Decodable> Decodable for Vec { - fn decode(d: &mut D) -> Result, E> { +impl Decodable for Vec { + fn decode(d: &mut D) -> Result, D::Error> { d.read_seq(|d, len| { let mut v = Vec::with_capacity(len); for i in range(0, len) { @@ -451,8 +469,8 @@ impl,T:Decodable> Decodable for Vec { } } -impl,T:Encodable> Encodable for Option { - fn encode(&self, s: &mut S) -> Result<(), E> { +impl Encodable for Option { + fn encode(&self, s: &mut S) -> Result<(), S::Error> { s.emit_option(|s| { match *self { None => s.emit_option_none(), @@ -462,8 +480,8 @@ impl,T:Encodable> Encodable for Option { } } -impl,T:Decodable> Decodable for Option { - fn decode(d: &mut D) -> Result, E> { +impl Decodable for Option { + fn decode(d: &mut D) -> Result, D::Error> { d.read_option(|d, b| { if b { Ok(Some(try!(Decodable::decode(d)))) @@ -487,22 +505,23 @@ macro_rules! count_idents { macro_rules! tuple { () => (); ( $($name:ident,)+ ) => ( - impl,$($name:Decodable),*> Decodable for ($($name,)*) { + impl<$($name:Decodable),*> Decodable for ($($name,)*) { #[allow(non_snake_case)] - fn decode(d: &mut D) -> Result<($($name,)*), E> { + fn decode(d: &mut D) -> Result<($($name,)*), D::Error> { let len: uint = count_idents!($($name),*); d.read_tuple(len, |d| { let mut i = 0; - let ret = ($(try!(d.read_tuple_arg({ i+=1; i-1 }, |d| -> Result<$name,E> { + let ret = ($(try!(d.read_tuple_arg({ i+=1; i-1 }, + |d| -> Result<$name,D::Error> { Decodable::decode(d) })),)*); return Ok(ret); }) } } - impl,$($name:Encodable),*> Encodable for ($($name,)*) { + impl<$($name:Encodable),*> Encodable for ($($name,)*) { #[allow(non_snake_case)] - fn encode(&self, s: &mut S) -> Result<(), E> { + fn encode(&self, s: &mut S) -> Result<(), S::Error> { let ($(ref $name,)*) = *self; let mut n = 0; $(let $name = $name; n += 1;)* @@ -519,40 +538,40 @@ macro_rules! tuple { tuple! { T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, } -impl> Encodable for path::posix::Path { - fn encode(&self, e: &mut S) -> Result<(), E> { +impl Encodable for path::posix::Path { + fn encode(&self, e: &mut S) -> Result<(), S::Error> { self.as_vec().encode(e) } } -impl> Decodable for path::posix::Path { - fn decode(d: &mut D) -> Result { +impl Decodable for path::posix::Path { + fn decode(d: &mut D) -> Result { let bytes: Vec = try!(Decodable::decode(d)); Ok(path::posix::Path::new(bytes)) } } -impl> Encodable for path::windows::Path { - fn encode(&self, e: &mut S) -> Result<(), E> { +impl Encodable for path::windows::Path { + fn encode(&self, e: &mut S) -> Result<(), S::Error> { self.as_vec().encode(e) } } -impl> Decodable for path::windows::Path { - fn decode(d: &mut D) -> Result { +impl Decodable for path::windows::Path { + fn decode(d: &mut D) -> Result { let bytes: Vec = try!(Decodable::decode(d)); Ok(path::windows::Path::new(bytes)) } } -impl, T: Encodable + Copy> Encodable for Cell { - fn encode(&self, s: &mut S) -> Result<(), E> { +impl Encodable for Cell { + fn encode(&self, s: &mut S) -> Result<(), S::Error> { self.get().encode(s) } } -impl, T: Decodable + Copy> Decodable for Cell { - fn decode(d: &mut D) -> Result, E> { +impl Decodable for Cell { + fn decode(d: &mut D) -> Result, D::Error> { Ok(Cell::new(try!(Decodable::decode(d)))) } } @@ -562,26 +581,26 @@ impl, T: Decodable + Copy> Decodable for Cell { // `encoder.error("attempting to Encode borrowed RefCell")` // from `encode` when `try_borrow` returns `None`. -impl, T: Encodable> Encodable for RefCell { - fn encode(&self, s: &mut S) -> Result<(), E> { +impl Encodable for RefCell { + fn encode(&self, s: &mut S) -> Result<(), S::Error> { self.borrow().encode(s) } } -impl, T: Decodable> Decodable for RefCell { - fn decode(d: &mut D) -> Result, E> { +impl Decodable for RefCell { + fn decode(d: &mut D) -> Result, D::Error> { Ok(RefCell::new(try!(Decodable::decode(d)))) } } -impl, T:Encodable> Encodable for Arc { - fn encode(&self, s: &mut S) -> Result<(), E> { +impl Encodable for Arc { + fn encode(&self, s: &mut S) -> Result<(), S::Error> { (**self).encode(s) } } -impl,T:Decodable+Send+Sync> Decodable for Arc { - fn decode(d: &mut D) -> Result, E> { +impl Decodable for Arc { + fn decode(d: &mut D) -> Result, D::Error> { Ok(Arc::new(try!(Decodable::decode(d)))) } } @@ -589,14 +608,15 @@ impl,T:Decodable+Send+Sync> Decodable for Arc { // ___________________________________________________________________________ // Helper routines -pub trait EncoderHelpers { - fn emit_from_vec(&mut self, v: &[T], f: F) -> Result<(), E> where - F: FnMut(&mut Self, &T) -> Result<(), E>; +pub trait EncoderHelpers: Encoder { + fn emit_from_vec(&mut self, v: &[T], f: F) + -> Result<(), ::Error> + where F: FnMut(&mut Self, &T) -> Result<(), ::Error>; } -impl> EncoderHelpers for S { - fn emit_from_vec(&mut self, v: &[T], mut f: F) -> Result<(), E> where - F: FnMut(&mut S, &T) -> Result<(), E>, +impl EncoderHelpers for S { + fn emit_from_vec(&mut self, v: &[T], mut f: F) -> Result<(), S::Error> where + F: FnMut(&mut S, &T) -> Result<(), S::Error>, { self.emit_seq(v.len(), |this| { for (i, e) in v.iter().enumerate() { @@ -609,14 +629,15 @@ impl> EncoderHelpers for S { } } -pub trait DecoderHelpers { - fn read_to_vec(&mut self, f: F) -> Result, E> where - F: FnMut(&mut Self) -> Result; +pub trait DecoderHelpers: Decoder { + fn read_to_vec(&mut self, f: F) + -> Result, ::Error> where + F: FnMut(&mut Self) -> Result::Error>; } -impl> DecoderHelpers for D { - fn read_to_vec(&mut self, mut f: F) -> Result, E> where F: - FnMut(&mut D) -> Result, +impl DecoderHelpers for D { + fn read_to_vec(&mut self, mut f: F) -> Result, D::Error> where F: + FnMut(&mut D) -> Result, { self.read_seq(|this, len| { let mut v = Vec::with_capacity(len); diff --git a/src/libserialize/serialize_stage0.rs b/src/libserialize/serialize_stage0.rs new file mode 100644 index 0000000000000..558f9e603e159 --- /dev/null +++ b/src/libserialize/serialize_stage0.rs @@ -0,0 +1,629 @@ +// 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. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Support code for encoding and decoding types. + +/* +Core encoding and decoding interfaces. +*/ + +use std::path; +use std::rc::Rc; +use std::cell::{Cell, RefCell}; +use std::sync::Arc; + +pub trait Encoder { + // Primitive types: + fn emit_nil(&mut self) -> Result<(), E>; + fn emit_uint(&mut self, v: uint) -> Result<(), E>; + fn emit_u64(&mut self, v: u64) -> Result<(), E>; + fn emit_u32(&mut self, v: u32) -> Result<(), E>; + fn emit_u16(&mut self, v: u16) -> Result<(), E>; + fn emit_u8(&mut self, v: u8) -> Result<(), E>; + fn emit_int(&mut self, v: int) -> Result<(), E>; + fn emit_i64(&mut self, v: i64) -> Result<(), E>; + fn emit_i32(&mut self, v: i32) -> Result<(), E>; + fn emit_i16(&mut self, v: i16) -> Result<(), E>; + fn emit_i8(&mut self, v: i8) -> Result<(), E>; + fn emit_bool(&mut self, v: bool) -> Result<(), E>; + fn emit_f64(&mut self, v: f64) -> Result<(), E>; + fn emit_f32(&mut self, v: f32) -> Result<(), E>; + fn emit_char(&mut self, v: char) -> Result<(), E>; + fn emit_str(&mut self, v: &str) -> Result<(), E>; + + // Compound types: + fn emit_enum(&mut self, name: &str, f: F) -> Result<(), E> where + F: FnOnce(&mut Self) -> Result<(), E>; + + fn emit_enum_variant(&mut self, v_name: &str, + v_id: uint, + len: uint, + f: F) -> Result<(), E> where + F: FnOnce(&mut Self) -> Result<(), E>; + fn emit_enum_variant_arg(&mut self, a_idx: uint, f: F) -> Result<(), E> where + F: FnOnce(&mut Self) -> Result<(), E>; + + fn emit_enum_struct_variant(&mut self, v_name: &str, + v_id: uint, + len: uint, + f: F) -> Result<(), E> where + F: FnOnce(&mut Self) -> Result<(), E>; + fn emit_enum_struct_variant_field(&mut self, + f_name: &str, + f_idx: uint, + f: F) -> Result<(), E> where + F: FnOnce(&mut Self) -> Result<(), E>; + + fn emit_struct(&mut self, name: &str, len: uint, f: F) -> Result<(), E> where + F: FnOnce(&mut Self) -> Result<(), E>; + fn emit_struct_field(&mut self, f_name: &str, f_idx: uint, f: F) -> Result<(), E> where + F: FnOnce(&mut Self) -> Result<(), E>; + + fn emit_tuple(&mut self, len: uint, f: F) -> Result<(), E> where + F: FnOnce(&mut Self) -> Result<(), E>; + fn emit_tuple_arg(&mut self, idx: uint, f: F) -> Result<(), E> where + F: FnOnce(&mut Self) -> Result<(), E>; + + fn emit_tuple_struct(&mut self, name: &str, len: uint, f: F) -> Result<(), E> where + F: FnOnce(&mut Self) -> Result<(), E>; + fn emit_tuple_struct_arg(&mut self, f_idx: uint, f: F) -> Result<(), E> where + F: FnOnce(&mut Self) -> Result<(), E>; + + // Specialized types: + fn emit_option(&mut self, f: F) -> Result<(), E> where + F: FnOnce(&mut Self) -> Result<(), E>; + fn emit_option_none(&mut self) -> Result<(), E>; + fn emit_option_some(&mut self, f: F) -> Result<(), E> where + F: FnOnce(&mut Self) -> Result<(), E>; + + fn emit_seq(&mut self, len: uint, f: F) -> Result<(), E> where + F: FnOnce(&mut Self) -> Result<(), E>; + fn emit_seq_elt(&mut self, idx: uint, f: F) -> Result<(), E> where + F: FnOnce(&mut Self) -> Result<(), E>; + + fn emit_map(&mut self, len: uint, f: F) -> Result<(), E> where + F: FnOnce(&mut Self) -> Result<(), E>; + fn emit_map_elt_key(&mut self, idx: uint, f: F) -> Result<(), E> where + F: FnMut(&mut Self) -> Result<(), E>; + fn emit_map_elt_val(&mut self, idx: uint, f: F) -> Result<(), E> where + F: FnOnce(&mut Self) -> Result<(), E>; +} + +pub trait Decoder { + // Primitive types: + fn read_nil(&mut self) -> Result<(), E>; + fn read_uint(&mut self) -> Result; + fn read_u64(&mut self) -> Result; + fn read_u32(&mut self) -> Result; + fn read_u16(&mut self) -> Result; + fn read_u8(&mut self) -> Result; + fn read_int(&mut self) -> Result; + fn read_i64(&mut self) -> Result; + fn read_i32(&mut self) -> Result; + fn read_i16(&mut self) -> Result; + fn read_i8(&mut self) -> Result; + fn read_bool(&mut self) -> Result; + fn read_f64(&mut self) -> Result; + fn read_f32(&mut self) -> Result; + fn read_char(&mut self) -> Result; + fn read_str(&mut self) -> Result; + + // Compound types: + fn read_enum(&mut self, name: &str, f: F) -> Result where + F: FnOnce(&mut Self) -> Result; + + fn read_enum_variant(&mut self, names: &[&str], f: F) -> Result where + F: FnMut(&mut Self, uint) -> Result; + fn read_enum_variant_arg(&mut self, a_idx: uint, f: F) -> Result where + F: FnOnce(&mut Self) -> Result; + + fn read_enum_struct_variant(&mut self, names: &[&str], f: F) -> Result where + F: FnMut(&mut Self, uint) -> Result; + fn read_enum_struct_variant_field(&mut self, + &f_name: &str, + f_idx: uint, + f: F) + -> Result where + F: FnOnce(&mut Self) -> Result; + + fn read_struct(&mut self, s_name: &str, len: uint, f: F) -> Result where + F: FnOnce(&mut Self) -> Result; + fn read_struct_field(&mut self, + f_name: &str, + f_idx: uint, + f: F) + -> Result where + F: FnOnce(&mut Self) -> Result; + + fn read_tuple(&mut self, len: uint, f: F) -> Result where + F: FnOnce(&mut Self) -> Result; + fn read_tuple_arg(&mut self, a_idx: uint, f: F) -> Result where + F: FnOnce(&mut Self) -> Result; + + fn read_tuple_struct(&mut self, s_name: &str, len: uint, f: F) -> Result where + F: FnOnce(&mut Self) -> Result; + fn read_tuple_struct_arg(&mut self, a_idx: uint, f: F) -> Result where + F: FnOnce(&mut Self) -> Result; + + // Specialized types: + fn read_option(&mut self, f: F) -> Result where + F: FnMut(&mut Self, bool) -> Result; + + fn read_seq(&mut self, f: F) -> Result where + F: FnOnce(&mut Self, uint) -> Result; + fn read_seq_elt(&mut self, idx: uint, f: F) -> Result where + F: FnOnce(&mut Self) -> Result; + + fn read_map(&mut self, f: F) -> Result where + F: FnOnce(&mut Self, uint) -> Result; + fn read_map_elt_key(&mut self, idx: uint, f: F) -> Result where + F: FnOnce(&mut Self) -> Result; + fn read_map_elt_val(&mut self, idx: uint, f: F) -> Result where + F: FnOnce(&mut Self) -> Result; + + // Failure + fn error(&mut self, err: &str) -> E; +} + +pub trait Encodable, E> for Sized? { + fn encode(&self, s: &mut S) -> Result<(), E>; +} + +pub trait Decodable, E> { + fn decode(d: &mut D) -> Result; +} + +impl> Encodable for uint { + fn encode(&self, s: &mut S) -> Result<(), E> { + s.emit_uint(*self) + } +} + +impl> Decodable for uint { + fn decode(d: &mut D) -> Result { + d.read_uint() + } +} + +impl> Encodable for u8 { + fn encode(&self, s: &mut S) -> Result<(), E> { + s.emit_u8(*self) + } +} + +impl> Decodable for u8 { + fn decode(d: &mut D) -> Result { + d.read_u8() + } +} + +impl> Encodable for u16 { + fn encode(&self, s: &mut S) -> Result<(), E> { + s.emit_u16(*self) + } +} + +impl> Decodable for u16 { + fn decode(d: &mut D) -> Result { + d.read_u16() + } +} + +impl> Encodable for u32 { + fn encode(&self, s: &mut S) -> Result<(), E> { + s.emit_u32(*self) + } +} + +impl> Decodable for u32 { + fn decode(d: &mut D) -> Result { + d.read_u32() + } +} + +impl> Encodable for u64 { + fn encode(&self, s: &mut S) -> Result<(), E> { + s.emit_u64(*self) + } +} + +impl> Decodable for u64 { + fn decode(d: &mut D) -> Result { + d.read_u64() + } +} + +impl> Encodable for int { + fn encode(&self, s: &mut S) -> Result<(), E> { + s.emit_int(*self) + } +} + +impl> Decodable for int { + fn decode(d: &mut D) -> Result { + d.read_int() + } +} + +impl> Encodable for i8 { + fn encode(&self, s: &mut S) -> Result<(), E> { + s.emit_i8(*self) + } +} + +impl> Decodable for i8 { + fn decode(d: &mut D) -> Result { + d.read_i8() + } +} + +impl> Encodable for i16 { + fn encode(&self, s: &mut S) -> Result<(), E> { + s.emit_i16(*self) + } +} + +impl> Decodable for i16 { + fn decode(d: &mut D) -> Result { + d.read_i16() + } +} + +impl> Encodable for i32 { + fn encode(&self, s: &mut S) -> Result<(), E> { + s.emit_i32(*self) + } +} + +impl> Decodable for i32 { + fn decode(d: &mut D) -> Result { + d.read_i32() + } +} + +impl> Encodable for i64 { + fn encode(&self, s: &mut S) -> Result<(), E> { + s.emit_i64(*self) + } +} + +impl> Decodable for i64 { + fn decode(d: &mut D) -> Result { + d.read_i64() + } +} + +impl> Encodable for str { + fn encode(&self, s: &mut S) -> Result<(), E> { + s.emit_str(self) + } +} + +impl> Encodable for String { + fn encode(&self, s: &mut S) -> Result<(), E> { + s.emit_str(self[]) + } +} + +impl> Decodable for String { + fn decode(d: &mut D) -> Result { + d.read_str() + } +} + +impl> Encodable for f32 { + fn encode(&self, s: &mut S) -> Result<(), E> { + s.emit_f32(*self) + } +} + +impl> Decodable for f32 { + fn decode(d: &mut D) -> Result { + d.read_f32() + } +} + +impl> Encodable for f64 { + fn encode(&self, s: &mut S) -> Result<(), E> { + s.emit_f64(*self) + } +} + +impl> Decodable for f64 { + fn decode(d: &mut D) -> Result { + d.read_f64() + } +} + +impl> Encodable for bool { + fn encode(&self, s: &mut S) -> Result<(), E> { + s.emit_bool(*self) + } +} + +impl> Decodable for bool { + fn decode(d: &mut D) -> Result { + d.read_bool() + } +} + +impl> Encodable for char { + fn encode(&self, s: &mut S) -> Result<(), E> { + s.emit_char(*self) + } +} + +impl> Decodable for char { + fn decode(d: &mut D) -> Result { + d.read_char() + } +} + +impl> Encodable for () { + fn encode(&self, s: &mut S) -> Result<(), E> { + s.emit_nil() + } +} + +impl> Decodable for () { + fn decode(d: &mut D) -> Result<(), E> { + d.read_nil() + } +} + +impl<'a, E, S: Encoder, Sized? T: Encodable> Encodable for &'a T { + fn encode(&self, s: &mut S) -> Result<(), E> { + (**self).encode(s) + } +} + +impl, Sized? T: Encodable> Encodable for Box { + fn encode(&self, s: &mut S) -> Result<(), E> { + (**self).encode(s) + } +} + +impl, T: Decodable> Decodable for Box { + fn decode(d: &mut D) -> Result, E> { + Ok(box try!(Decodable::decode(d))) + } +} + +impl, T: Decodable> Decodable for Box<[T]> { + fn decode(d: &mut D) -> Result, E> { + let v: Vec = try!(Decodable::decode(d)); + Ok(v.into_boxed_slice()) + } +} + +impl,T:Encodable> Encodable for Rc { + #[inline] + fn encode(&self, s: &mut S) -> Result<(), E> { + (**self).encode(s) + } +} + +impl,T:Decodable> Decodable for Rc { + #[inline] + fn decode(d: &mut D) -> Result, E> { + Ok(Rc::new(try!(Decodable::decode(d)))) + } +} + +impl,T:Encodable> Encodable for [T] { + fn encode(&self, s: &mut S) -> Result<(), E> { + s.emit_seq(self.len(), |s| { + for (i, e) in self.iter().enumerate() { + try!(s.emit_seq_elt(i, |s| e.encode(s))) + } + Ok(()) + }) + } +} + +impl,T:Encodable> Encodable for Vec { + fn encode(&self, s: &mut S) -> Result<(), E> { + s.emit_seq(self.len(), |s| { + for (i, e) in self.iter().enumerate() { + try!(s.emit_seq_elt(i, |s| e.encode(s))) + } + Ok(()) + }) + } +} + +impl,T:Decodable> Decodable for Vec { + fn decode(d: &mut D) -> Result, E> { + d.read_seq(|d, len| { + let mut v = Vec::with_capacity(len); + for i in range(0, len) { + v.push(try!(d.read_seq_elt(i, |d| Decodable::decode(d)))); + } + Ok(v) + }) + } +} + +impl,T:Encodable> Encodable for Option { + fn encode(&self, s: &mut S) -> Result<(), E> { + s.emit_option(|s| { + match *self { + None => s.emit_option_none(), + Some(ref v) => s.emit_option_some(|s| v.encode(s)), + } + }) + } +} + +impl,T:Decodable> Decodable for Option { + fn decode(d: &mut D) -> Result, E> { + d.read_option(|d, b| { + if b { + Ok(Some(try!(Decodable::decode(d)))) + } else { + Ok(None) + } + }) + } +} + +macro_rules! peel { + ($name:ident, $($other:ident,)*) => (tuple! { $($other,)* }) +} + +/// Evaluates to the number of identifiers passed to it, for example: `count_idents!(a, b, c) == 3 +macro_rules! count_idents { + () => { 0u }; + ($_i:ident $(, $rest:ident)*) => { 1 + count_idents!($($rest),*) } +} + +macro_rules! tuple { + () => (); + ( $($name:ident,)+ ) => ( + impl,$($name:Decodable),*> Decodable for ($($name,)*) { + #[allow(non_snake_case)] + fn decode(d: &mut D) -> Result<($($name,)*), E> { + let len: uint = count_idents!($($name),*); + d.read_tuple(len, |d| { + let mut i = 0; + let ret = ($(try!(d.read_tuple_arg({ i+=1; i-1 }, |d| -> Result<$name,E> { + Decodable::decode(d) + })),)*); + return Ok(ret); + }) + } + } + impl,$($name:Encodable),*> Encodable for ($($name,)*) { + #[allow(non_snake_case)] + fn encode(&self, s: &mut S) -> Result<(), E> { + let ($(ref $name,)*) = *self; + let mut n = 0; + $(let $name = $name; n += 1;)* + s.emit_tuple(n, |s| { + let mut i = 0; + $(try!(s.emit_tuple_arg({ i+=1; i-1 }, |s| $name.encode(s)));)* + Ok(()) + }) + } + } + peel! { $($name,)* } + ) +} + +tuple! { T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, } + +impl> Encodable for path::posix::Path { + fn encode(&self, e: &mut S) -> Result<(), E> { + self.as_vec().encode(e) + } +} + +impl> Decodable for path::posix::Path { + fn decode(d: &mut D) -> Result { + let bytes: Vec = try!(Decodable::decode(d)); + Ok(path::posix::Path::new(bytes)) + } +} + +impl> Encodable for path::windows::Path { + fn encode(&self, e: &mut S) -> Result<(), E> { + self.as_vec().encode(e) + } +} + +impl> Decodable for path::windows::Path { + fn decode(d: &mut D) -> Result { + let bytes: Vec = try!(Decodable::decode(d)); + Ok(path::windows::Path::new(bytes)) + } +} + +impl, T: Encodable + Copy> Encodable for Cell { + fn encode(&self, s: &mut S) -> Result<(), E> { + self.get().encode(s) + } +} + +impl, T: Decodable + Copy> Decodable for Cell { + fn decode(d: &mut D) -> Result, E> { + Ok(Cell::new(try!(Decodable::decode(d)))) + } +} + +// FIXME: #15036 +// Should use `try_borrow`, returning a +// `encoder.error("attempting to Encode borrowed RefCell")` +// from `encode` when `try_borrow` returns `None`. + +impl, T: Encodable> Encodable for RefCell { + fn encode(&self, s: &mut S) -> Result<(), E> { + self.borrow().encode(s) + } +} + +impl, T: Decodable> Decodable for RefCell { + fn decode(d: &mut D) -> Result, E> { + Ok(RefCell::new(try!(Decodable::decode(d)))) + } +} + +impl, T:Encodable> Encodable for Arc { + fn encode(&self, s: &mut S) -> Result<(), E> { + (**self).encode(s) + } +} + +impl,T:Decodable+Send+Sync> Decodable for Arc { + fn decode(d: &mut D) -> Result, E> { + Ok(Arc::new(try!(Decodable::decode(d)))) + } +} + +// ___________________________________________________________________________ +// Helper routines + +pub trait EncoderHelpers { + fn emit_from_vec(&mut self, v: &[T], f: F) -> Result<(), E> where + F: FnMut(&mut Self, &T) -> Result<(), E>; +} + +impl> EncoderHelpers for S { + fn emit_from_vec(&mut self, v: &[T], mut f: F) -> Result<(), E> where + F: FnMut(&mut S, &T) -> Result<(), E>, + { + self.emit_seq(v.len(), |this| { + for (i, e) in v.iter().enumerate() { + try!(this.emit_seq_elt(i, |this| { + f(this, e) + })); + } + Ok(()) + }) + } +} + +pub trait DecoderHelpers { + fn read_to_vec(&mut self, f: F) -> Result, E> where + F: FnMut(&mut Self) -> Result; +} + +impl> DecoderHelpers for D { + fn read_to_vec(&mut self, mut f: F) -> Result, E> where F: + FnMut(&mut D) -> Result, + { + self.read_seq(|this, len| { + let mut v = Vec::with_capacity(len); + for i in range(0, len) { + v.push(try!(this.read_seq_elt(i, |this| f(this)))); + } + Ok(v) + }) + } +} diff --git a/src/libstd/ascii.rs b/src/libstd/ascii.rs index bcd87f6786d35..abd4c7faa5bda 100644 --- a/src/libstd/ascii.rs +++ b/src/libstd/ascii.rs @@ -14,7 +14,6 @@ #![unstable = "unsure about placement and naming"] -use core::kinds::Sized; use iter::IteratorExt; use ops::FnMut; use slice::SliceExt; @@ -38,7 +37,7 @@ pub trait OwnedAsciiExt { /// Extension methods for ASCII-subset only operations on string slices #[experimental = "would prefer to do this in a more general way"] -pub trait AsciiExt for Sized? { +pub trait AsciiExt { /// Check if within the ASCII range. fn is_ascii(&self) -> bool; diff --git a/src/libstd/c_str.rs b/src/libstd/c_str.rs deleted file mode 100644 index 9c96a9cac7831..0000000000000 --- a/src/libstd/c_str.rs +++ /dev/null @@ -1,857 +0,0 @@ -// Copyright 2012 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! C-string manipulation and management -//! -//! This modules provides the basic methods for creating and manipulating -//! null-terminated strings for use with FFI calls (back to C). Most C APIs require -//! that the string being passed to them is null-terminated, and by default rust's -//! string types are *not* null terminated. -//! -//! The other problem with translating Rust strings to C strings is that Rust -//! strings can validly contain a null-byte in the middle of the string (0 is a -//! valid Unicode codepoint). This means that not all Rust strings can actually be -//! translated to C strings. -//! -//! # Creation of a C string -//! -//! A C string is managed through the `CString` type defined in this module. It -//! "owns" the internal buffer of characters and will automatically deallocate the -//! buffer when the string is dropped. The `ToCStr` trait is implemented for `&str` -//! and `&[u8]`, but the conversions can fail due to some of the limitations -//! explained above. -//! -//! This also means that currently whenever a C string is created, an allocation -//! must be performed to place the data elsewhere (the lifetime of the C string is -//! not tied to the lifetime of the original string/data buffer). If C strings are -//! heavily used in applications, then caching may be advisable to prevent -//! unnecessary amounts of allocations. -//! -//! Be carefull to remember that the memory is managed by C allocator API and not -//! by Rust allocator API. -//! That means that the CString pointers should be freed with C allocator API -//! if you intend to do that on your own, as the behaviour if you free them with -//! Rust's allocator API is not well defined -//! -//! An example of creating and using a C string would be: -//! -//! ```rust -//! extern crate libc; -//! -//! use std::c_str::ToCStr; -//! -//! extern { -//! fn puts(s: *const libc::c_char); -//! } -//! -//! fn main() { -//! let my_string = "Hello, world!"; -//! -//! // Allocate the C string with an explicit local that owns the string. The -//! // `c_buffer` pointer will be deallocated when `my_c_string` goes out of scope. -//! let my_c_string = my_string.to_c_str(); -//! unsafe { -//! puts(my_c_string.as_ptr()); -//! } -//! -//! // Don't save/return the pointer to the C string, the `c_buffer` will be -//! // deallocated when this block returns! -//! my_string.with_c_str(|c_buffer| { -//! unsafe { puts(c_buffer); } -//! }); -//! } -//! ``` - -use core::prelude::*; -use libc; - -use cmp::Ordering; -use fmt; -use hash; -use mem; -use ptr; -use slice::{self, IntSliceExt}; -use str; -use string::String; -use core::kinds::marker; - -/// The representation of a C String. -/// -/// This structure wraps a `*libc::c_char`, and will automatically free the -/// memory it is pointing to when it goes out of scope. -#[allow(missing_copy_implementations)] -pub struct CString { - buf: *const libc::c_char, - owns_buffer_: bool, -} - -unsafe impl Send for CString { } -unsafe impl Sync for CString { } - -impl Clone for CString { - /// Clone this CString into a new, uniquely owned CString. For safety - /// reasons, this is always a deep clone with the memory allocated - /// with C's allocator API, rather than the usual shallow clone. - fn clone(&self) -> CString { - let len = self.len() + 1; - let buf = unsafe { libc::malloc(len as libc::size_t) } as *mut libc::c_char; - if buf.is_null() { ::alloc::oom() } - unsafe { ptr::copy_nonoverlapping_memory(buf, self.buf, len); } - CString { buf: buf as *const libc::c_char, owns_buffer_: true } - } -} - -impl PartialEq for CString { - fn eq(&self, other: &CString) -> bool { - // Check if the two strings share the same buffer - if self.buf as uint == other.buf as uint { - true - } else { - unsafe { - libc::strcmp(self.buf, other.buf) == 0 - } - } - } -} - -impl PartialOrd for CString { - #[inline] - fn partial_cmp(&self, other: &CString) -> Option { - self.as_bytes().partial_cmp(other.as_bytes()) - } -} - -impl Eq for CString {} - -impl hash::Hash for CString { - #[inline] - fn hash(&self, state: &mut S) { - self.as_bytes().hash(state) - } -} - -impl CString { - /// Create a C String from a pointer, with memory managed by C's allocator - /// API, so avoid calling it with a pointer to memory managed by Rust's - /// allocator API, as the behaviour would not be well defined. - /// - ///# Panics - /// - /// Panics if `buf` is null - pub unsafe fn new(buf: *const libc::c_char, owns_buffer: bool) -> CString { - assert!(!buf.is_null()); - CString { buf: buf, owns_buffer_: owns_buffer } - } - - /// Return a pointer to the NUL-terminated string data. - /// - /// `.as_ptr` returns an internal pointer into the `CString`, and - /// may be invalidated when the `CString` falls out of scope (the - /// destructor will run, freeing the allocation if there is - /// one). - /// - /// ```rust - /// use std::c_str::ToCStr; - /// - /// let foo = "some string"; - /// - /// // right - /// let x = foo.to_c_str(); - /// let p = x.as_ptr(); - /// - /// // wrong (the CString will be freed, invalidating `p`) - /// let p = foo.to_c_str().as_ptr(); - /// ``` - /// - /// # Example - /// - /// ```rust - /// extern crate libc; - /// - /// use std::c_str::ToCStr; - /// - /// fn main() { - /// let c_str = "foo bar".to_c_str(); - /// unsafe { - /// libc::puts(c_str.as_ptr()); - /// } - /// } - /// ``` - pub fn as_ptr(&self) -> *const libc::c_char { - self.buf - } - - /// Return a mutable pointer to the NUL-terminated string data. - /// - /// `.as_mut_ptr` returns an internal pointer into the `CString`, and - /// may be invalidated when the `CString` falls out of scope (the - /// destructor will run, freeing the allocation if there is - /// one). - /// - /// ```rust - /// use std::c_str::ToCStr; - /// - /// let foo = "some string"; - /// - /// // right - /// let mut x = foo.to_c_str(); - /// let p = x.as_mut_ptr(); - /// - /// // wrong (the CString will be freed, invalidating `p`) - /// let p = foo.to_c_str().as_mut_ptr(); - /// ``` - pub fn as_mut_ptr(&mut self) -> *mut libc::c_char { - self.buf as *mut _ - } - - /// Returns whether or not the `CString` owns the buffer. - pub fn owns_buffer(&self) -> bool { - self.owns_buffer_ - } - - /// Converts the CString into a `&[u8]` without copying. - /// Includes the terminating NUL byte. - #[inline] - pub fn as_bytes<'a>(&'a self) -> &'a [u8] { - unsafe { - slice::from_raw_buf(&self.buf, self.len() + 1).as_unsigned() - } - } - - /// Converts the CString into a `&[u8]` without copying. - /// Does not include the terminating NUL byte. - #[inline] - pub fn as_bytes_no_nul<'a>(&'a self) -> &'a [u8] { - unsafe { - slice::from_raw_buf(&self.buf, self.len()).as_unsigned() - } - } - - /// Converts the CString into a `&str` without copying. - /// Returns None if the CString is not UTF-8. - #[inline] - pub fn as_str<'a>(&'a self) -> Option<&'a str> { - let buf = self.as_bytes_no_nul(); - str::from_utf8(buf).ok() - } - - /// Return a CString iterator. - pub fn iter<'a>(&'a self) -> CChars<'a> { - CChars { - ptr: self.buf, - marker: marker::ContravariantLifetime, - } - } - - /// Unwraps the wrapped `*libc::c_char` from the `CString` wrapper. - /// - /// Any ownership of the buffer by the `CString` wrapper is - /// forgotten, meaning that the backing allocation of this - /// `CString` is not automatically freed if it owns the - /// allocation. In this case, a user of `.unwrap()` should ensure - /// the allocation is freed, to avoid leaking memory. You should - /// use libc's memory allocator in this case. - /// - /// Prefer `.as_ptr()` when just retrieving a pointer to the - /// string data, as that does not relinquish ownership. - pub unsafe fn into_inner(mut self) -> *const libc::c_char { - self.owns_buffer_ = false; - self.buf - } - - /// Return the number of bytes in the CString (not including the NUL - /// terminator). - #[inline] - pub fn len(&self) -> uint { - unsafe { libc::strlen(self.buf) as uint } - } - - /// Returns if there are no bytes in this string - #[inline] - pub fn is_empty(&self) -> bool { self.len() == 0 } -} - -impl Drop for CString { - fn drop(&mut self) { - if self.owns_buffer_ { - unsafe { - libc::free(self.buf as *mut libc::c_void) - } - } - } -} - -impl fmt::Show for CString { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - String::from_utf8_lossy(self.as_bytes_no_nul()).fmt(f) - } -} - -/// A generic trait for converting a value to a CString. -pub trait ToCStr for Sized? { - /// Copy the receiver into a CString. - /// - /// # Panics - /// - /// Panics the task if the receiver has an interior null. - fn to_c_str(&self) -> CString; - - /// Unsafe variant of `to_c_str()` that doesn't check for nulls. - unsafe fn to_c_str_unchecked(&self) -> CString; - - /// Work with a temporary CString constructed from the receiver. - /// The provided `*libc::c_char` will be freed immediately upon return. - /// - /// # Example - /// - /// ```rust - /// extern crate libc; - /// - /// use std::c_str::ToCStr; - /// - /// fn main() { - /// let s = "PATH".with_c_str(|path| unsafe { - /// libc::getenv(path) - /// }); - /// } - /// ``` - /// - /// # Panics - /// - /// Panics the task if the receiver has an interior null. - #[inline] - fn with_c_str(&self, f: F) -> T where - F: FnOnce(*const libc::c_char) -> T, - { - let c_str = self.to_c_str(); - f(c_str.as_ptr()) - } - - /// Unsafe variant of `with_c_str()` that doesn't check for nulls. - #[inline] - unsafe fn with_c_str_unchecked(&self, f: F) -> T where - F: FnOnce(*const libc::c_char) -> T, - { - let c_str = self.to_c_str_unchecked(); - f(c_str.as_ptr()) - } -} - -impl ToCStr for str { - #[inline] - fn to_c_str(&self) -> CString { - self.as_bytes().to_c_str() - } - - #[inline] - unsafe fn to_c_str_unchecked(&self) -> CString { - self.as_bytes().to_c_str_unchecked() - } - - #[inline] - fn with_c_str(&self, f: F) -> T where - F: FnOnce(*const libc::c_char) -> T, - { - self.as_bytes().with_c_str(f) - } - - #[inline] - unsafe fn with_c_str_unchecked(&self, f: F) -> T where - F: FnOnce(*const libc::c_char) -> T, - { - self.as_bytes().with_c_str_unchecked(f) - } -} - -impl ToCStr for String { - #[inline] - fn to_c_str(&self) -> CString { - self.as_bytes().to_c_str() - } - - #[inline] - unsafe fn to_c_str_unchecked(&self) -> CString { - self.as_bytes().to_c_str_unchecked() - } - - #[inline] - fn with_c_str(&self, f: F) -> T where - F: FnOnce(*const libc::c_char) -> T, - { - self.as_bytes().with_c_str(f) - } - - #[inline] - unsafe fn with_c_str_unchecked(&self, f: F) -> T where - F: FnOnce(*const libc::c_char) -> T, - { - self.as_bytes().with_c_str_unchecked(f) - } -} - -// The length of the stack allocated buffer for `vec.with_c_str()` -const BUF_LEN: uint = 128; - -impl ToCStr for [u8] { - fn to_c_str(&self) -> CString { - let mut cs = unsafe { self.to_c_str_unchecked() }; - check_for_null(self, cs.as_mut_ptr()); - cs - } - - unsafe fn to_c_str_unchecked(&self) -> CString { - let self_len = self.len(); - let buf = libc::malloc(self_len as libc::size_t + 1) as *mut u8; - if buf.is_null() { ::alloc::oom() } - - ptr::copy_memory(buf, self.as_ptr(), self_len); - *buf.offset(self_len as int) = 0; - - CString::new(buf as *const libc::c_char, true) - } - - fn with_c_str(&self, f: F) -> T where - F: FnOnce(*const libc::c_char) -> T, - { - unsafe { with_c_str(self, true, f) } - } - - unsafe fn with_c_str_unchecked(&self, f: F) -> T where - F: FnOnce(*const libc::c_char) -> T, - { - with_c_str(self, false, f) - } -} - -impl<'a, Sized? T: ToCStr> ToCStr for &'a T { - #[inline] - fn to_c_str(&self) -> CString { - (**self).to_c_str() - } - - #[inline] - unsafe fn to_c_str_unchecked(&self) -> CString { - (**self).to_c_str_unchecked() - } - - #[inline] - fn with_c_str(&self, f: F) -> T where - F: FnOnce(*const libc::c_char) -> T, - { - (**self).with_c_str(f) - } - - #[inline] - unsafe fn with_c_str_unchecked(&self, f: F) -> T where - F: FnOnce(*const libc::c_char) -> T, - { - (**self).with_c_str_unchecked(f) - } -} - -// Unsafe function that handles possibly copying the &[u8] into a stack array. -unsafe fn with_c_str(v: &[u8], checked: bool, f: F) -> T where - F: FnOnce(*const libc::c_char) -> T, -{ - let c_str = if v.len() < BUF_LEN { - let mut buf: [u8; BUF_LEN] = mem::uninitialized(); - slice::bytes::copy_memory(&mut buf, v); - buf[v.len()] = 0; - - let buf = buf.as_mut_ptr(); - if checked { - check_for_null(v, buf as *mut libc::c_char); - } - - return f(buf as *const libc::c_char) - } else if checked { - v.to_c_str() - } else { - v.to_c_str_unchecked() - }; - - f(c_str.as_ptr()) -} - -#[inline] -fn check_for_null(v: &[u8], buf: *mut libc::c_char) { - for i in range(0, v.len()) { - unsafe { - let p = buf.offset(i as int); - assert!(*p != 0); - } - } -} - -/// External iterator for a CString's bytes. -/// -/// Use with the `std::iter` module. -#[allow(raw_pointer_deriving)] -#[derive(Clone)] -pub struct CChars<'a> { - ptr: *const libc::c_char, - marker: marker::ContravariantLifetime<'a>, -} - -impl<'a> Iterator for CChars<'a> { - type Item = libc::c_char; - - fn next(&mut self) -> Option { - let ch = unsafe { *self.ptr }; - if ch == 0 { - None - } else { - self.ptr = unsafe { self.ptr.offset(1) }; - Some(ch) - } - } -} - -/// Parses a C "multistring", eg windows env values or -/// the req->ptr result in a uv_fs_readdir() call. -/// -/// Optionally, a `count` can be passed in, limiting the -/// parsing to only being done `count`-times. -/// -/// The specified closure is invoked with each string that -/// is found, and the number of strings found is returned. -pub unsafe fn from_c_multistring(buf: *const libc::c_char, - count: Option, - mut f: F) - -> uint where - F: FnMut(&CString), -{ - - let mut curr_ptr: uint = buf as uint; - let mut ctr = 0; - let (limited_count, limit) = match count { - Some(limit) => (true, limit), - None => (false, 0) - }; - while ((limited_count && ctr < limit) || !limited_count) - && *(curr_ptr as *const libc::c_char) != 0 as libc::c_char { - let cstr = CString::new(curr_ptr as *const libc::c_char, false); - f(&cstr); - curr_ptr += cstr.len() + 1; - ctr += 1; - } - return ctr; -} - -#[cfg(test)] -mod tests { - use prelude::v1::*; - use super::*; - use ptr; - use thread::Thread; - use libc; - - #[test] - fn test_str_multistring_parsing() { - unsafe { - let input = b"zero\0one\0\0"; - let ptr = input.as_ptr(); - let expected = ["zero", "one"]; - let mut it = expected.iter(); - let result = from_c_multistring(ptr as *const libc::c_char, None, |c| { - let cbytes = c.as_bytes_no_nul(); - assert_eq!(cbytes, it.next().unwrap().as_bytes()); - }); - assert_eq!(result, 2); - assert!(it.next().is_none()); - } - } - - #[test] - fn test_str_to_c_str() { - let c_str = "".to_c_str(); - unsafe { - assert_eq!(*c_str.as_ptr().offset(0), 0); - } - - let c_str = "hello".to_c_str(); - let buf = c_str.as_ptr(); - unsafe { - assert_eq!(*buf.offset(0), 'h' as libc::c_char); - assert_eq!(*buf.offset(1), 'e' as libc::c_char); - assert_eq!(*buf.offset(2), 'l' as libc::c_char); - assert_eq!(*buf.offset(3), 'l' as libc::c_char); - assert_eq!(*buf.offset(4), 'o' as libc::c_char); - assert_eq!(*buf.offset(5), 0); - } - } - - #[test] - fn test_vec_to_c_str() { - let b: &[u8] = &[]; - let c_str = b.to_c_str(); - unsafe { - assert_eq!(*c_str.as_ptr().offset(0), 0); - } - - let c_str = b"hello".to_c_str(); - let buf = c_str.as_ptr(); - unsafe { - assert_eq!(*buf.offset(0), 'h' as libc::c_char); - assert_eq!(*buf.offset(1), 'e' as libc::c_char); - assert_eq!(*buf.offset(2), 'l' as libc::c_char); - assert_eq!(*buf.offset(3), 'l' as libc::c_char); - assert_eq!(*buf.offset(4), 'o' as libc::c_char); - assert_eq!(*buf.offset(5), 0); - } - - let c_str = b"foo\xFF".to_c_str(); - let buf = c_str.as_ptr(); - unsafe { - assert_eq!(*buf.offset(0), 'f' as libc::c_char); - assert_eq!(*buf.offset(1), 'o' as libc::c_char); - assert_eq!(*buf.offset(2), 'o' as libc::c_char); - assert_eq!(*buf.offset(3), 0xffu8 as libc::c_char); - assert_eq!(*buf.offset(4), 0); - } - } - - #[test] - fn test_unwrap() { - let c_str = "hello".to_c_str(); - unsafe { libc::free(c_str.into_inner() as *mut libc::c_void) } - } - - #[test] - fn test_as_ptr() { - let c_str = "hello".to_c_str(); - let len = unsafe { libc::strlen(c_str.as_ptr()) }; - assert_eq!(len, 5); - } - - #[test] - fn test_iterator() { - let c_str = "".to_c_str(); - let mut iter = c_str.iter(); - assert_eq!(iter.next(), None); - - let c_str = "hello".to_c_str(); - let mut iter = c_str.iter(); - assert_eq!(iter.next(), Some('h' as libc::c_char)); - assert_eq!(iter.next(), Some('e' as libc::c_char)); - assert_eq!(iter.next(), Some('l' as libc::c_char)); - assert_eq!(iter.next(), Some('l' as libc::c_char)); - assert_eq!(iter.next(), Some('o' as libc::c_char)); - assert_eq!(iter.next(), None); - } - - #[test] - fn test_to_c_str_fail() { - assert!(Thread::spawn(move|| { "he\x00llo".to_c_str() }).join().is_err()); - } - - #[test] - fn test_to_c_str_unchecked() { - unsafe { - let c_string = "he\x00llo".to_c_str_unchecked(); - let buf = c_string.as_ptr(); - assert_eq!(*buf.offset(0), 'h' as libc::c_char); - assert_eq!(*buf.offset(1), 'e' as libc::c_char); - assert_eq!(*buf.offset(2), 0); - assert_eq!(*buf.offset(3), 'l' as libc::c_char); - assert_eq!(*buf.offset(4), 'l' as libc::c_char); - assert_eq!(*buf.offset(5), 'o' as libc::c_char); - assert_eq!(*buf.offset(6), 0); - } - } - - #[test] - fn test_as_bytes() { - let c_str = "hello".to_c_str(); - assert_eq!(c_str.as_bytes(), b"hello\0"); - let c_str = "".to_c_str(); - assert_eq!(c_str.as_bytes(), b"\0"); - let c_str = b"foo\xFF".to_c_str(); - assert_eq!(c_str.as_bytes(), b"foo\xFF\0"); - } - - #[test] - fn test_as_bytes_no_nul() { - let c_str = "hello".to_c_str(); - assert_eq!(c_str.as_bytes_no_nul(), b"hello"); - let c_str = "".to_c_str(); - let exp: &[u8] = &[]; - assert_eq!(c_str.as_bytes_no_nul(), exp); - let c_str = b"foo\xFF".to_c_str(); - assert_eq!(c_str.as_bytes_no_nul(), b"foo\xFF"); - } - - #[test] - fn test_as_str() { - let c_str = "hello".to_c_str(); - assert_eq!(c_str.as_str(), Some("hello")); - let c_str = "".to_c_str(); - assert_eq!(c_str.as_str(), Some("")); - let c_str = b"foo\xFF".to_c_str(); - assert_eq!(c_str.as_str(), None); - } - - #[test] - #[should_fail] - fn test_new_fail() { - let _c_str = unsafe { CString::new(ptr::null(), false) }; - } - - #[test] - fn test_clone() { - let a = "hello".to_c_str(); - let b = a.clone(); - assert!(a == b); - } - - #[test] - fn test_clone_noleak() { - fn foo(f: F) where F: FnOnce(&CString) { - let s = "test".to_string(); - let c = s.to_c_str(); - // give the closure a non-owned CString - let mut c_ = unsafe { CString::new(c.as_ptr(), false) }; - f(&c_); - // muck with the buffer for later printing - unsafe { *c_.as_mut_ptr() = 'X' as libc::c_char } - } - - let mut c_: Option = None; - foo(|c| { - c_ = Some(c.clone()); - c.clone(); - // force a copy, reading the memory - c.as_bytes().to_vec(); - }); - let c_ = c_.unwrap(); - // force a copy, reading the memory - c_.as_bytes().to_vec(); - } -} - -#[cfg(test)] -mod bench { - extern crate test; - - use prelude::v1::*; - use self::test::Bencher; - use libc; - use c_str::ToCStr; - - #[inline] - fn check(s: &str, c_str: *const libc::c_char) { - let s_buf = s.as_ptr(); - for i in range(0, s.len()) { - unsafe { - assert_eq!( - *s_buf.offset(i as int) as libc::c_char, - *c_str.offset(i as int)); - } - } - } - - static S_SHORT: &'static str = "Mary"; - static S_MEDIUM: &'static str = "Mary had a little lamb"; - static S_LONG: &'static str = "\ - Mary had a little lamb, Little lamb - Mary had a little lamb, Little lamb - Mary had a little lamb, Little lamb - Mary had a little lamb, Little lamb - Mary had a little lamb, Little lamb - Mary had a little lamb, Little lamb"; - - fn bench_to_string(b: &mut Bencher, s: &str) { - b.iter(|| { - let c_str = s.to_c_str(); - check(s, c_str.as_ptr()); - }) - } - - #[bench] - fn bench_to_c_str_short(b: &mut Bencher) { - bench_to_string(b, S_SHORT) - } - - #[bench] - fn bench_to_c_str_medium(b: &mut Bencher) { - bench_to_string(b, S_MEDIUM) - } - - #[bench] - fn bench_to_c_str_long(b: &mut Bencher) { - bench_to_string(b, S_LONG) - } - - fn bench_to_c_str_unchecked(b: &mut Bencher, s: &str) { - b.iter(|| { - let c_str = unsafe { s.to_c_str_unchecked() }; - check(s, c_str.as_ptr()) - }) - } - - #[bench] - fn bench_to_c_str_unchecked_short(b: &mut Bencher) { - bench_to_c_str_unchecked(b, S_SHORT) - } - - #[bench] - fn bench_to_c_str_unchecked_medium(b: &mut Bencher) { - bench_to_c_str_unchecked(b, S_MEDIUM) - } - - #[bench] - fn bench_to_c_str_unchecked_long(b: &mut Bencher) { - bench_to_c_str_unchecked(b, S_LONG) - } - - fn bench_with_c_str(b: &mut Bencher, s: &str) { - b.iter(|| { - s.with_c_str(|c_str_buf| check(s, c_str_buf)) - }) - } - - #[bench] - fn bench_with_c_str_short(b: &mut Bencher) { - bench_with_c_str(b, S_SHORT) - } - - #[bench] - fn bench_with_c_str_medium(b: &mut Bencher) { - bench_with_c_str(b, S_MEDIUM) - } - - #[bench] - fn bench_with_c_str_long(b: &mut Bencher) { - bench_with_c_str(b, S_LONG) - } - - fn bench_with_c_str_unchecked(b: &mut Bencher, s: &str) { - b.iter(|| { - unsafe { - s.with_c_str_unchecked(|c_str_buf| check(s, c_str_buf)) - } - }) - } - - #[bench] - fn bench_with_c_str_unchecked_short(b: &mut Bencher) { - bench_with_c_str_unchecked(b, S_SHORT) - } - - #[bench] - fn bench_with_c_str_unchecked_medium(b: &mut Bencher) { - bench_with_c_str_unchecked(b, S_MEDIUM) - } - - #[bench] - fn bench_with_c_str_unchecked_long(b: &mut Bencher) { - bench_with_c_str_unchecked(b, S_LONG) - } -} diff --git a/src/libstd/c_vec.rs b/src/libstd/c_vec.rs deleted file mode 100644 index 4a20208f31a6a..0000000000000 --- a/src/libstd/c_vec.rs +++ /dev/null @@ -1,232 +0,0 @@ -// Copyright 2012 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Library to interface with chunks of memory allocated in C. -//! -//! It is often desirable to safely interface with memory allocated from C, -//! encapsulating the unsafety into allocation and destruction time. Indeed, -//! allocating memory externally is currently the only way to give Rust shared -//! mut state with C programs that keep their own references; vectors are -//! unsuitable because they could be reallocated or moved at any time, and -//! importing C memory into a vector takes a one-time snapshot of the memory. -//! -//! This module simplifies the usage of such external blocks of memory. Memory -//! is encapsulated into an opaque object after creation; the lifecycle of the -//! memory can be optionally managed by Rust, if an appropriate destructor -//! closure is provided. Safety is ensured by bounds-checking accesses, which -//! are marshalled through get and set functions. -//! -//! There are three unsafe functions: the two constructors, and the -//! unwrap method. The constructors are unsafe for the -//! obvious reason (they act on a pointer that cannot be checked inside the -//! method), but `unwrap()` is somewhat more subtle in its unsafety. -//! It returns the contained pointer, but at the same time destroys the CVec -//! without running its destructor. This can be used to pass memory back to -//! C, but care must be taken that the ownership of underlying resources are -//! handled correctly, i.e. that allocated memory is eventually freed -//! if necessary. - -#![experimental] - -use kinds::Send; -use mem; -use ops::{Drop, FnOnce}; -use option::Option; -use option::Option::{Some, None}; -use ptr::PtrExt; -use ptr; -use raw; -use slice::AsSlice; -use thunk::{Thunk}; - -/// The type representing a foreign chunk of memory -pub struct CVec { - base: *mut T, - len: uint, - dtor: Option, -} - -#[unsafe_destructor] -impl Drop for CVec { - fn drop(&mut self) { - match self.dtor.take() { - None => (), - Some(f) => f.invoke(()) - } - } -} - -impl CVec { - /// Create a `CVec` from a raw pointer to a buffer with a given length. - /// - /// Panics if the given pointer is null. The returned vector will not attempt - /// to deallocate the vector when dropped. - /// - /// # Arguments - /// - /// * base - A raw pointer to a buffer - /// * len - The number of elements in the buffer - pub unsafe fn new(base: *mut T, len: uint) -> CVec { - assert!(base != ptr::null_mut()); - CVec { - base: base, - len: len, - dtor: None, - } - } - - /// Create a `CVec` from a foreign buffer, with a given length, - /// and a function to run upon destruction. - /// - /// Panics if the given pointer is null. - /// - /// # Arguments - /// - /// * base - A foreign pointer to a buffer - /// * len - The number of elements in the buffer - /// * dtor - A fn to run when the value is destructed, useful - /// for freeing the buffer, etc. - pub unsafe fn new_with_dtor(base: *mut T, - len: uint, - dtor: F) - -> CVec - where F : FnOnce(), F : Send - { - assert!(base != ptr::null_mut()); - let dtor: Thunk = Thunk::new(dtor); - CVec { - base: base, - len: len, - dtor: Some(dtor) - } - } - - /// View the stored data as a mutable slice. - pub fn as_mut_slice<'a>(&'a mut self) -> &'a mut [T] { - unsafe { - mem::transmute(raw::Slice { data: self.base as *const T, len: self.len }) - } - } - - /// Retrieves an element at a given index, returning `None` if the requested - /// index is greater than the length of the vector. - pub fn get<'a>(&'a self, ofs: uint) -> Option<&'a T> { - if ofs < self.len { - Some(unsafe { &*self.base.offset(ofs as int) }) - } else { - None - } - } - - /// Retrieves a mutable element at a given index, returning `None` if the - /// requested index is greater than the length of the vector. - pub fn get_mut<'a>(&'a mut self, ofs: uint) -> Option<&'a mut T> { - if ofs < self.len { - Some(unsafe { &mut *self.base.offset(ofs as int) }) - } else { - None - } - } - - /// Unwrap the pointer without running the destructor - /// - /// This method retrieves the underlying pointer, and in the process - /// destroys the CVec but without running the destructor. A use case - /// would be transferring ownership of the buffer to a C function, as - /// in this case you would not want to run the destructor. - /// - /// Note that if you want to access the underlying pointer without - /// cancelling the destructor, you can simply call `transmute` on the return - /// value of `get(0)`. - pub unsafe fn into_inner(mut self) -> *mut T { - self.dtor = None; - self.base - } - - /// Returns the number of items in this vector. - pub fn len(&self) -> uint { self.len } - - /// Returns whether this vector is empty. - pub fn is_empty(&self) -> bool { self.len() == 0 } -} - -impl AsSlice for CVec { - /// View the stored data as a slice. - fn as_slice<'a>(&'a self) -> &'a [T] { - unsafe { - mem::transmute(raw::Slice { data: self.base as *const T, len: self.len }) - } - } -} - -#[cfg(test)] -mod tests { - use prelude::v1::*; - - use super::CVec; - use libc; - use ptr; - - fn malloc(n: uint) -> CVec { - unsafe { - let mem = ptr::Unique(libc::malloc(n as libc::size_t)); - if mem.0.is_null() { ::alloc::oom() } - - CVec::new_with_dtor(mem.0 as *mut u8, - n, - move|| { libc::free(mem.0 as *mut libc::c_void); }) - } - } - - #[test] - fn test_basic() { - let mut cv = malloc(16); - - *cv.get_mut(3).unwrap() = 8; - *cv.get_mut(4).unwrap() = 9; - assert_eq!(*cv.get(3).unwrap(), 8); - assert_eq!(*cv.get(4).unwrap(), 9); - assert_eq!(cv.len(), 16); - } - - #[test] - #[should_fail] - fn test_panic_at_null() { - unsafe { - CVec::new(ptr::null_mut::(), 9); - } - } - - #[test] - fn test_overrun_get() { - let cv = malloc(16); - - assert!(cv.get(17).is_none()); - } - - #[test] - fn test_overrun_set() { - let mut cv = malloc(16); - - assert!(cv.get_mut(17).is_none()); - } - - #[test] - fn test_unwrap() { - unsafe { - let cv = CVec::new_with_dtor(1 as *mut int, - 0, - move|:| panic!("Don't run this destructor!")); - let p = cv.into_inner(); - assert_eq!(p, 1 as *mut int); - } - } - -} diff --git a/src/libstd/dynamic_lib.rs b/src/libstd/dynamic_lib.rs index de3d75ffb3242..66cb1f2c948d9 100644 --- a/src/libstd/dynamic_lib.rs +++ b/src/libstd/dynamic_lib.rs @@ -17,7 +17,7 @@ use prelude::v1::*; -use c_str::ToCStr; +use ffi::CString; use mem; use os; use str; @@ -51,13 +51,11 @@ impl DynamicLibrary { /// Lazily open a dynamic library. When passed None it gives a /// handle to the calling process - pub fn open(filename: Option) - -> Result { + pub fn open(filename: Option<&Path>) -> Result { unsafe { - let mut filename = filename; let maybe_library = dl::check_for_errors_in(|| { - match filename.take() { - Some(name) => dl::open_external(name), + match filename { + Some(name) => dl::open_external(name.as_vec()), None => dl::open_internal() } }); @@ -131,9 +129,8 @@ impl DynamicLibrary { // T but that feature is still unimplemented let maybe_symbol_value = dl::check_for_errors_in(|| { - symbol.with_c_str(|raw_string| { - dl::symbol(self.handle, raw_string) - }) + let raw_string = CString::from_slice(symbol.as_bytes()); + dl::symbol(self.handle, raw_string.as_ptr()) }); // The value must not be constructed if there is an error so @@ -157,7 +154,7 @@ mod test { fn test_loading_cosine() { // The math library does not need to be loaded since it is already // statically linked in - let none: Option = None; // appease the typechecker + let none: Option<&Path> = None; // appease the typechecker let libm = match DynamicLibrary::open(none) { Err(error) => panic!("Could not load self as module: {}", error), Ok(libm) => libm @@ -202,17 +199,17 @@ mod test { target_os = "freebsd", target_os = "dragonfly"))] pub mod dl { - use self::Rtld::*; - + pub use self::Rtld::*; use prelude::v1::*; - use c_str::{CString, ToCStr}; + + use ffi::{self, CString}; + use str; use libc; use ptr; - pub unsafe fn open_external(filename: T) -> *mut u8 { - filename.with_c_str(|raw_name| { - dlopen(raw_name, Lazy as libc::c_int) as *mut u8 - }) + pub unsafe fn open_external(filename: &[u8]) -> *mut u8 { + let s = CString::from_slice(filename); + dlopen(s.as_ptr(), Lazy as libc::c_int) as *mut u8 } pub unsafe fn open_internal() -> *mut u8 { @@ -236,8 +233,8 @@ pub mod dl { let ret = if ptr::null() == last_error { Ok(result) } else { - Err(String::from_str(CString::new(last_error, false).as_str() - .unwrap())) + let s = ffi::c_str_to_bytes(&last_error); + Err(str::from_utf8(s).unwrap().to_string()) }; ret @@ -273,7 +270,6 @@ pub mod dl { #[cfg(target_os = "windows")] pub mod dl { - use c_str::ToCStr; use iter::IteratorExt; use libc; use ops::FnOnce; @@ -287,10 +283,9 @@ pub mod dl { use string::String; use vec::Vec; - pub unsafe fn open_external(filename: T) -> *mut u8 { + pub unsafe fn open_external(filename: &[u8]) -> *mut u8 { // Windows expects Unicode data - let filename_cstr = filename.to_c_str(); - let filename_str = str::from_utf8(filename_cstr.as_bytes_no_nul()).unwrap(); + let filename_str = str::from_utf8(filename).unwrap(); let mut filename_str: Vec = filename_str.utf16_units().collect(); filename_str.push(0); LoadLibraryW(filename_str.as_ptr() as *const libc::c_void) as *mut u8 diff --git a/src/libstd/ffi/c_str.rs b/src/libstd/ffi/c_str.rs new file mode 100644 index 0000000000000..bef2344d9e8bc --- /dev/null +++ b/src/libstd/ffi/c_str.rs @@ -0,0 +1,218 @@ +// Copyright 2012 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use fmt; +use iter::IteratorExt; +use libc; +use mem; +use ops::Deref; +use slice::{self, SliceExt, AsSlice}; +use string::String; +use vec::Vec; + +/// A type representing a C-compatible string +/// +/// This type serves the primary purpose of being able to generate a +/// C-compatible string from a Rust byte slice or vector. An instance of this +/// type is a static guarantee that the underlying bytes contain no interior 0 +/// bytes and the final byte is 0. +/// +/// A `CString` is created from either a byte slice or a byte vector. After +/// being created, a `CString` predominately inherits all of its methods from +/// the `Deref` implementation to `[libc::c_char]`. Note that the underlying +/// array is represented as an array of `libc::c_char` as opposed to `u8`. A +/// `u8` slice can be obtained with the `as_bytes` method. Slices produced from +/// a `CString` do *not* contain the trailing nul terminator unless otherwise +/// specified. +/// +/// # Example +/// +/// ```no_run +/// # extern crate libc; +/// # fn main() { +/// use std::ffi::CString; +/// use libc; +/// +/// extern { +/// fn my_printer(s: *const libc::c_char); +/// } +/// +/// let to_print = "Hello, world!"; +/// let c_to_print = CString::from_slice(to_print.as_bytes()); +/// unsafe { +/// my_printer(c_to_print.as_ptr()); +/// } +/// # } +/// ``` +#[derive(Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] +pub struct CString { + inner: Vec, +} + +impl CString { + /// Create a new C-compatible string from a byte slice. + /// + /// This method will copy the data of the slice provided into a new + /// allocation, ensuring that there is a trailing 0 byte. + /// + /// # Panics + /// + /// This function will panic if there are any 0 bytes already in the slice + /// provided. + pub fn from_slice(v: &[u8]) -> CString { + CString::from_vec(v.to_vec()) + } + + /// Create a C-compatible string from a byte vector. + /// + /// This method will consume ownership of the provided vector, appending a 0 + /// byte to the end after verifying that there are no interior 0 bytes. + /// + /// # Panics + /// + /// This function will panic if there are any 0 bytes already in the vector + /// provided. + pub fn from_vec(v: Vec) -> CString { + assert!(!v.iter().any(|&x| x == 0)); + unsafe { CString::from_vec_unchecked(v) } + } + + /// Create a C-compatibel string from a byte vector without checking for + /// interior 0 bytes. + /// + /// This method is equivalent to `from_vec` except that no runtime assertion + /// is made that `v` contains no 0 bytes. + pub unsafe fn from_vec_unchecked(mut v: Vec) -> CString { + v.push(0); + CString { inner: mem::transmute(v) } + } + + /// Create a view into this C string which includes the trailing nul + /// terminator at the end of the string. + pub fn as_slice_with_nul(&self) -> &[libc::c_char] { self.inner.as_slice() } + + /// Similar to the `as_slice` method, but returns a `u8` slice instead of a + /// `libc::c_char` slice. + pub fn as_bytes(&self) -> &[u8] { + unsafe { mem::transmute(self.as_slice()) } + } + + /// Equivalend to `as_slice_with_nul` except that the type returned is a + /// `u8` slice instead of a `libc::c_char` slice. + pub fn as_bytes_with_nul(&self) -> &[u8] { + unsafe { mem::transmute(self.as_slice_with_nul()) } + } +} + +impl Deref for CString { + type Target = [libc::c_char]; + + fn deref(&self) -> &[libc::c_char] { + self.inner.slice_to(self.inner.len() - 1) + } +} + +impl fmt::Show for CString { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + String::from_utf8_lossy(self.as_bytes()).fmt(f) + } +} + +/// Interpret a C string as a byte slice. +/// +/// This function will calculate the length of the C string provided, and it +/// will then return a corresponding slice for the contents of the C string not +/// including the nul terminator. +/// +/// This function will tie the lifetime of the returned slice to the lifetime of +/// the pointer provided. This is done to help prevent the slice from escaping +/// the lifetime of the pointer itself. If a longer lifetime is needed, then +/// `mem::copy_lifetime` should be used. +/// +/// This function is unsafe because there is no guarantee of the validity of the +/// pointer `raw` or a guarantee that a nul terminator will be found. +/// +/// # Example +/// +/// ```no_run +/// # extern crate libc; +/// # fn main() { +/// use std::ffi; +/// use std::str; +/// use libc; +/// +/// extern { +/// fn my_string() -> *const libc::c_char; +/// } +/// +/// unsafe { +/// let to_print = my_string(); +/// let slice = ffi::c_str_to_bytes(&to_print); +/// println!("string returned: {}", str::from_utf8(slice).unwrap()); +/// } +/// # } +/// ``` +pub unsafe fn c_str_to_bytes<'a>(raw: &'a *const libc::c_char) -> &'a [u8] { + let len = libc::strlen(*raw); + slice::from_raw_buf(&*(raw as *const _ as *const *const u8), len as uint) +} + +/// Interpret a C string as a byte slice with the nul terminator. +/// +/// This function is identical to `from_raw_buf` except that the returned slice +/// will include the nul terminator of the string. +pub unsafe fn c_str_to_bytes_with_nul<'a>(raw: &'a *const libc::c_char) -> &'a [u8] { + let len = libc::strlen(*raw) + 1; + slice::from_raw_buf(&*(raw as *const _ as *const *const u8), len as uint) +} + +#[cfg(test)] +mod tests { + use prelude::v1::*; + use super::*; + use libc; + use mem; + + #[test] + fn c_to_rust() { + let data = b"123\0"; + let ptr = data.as_ptr() as *const libc::c_char; + unsafe { + assert_eq!(c_str_to_bytes(&ptr), b"123"); + assert_eq!(c_str_to_bytes_with_nul(&ptr), b"123\0"); + } + } + + #[test] + fn simple() { + let s = CString::from_slice(b"1234"); + assert_eq!(s.as_bytes(), b"1234"); + assert_eq!(s.as_bytes_with_nul(), b"1234\0"); + unsafe { + assert_eq!(s.as_slice(), + mem::transmute::<_, &[libc::c_char]>(b"1234")); + assert_eq!(s.as_slice_with_nul(), + mem::transmute::<_, &[libc::c_char]>(b"1234\0")); + } + } + + #[should_fail] #[test] + fn build_with_zero1() { CString::from_slice(b"\0"); } + #[should_fail] #[test] + fn build_with_zero2() { CString::from_vec(vec![0]); } + + #[test] + fn build_with_zero3() { + unsafe { + let s = CString::from_vec_unchecked(vec![0]); + assert_eq!(s.as_bytes(), b"\0"); + } + } +} diff --git a/src/libstd/ffi/mod.rs b/src/libstd/ffi/mod.rs new file mode 100644 index 0000000000000..cc86f804e3eb1 --- /dev/null +++ b/src/libstd/ffi/mod.rs @@ -0,0 +1,20 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Utilities related to FFI bindings. + +#![unstable = "module just underwent fairly large reorganization and the dust \ + still needs to settle"] + +pub use self::c_str::CString; +pub use self::c_str::c_str_to_bytes; +pub use self::c_str::c_str_to_bytes_with_nul; + +mod c_str; diff --git a/src/libstd/io/net/pipe.rs b/src/libstd/io/net/pipe.rs index daefdd28b306a..738c70412f78a 100644 --- a/src/libstd/io/net/pipe.rs +++ b/src/libstd/io/net/pipe.rs @@ -22,7 +22,8 @@ use prelude::v1::*; -use c_str::ToCStr; +use ffi::CString; +use path::BytesContainer; use io::{Listener, Acceptor, IoResult, TimedOut, standard_error}; use sys::pipe::UnixAcceptor as UnixAcceptorImp; use sys::pipe::UnixListener as UnixListenerImp; @@ -53,8 +54,9 @@ impl UnixStream { /// let mut stream = UnixStream::connect(&server); /// stream.write(&[1, 2, 3]); /// ``` - pub fn connect(path: &P) -> IoResult { - UnixStreamImp::connect(&path.to_c_str(), None) + pub fn connect(path: P) -> IoResult { + let path = CString::from_slice(path.container_as_bytes()); + UnixStreamImp::connect(&path, None) .map(|inner| UnixStream { inner: inner }) } @@ -67,13 +69,15 @@ impl UnixStream { /// If a `timeout` with zero or negative duration is specified then /// the function returns `Err`, with the error kind set to `TimedOut`. #[experimental = "the timeout argument is likely to change types"] - pub fn connect_timeout(path: &P, - timeout: Duration) -> IoResult { + pub fn connect_timeout

(path: P, timeout: Duration) + -> IoResult + where P: BytesContainer { if timeout <= Duration::milliseconds(0) { return Err(standard_error(TimedOut)); } - UnixStreamImp::connect(&path.to_c_str(), Some(timeout.num_milliseconds() as u64)) + let path = CString::from_slice(path.container_as_bytes()); + UnixStreamImp::connect(&path, Some(timeout.num_milliseconds() as u64)) .map(|inner| UnixStream { inner: inner }) } @@ -177,8 +181,9 @@ impl UnixListener { /// } /// # } /// ``` - pub fn bind(path: &P) -> IoResult { - UnixListenerImp::bind(&path.to_c_str()) + pub fn bind(path: P) -> IoResult { + let path = CString::from_slice(path.container_as_bytes()); + UnixListenerImp::bind(&path) .map(|inner| UnixListener { inner: inner }) } } diff --git a/src/libstd/io/process.rs b/src/libstd/io/process.rs index 5886c9cc3e287..ea232ad0c3f1b 100644 --- a/src/libstd/io/process.rs +++ b/src/libstd/io/process.rs @@ -18,8 +18,8 @@ pub use self::ProcessExit::*; use prelude::v1::*; -use c_str::{CString, ToCStr}; use collections::HashMap; +use ffi::CString; use fmt; use hash::Hash; use io::pipe::{PipeStream, PipePair}; @@ -35,6 +35,7 @@ use sys; use thread::Thread; #[cfg(windows)] use std::hash::sip::SipState; +#[cfg(windows)] use str; /// Signal a process to exit, without forcibly killing it. Corresponds to /// SIGTERM on unix platforms. @@ -109,11 +110,11 @@ struct EnvKey(CString); impl Hash for EnvKey { fn hash(&self, state: &mut SipState) { let &EnvKey(ref x) = self; - match x.as_str() { - Some(s) => for ch in s.chars() { + match str::from_utf8(x.as_bytes()) { + Ok(s) => for ch in s.chars() { (ch as u8 as char).to_lowercase().hash(state); }, - None => x.hash(state) + Err(..) => x.hash(state) } } } @@ -123,8 +124,8 @@ impl PartialEq for EnvKey { fn eq(&self, other: &EnvKey) -> bool { let &EnvKey(ref x) = self; let &EnvKey(ref y) = other; - match (x.as_str(), y.as_str()) { - (Some(xs), Some(ys)) => { + match (str::from_utf8(x.as_bytes()), str::from_utf8(y.as_bytes())) { + (Ok(xs), Ok(ys)) => { if xs.len() != ys.len() { return false } else { @@ -185,10 +186,10 @@ pub struct Command { } // FIXME (#12938): Until DST lands, we cannot decompose &str into & and str, so -// we cannot usefully take ToCStr arguments by reference (without forcing an +// we cannot usefully take BytesContainer arguments by reference (without forcing an // additional & around &str). So we are instead temporarily adding an instance -// for &Path, so that we can take ToCStr as owned. When DST lands, the &Path -// instance should be removed, and arguments bound by ToCStr should be passed by +// for &Path, so that we can take BytesContainer as owned. When DST lands, the &Path +// instance should be removed, and arguments bound by BytesContainer should be passed by // reference. (Here: {new, arg, args, env}.) impl Command { @@ -203,9 +204,9 @@ impl Command { /// /// Builder methods are provided to change these defaults and /// otherwise configure the process. - pub fn new(program: T) -> Command { + pub fn new(program: T) -> Command { Command { - program: program.to_c_str(), + program: CString::from_slice(program.container_as_bytes()), args: Vec::new(), env: None, cwd: None, @@ -219,27 +220,29 @@ impl Command { } /// Add an argument to pass to the program. - pub fn arg<'a, T: ToCStr>(&'a mut self, arg: T) -> &'a mut Command { - self.args.push(arg.to_c_str()); + pub fn arg<'a, T: BytesContainer>(&'a mut self, arg: T) -> &'a mut Command { + self.args.push(CString::from_slice(arg.container_as_bytes())); self } /// Add multiple arguments to pass to the program. - pub fn args<'a, T: ToCStr>(&'a mut self, args: &[T]) -> &'a mut Command { - self.args.extend(args.iter().map(|arg| arg.to_c_str()));; + pub fn args<'a, T: BytesContainer>(&'a mut self, args: &[T]) -> &'a mut Command { + self.args.extend(args.iter().map(|arg| { + CString::from_slice(arg.container_as_bytes()) + })); self } // Get a mutable borrow of the environment variable map for this `Command`. - fn get_env_map<'a>(&'a mut self) -> &'a mut EnvMap { + fn get_env_map<'a>(&'a mut self) -> &'a mut EnvMap { match self.env { Some(ref mut map) => map, None => { // if the env is currently just inheriting from the parent's, // materialize the parent's env into a hashtable. - self.env = Some(os::env_as_bytes().into_iter() - .map(|(k, v)| (EnvKey(k.to_c_str()), - v.to_c_str())) - .collect()); + self.env = Some(os::env_as_bytes().into_iter().map(|(k, v)| { + (EnvKey(CString::from_slice(k.as_slice())), + CString::from_slice(v.as_slice())) + }).collect()); self.env.as_mut().unwrap() } } @@ -249,15 +252,20 @@ impl Command { /// /// Note that environment variable names are case-insensitive (but case-preserving) on Windows, /// and case-sensitive on all other platforms. - pub fn env<'a, T: ToCStr, U: ToCStr>(&'a mut self, key: T, val: U) - -> &'a mut Command { - self.get_env_map().insert(EnvKey(key.to_c_str()), val.to_c_str()); + pub fn env<'a, T, U>(&'a mut self, key: T, val: U) + -> &'a mut Command + where T: BytesContainer, U: BytesContainer { + let key = EnvKey(CString::from_slice(key.container_as_bytes())); + let val = CString::from_slice(val.container_as_bytes()); + self.get_env_map().insert(key, val); self } /// Removes an environment variable mapping. - pub fn env_remove<'a, T: ToCStr>(&'a mut self, key: T) -> &'a mut Command { - self.get_env_map().remove(&EnvKey(key.to_c_str())); + pub fn env_remove<'a, T>(&'a mut self, key: T) -> &'a mut Command + where T: BytesContainer { + let key = EnvKey(CString::from_slice(key.container_as_bytes())); + self.get_env_map().remove(&key); self } @@ -265,16 +273,19 @@ impl Command { /// /// If the given slice contains multiple instances of an environment /// variable, the *rightmost* instance will determine the value. - pub fn env_set_all<'a, T: ToCStr, U: ToCStr>(&'a mut self, env: &[(T,U)]) - -> &'a mut Command { - self.env = Some(env.iter().map(|&(ref k, ref v)| (EnvKey(k.to_c_str()), v.to_c_str())) - .collect()); + pub fn env_set_all<'a, T, U>(&'a mut self, env: &[(T,U)]) + -> &'a mut Command + where T: BytesContainer, U: BytesContainer { + self.env = Some(env.iter().map(|&(ref k, ref v)| { + (EnvKey(CString::from_slice(k.container_as_bytes())), + CString::from_slice(v.container_as_bytes())) + }).collect()); self } /// Set the working directory for the child process. pub fn cwd<'a>(&'a mut self, dir: &Path) -> &'a mut Command { - self.cwd = Some(dir.to_c_str()); + self.cwd = Some(CString::from_slice(dir.as_vec())); self } @@ -389,9 +400,9 @@ impl fmt::Show for Command { /// non-utf8 data is lossily converted using the utf8 replacement /// character. fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - try!(write!(f, "{}", String::from_utf8_lossy(self.program.as_bytes_no_nul()))); + try!(write!(f, "{}", String::from_utf8_lossy(self.program.as_bytes()))); for arg in self.args.iter() { - try!(write!(f, " '{}'", String::from_utf8_lossy(arg.as_bytes_no_nul()))); + try!(write!(f, " '{}'", String::from_utf8_lossy(arg.as_bytes()))); } Ok(()) } @@ -1208,13 +1219,13 @@ mod tests { #[test] #[cfg(windows)] fn env_map_keys_ci() { - use c_str::ToCStr; + use ffi::CString; use super::EnvKey; let mut cmd = Command::new(""); cmd.env("path", "foo"); cmd.env("Path", "bar"); let env = &cmd.env.unwrap(); - let val = env.get(&EnvKey("PATH".to_c_str())); - assert!(val.unwrap() == &"bar".to_c_str()); + let val = env.get(&EnvKey(CString::from_slice(b"PATH"))); + assert!(val.unwrap() == &CString::from_slice(b"bar")); } } diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index 608ad9882b977..2d3a4639379cf 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -208,10 +208,10 @@ pub mod num; /* Runtime and platform support */ -pub mod thread_local; -pub mod c_str; -pub mod c_vec; +pub mod thread_local; // first for macros + pub mod dynamic_lib; +pub mod ffi; pub mod fmt; pub mod io; pub mod os; diff --git a/src/libstd/os.rs b/src/libstd/os.rs index be8f82349c222..300ceec4b45bf 100644 --- a/src/libstd/os.rs +++ b/src/libstd/os.rs @@ -57,12 +57,10 @@ use string::{String, ToString}; use sync::atomic::{AtomicInt, ATOMIC_INT_INIT, Ordering}; use vec::Vec; -#[cfg(unix)] use c_str::ToCStr; +#[cfg(unix)] use ffi::{self, CString}; -#[cfg(unix)] -pub use sys::ext as unix; -#[cfg(windows)] -pub use sys::ext as windows; +#[cfg(unix)] pub use sys::ext as unix; +#[cfg(windows)] pub use sys::ext as windows; /// Get the number of cores available pub fn num_cpus() -> uint { @@ -196,15 +194,14 @@ pub fn getenv(n: &str) -> Option { /// /// Panics if `n` has any interior NULs. pub fn getenv_as_bytes(n: &str) -> Option> { - use c_str::CString; - unsafe { with_env_lock(|| { - let s = n.with_c_str(|buf| libc::getenv(buf)); + let s = CString::from_slice(n.as_bytes()); + let s = libc::getenv(s.as_ptr()) as *const _; if s.is_null() { None } else { - Some(CString::new(s as *const libc::c_char, false).as_bytes_no_nul().to_vec()) + Some(ffi::c_str_to_bytes(&s).to_vec()) } }) } @@ -253,13 +250,12 @@ pub fn setenv(n: &str, v: T) { fn _setenv(n: &str, v: &[u8]) { unsafe { with_env_lock(|| { - n.with_c_str(|nbuf| { - v.with_c_str(|vbuf| { - if libc::funcs::posix01::unistd::setenv(nbuf, vbuf, 1) != 0 { - panic!(IoError::last_error()); - } - }) - }) + let k = CString::from_slice(n.as_bytes()); + let v = CString::from_slice(v); + if libc::funcs::posix01::unistd::setenv(k.as_ptr(), + v.as_ptr(), 1) != 0 { + panic!(IoError::last_error()); + } }) } } @@ -289,11 +285,10 @@ pub fn unsetenv(n: &str) { fn _unsetenv(n: &str) { unsafe { with_env_lock(|| { - n.with_c_str(|nbuf| { - if libc::funcs::posix01::unistd::unsetenv(nbuf) != 0 { - panic!(IoError::last_error()); - } - }) + let nbuf = CString::from_slice(n.as_bytes()); + if libc::funcs::posix01::unistd::unsetenv(nbuf.as_ptr()) != 0 { + panic!(IoError::last_error()); + } }) } } @@ -618,11 +613,10 @@ pub fn get_exit_status() -> int { #[cfg(target_os = "macos")] unsafe fn load_argc_and_argv(argc: int, argv: *const *const c_char) -> Vec> { - use c_str::CString; use iter::range; range(0, argc as uint).map(|i| { - CString::new(*argv.offset(i as int), false).as_bytes_no_nul().to_vec() + ffi::c_str_to_bytes(&*argv.offset(i as int)).to_vec() }).collect() } @@ -652,7 +646,6 @@ fn real_args_as_bytes() -> Vec> { // res #[cfg(target_os = "ios")] fn real_args_as_bytes() -> Vec> { - use c_str::CString; use iter::range; use mem; diff --git a/src/libstd/path/mod.rs b/src/libstd/path/mod.rs index bf9ffbffe7d50..a2d69a7e7dcea 100644 --- a/src/libstd/path/mod.rs +++ b/src/libstd/path/mod.rs @@ -62,7 +62,7 @@ #![experimental] use core::kinds::Sized; -use c_str::CString; +use ffi::CString; use clone::Clone; use fmt; use iter::IteratorExt; @@ -786,7 +786,7 @@ pub trait GenericPath: Clone + GenericPathUnsafe { } /// A trait that represents something bytes-like (e.g. a &[u8] or a &str) -pub trait BytesContainer for Sized? { +pub trait BytesContainer { /// Returns a &[u8] representing the receiver fn container_as_bytes<'a>(&'a self) -> &'a [u8]; /// Returns the receiver interpreted as a utf-8 string, if possible @@ -892,7 +892,7 @@ impl BytesContainer for Vec { impl BytesContainer for CString { #[inline] fn container_as_bytes<'a>(&'a self) -> &'a [u8] { - self.as_bytes_no_nul() + self.as_bytes() } } @@ -913,21 +913,3 @@ impl<'a, Sized? T: BytesContainer> BytesContainer for &'a T { fn contains_nul(v: &T) -> bool { v.container_as_bytes().iter().any(|&x| x == 0) } - -#[cfg(test)] -mod tests { - use prelude::v1::*; - use c_str::ToCStr; - use path::{WindowsPath, PosixPath}; - - #[test] - fn test_cstring() { - let input = "/foo/bar/baz"; - let path: PosixPath = PosixPath::new(input.to_c_str()); - assert_eq!(path.as_vec(), input.as_bytes()); - - let input = r"\foo\bar\baz"; - let path: WindowsPath = WindowsPath::new(input.to_c_str()); - assert_eq!(path.as_str().unwrap(), input); - } -} diff --git a/src/libstd/path/posix.rs b/src/libstd/path/posix.rs index ae82e201cb855..013212b27058c 100644 --- a/src/libstd/path/posix.rs +++ b/src/libstd/path/posix.rs @@ -10,19 +10,16 @@ //! POSIX file path handling -use c_str::{CString, ToCStr}; use clone::Clone; -use cmp::{PartialEq, Eq, PartialOrd, Ord, Ordering}; +use cmp::{Ordering, Eq, Ord, PartialEq, PartialOrd}; use hash; use io::Writer; use iter::{AdditiveIterator, Extend}; use iter::{Iterator, IteratorExt, Map}; -use option::Option; -use option::Option::{None, Some}; use kinds::Sized; -use str::{FromStr, Str}; -use str; -use slice::{Split, AsSlice, SliceConcatExt, SliceExt}; +use option::Option::{self, Some, None}; +use slice::{AsSlice, Split, SliceExt, SliceConcatExt}; +use str::{self, FromStr, StrExt}; use vec::Vec; use super::{BytesContainer, GenericPath, GenericPathUnsafe}; @@ -86,26 +83,6 @@ impl FromStr for Path { } } -// FIXME (#12938): Until DST lands, we cannot decompose &str into & and str, so -// we cannot usefully take ToCStr arguments by reference (without forcing an -// additional & around &str). So we are instead temporarily adding an instance -// for &Path, so that we can take ToCStr as owned. When DST lands, the &Path -// instance should be removed, and arguments bound by ToCStr should be passed by -// reference. - -impl ToCStr for Path { - #[inline] - fn to_c_str(&self) -> CString { - // The Path impl guarantees no internal NUL - unsafe { self.to_c_str_unchecked() } - } - - #[inline] - unsafe fn to_c_str_unchecked(&self) -> CString { - self.as_vec().to_c_str_unchecked() - } -} - impl hash::Hash for Path { #[inline] fn hash(&self, state: &mut S) { diff --git a/src/libstd/path/windows.rs b/src/libstd/path/windows.rs index cf8bc0e6242b3..05129a7ab9da3 100644 --- a/src/libstd/path/windows.rs +++ b/src/libstd/path/windows.rs @@ -15,17 +15,15 @@ use self::PathPrefix::*; use ascii::AsciiExt; -use c_str::{CString, ToCStr}; use char::CharExt; use clone::Clone; -use cmp::{PartialEq, Eq, PartialOrd, Ord, Ordering}; +use cmp::{Ordering, Eq, Ord, PartialEq, PartialOrd}; use hash; use io::Writer; use iter::{AdditiveIterator, Extend}; use iter::{Iterator, IteratorExt, Map, repeat}; use mem; -use option::Option; -use option::Option::{Some, None}; +use option::Option::{self, Some, None}; use slice::{SliceExt, SliceConcatExt}; use str::{SplitTerminator, FromStr, StrExt}; use string::{String, ToString}; @@ -112,26 +110,6 @@ impl FromStr for Path { } } -// FIXME (#12938): Until DST lands, we cannot decompose &str into & and str, so -// we cannot usefully take ToCStr arguments by reference (without forcing an -// additional & around &str). So we are instead temporarily adding an instance -// for &Path, so that we can take ToCStr as owned. When DST lands, the &Path -// instance should be removed, and arguments bound by ToCStr should be passed by -// reference. - -impl ToCStr for Path { - #[inline] - fn to_c_str(&self) -> CString { - // The Path impl guarantees no internal NUL - unsafe { self.to_c_str_unchecked() } - } - - #[inline] - unsafe fn to_c_str_unchecked(&self) -> CString { - self.as_vec().to_c_str_unchecked() - } -} - impl hash::Hash for Path { #[cfg(not(test))] #[inline] diff --git a/src/libstd/rt/args.rs b/src/libstd/rt/args.rs index 4734a39c83542..86abacb936501 100644 --- a/src/libstd/rt/args.rs +++ b/src/libstd/rt/args.rs @@ -46,8 +46,9 @@ pub fn clone() -> Option>> { imp::clone() } mod imp { use prelude::v1::*; + use libc; use mem; - use slice; + use ffi; use sync::{StaticMutex, MUTEX_INIT}; @@ -95,13 +96,9 @@ mod imp { } unsafe fn load_argc_and_argv(argc: int, argv: *const *const u8) -> Vec> { + let argv = argv as *const *const libc::c_char; range(0, argc as uint).map(|i| { - let arg = *argv.offset(i as int); - let mut len = 0u; - while *arg.offset(len as int) != 0 { - len += 1u; - } - slice::from_raw_buf(&arg, len).to_vec() + ffi::c_str_to_bytes(&*argv.offset(i as int)).to_vec() }).collect() } diff --git a/src/libstd/rt/backtrace.rs b/src/libstd/rt/backtrace.rs index 578239c9cc42e..bb0b6fe804bea 100644 --- a/src/libstd/rt/backtrace.rs +++ b/src/libstd/rt/backtrace.rs @@ -15,7 +15,7 @@ use prelude::v1::*; use os; -use sync::atomic::{mod, Ordering}; +use sync::atomic::{self, Ordering}; pub use sys::backtrace::write; diff --git a/src/libstd/rt/unwind.rs b/src/libstd/rt/unwind.rs index a48a8edd82f60..71169386c186a 100644 --- a/src/libstd/rt/unwind.rs +++ b/src/libstd/rt/unwind.rs @@ -67,7 +67,7 @@ use fmt; use intrinsics; use libc::c_void; use mem; -use sync::atomic::{mod, Ordering}; +use sync::atomic::{self, Ordering}; use sync::{Once, ONCE_INIT}; use rt::libunwind as uw; diff --git a/src/libstd/rt/util.rs b/src/libstd/rt/util.rs index 883a01fa31801..bc01ce926f8bc 100644 --- a/src/libstd/rt/util.rs +++ b/src/libstd/rt/util.rs @@ -19,7 +19,7 @@ use libc::{self, uintptr_t}; use os; use slice; use str; -use sync::atomic::{mod, Ordering}; +use sync::atomic::{self, Ordering}; /// Dynamically inquire about whether we're running under V. /// You should usually not use this unless your test definitely diff --git a/src/libstd/sys/common/mod.rs b/src/libstd/sys/common/mod.rs index a441e55a732b0..a31dcc9884f46 100644 --- a/src/libstd/sys/common/mod.rs +++ b/src/libstd/sys/common/mod.rs @@ -14,7 +14,7 @@ use io::{self, IoError, IoResult}; use prelude::v1::*; use sys::{last_error, retry}; -use c_str::CString; +use ffi::CString; use num::Int; use path::BytesContainer; use collections; diff --git a/src/libstd/sys/common/net.rs b/src/libstd/sys/common/net.rs index 3f67b284f6887..4cf891ac4985e 100644 --- a/src/libstd/sys/common/net.rs +++ b/src/libstd/sys/common/net.rs @@ -12,15 +12,16 @@ use prelude::v1::*; use self::SocketStatus::*; use self::InAddr::*; -use c_str::ToCStr; +use ffi::CString; +use ffi; use io::net::addrinfo; use io::net::ip::{SocketAddr, IpAddr, Ipv4Addr, Ipv6Addr}; use io::{IoResult, IoError}; use libc::{self, c_char, c_int}; -use c_str::CString; use mem; use num::Int; use ptr::{self, null, null_mut}; +use str; use sys::{self, retry, c, sock_t, last_error, last_net_error, last_gai_error, close_sock, wrlen, msglen_t, os, wouldblock, set_nonblocking, timer, ms_to_timeval, decode_error_detailed}; @@ -234,9 +235,9 @@ pub fn get_host_addresses(host: Option<&str>, servname: Option<&str>, assert!(host.is_some() || servname.is_some()); - let c_host = host.map(|x| x.to_c_str()); + let c_host = host.map(|x| CString::from_slice(x.as_bytes())); let c_host = c_host.as_ref().map(|x| x.as_ptr()).unwrap_or(null()); - let c_serv = servname.map(|x| x.to_c_str()); + let c_serv = servname.map(|x| CString::from_slice(x.as_bytes())); let c_serv = c_serv.as_ref().map(|x| x.as_ptr()).unwrap_or(null()); let hint = hint.map(|hint| { @@ -324,7 +325,8 @@ pub fn get_address_name(addr: IpAddr) -> Result { } unsafe { - Ok(CString::new(hostbuf.as_ptr(), false).as_str().unwrap().to_string()) + Ok(str::from_utf8(ffi::c_str_to_bytes(&hostbuf.as_ptr())) + .unwrap().to_string()) } } diff --git a/src/libstd/sys/unix/backtrace.rs b/src/libstd/sys/unix/backtrace.rs index 5b261ea6b9e58..ca268a8f27ff3 100644 --- a/src/libstd/sys/unix/backtrace.rs +++ b/src/libstd/sys/unix/backtrace.rs @@ -83,12 +83,13 @@ /// to symbols. This is a bit of a hokey implementation as-is, but it works for /// all unix platforms we support right now, so it at least gets the job done. -use c_str::CString; -use io::{IoResult, Writer}; +use prelude::v1::*; + +use ffi; +use io::IoResult; use libc; use mem; -use option::Option::{self, Some, None}; -use result::Result::{Ok, Err}; +use str; use sync::{StaticMutex, MUTEX_INIT}; use sys_common::backtrace::*; @@ -105,9 +106,7 @@ use sys_common::backtrace::*; #[cfg(all(target_os = "ios", target_arch = "arm"))] #[inline(never)] pub fn write(w: &mut Writer) -> IoResult<()> { - use iter::{IteratorExt, range}; use result; - use slice::SliceExt; extern { fn backtrace(buf: *mut *mut libc::c_void, @@ -234,19 +233,15 @@ fn print(w: &mut Writer, idx: int, addr: *mut libc::c_void) -> IoResult<()> { output(w, idx,addr, None) } else { output(w, idx, addr, Some(unsafe { - CString::new(info.dli_sname, false) + ffi::c_str_to_bytes(&info.dli_sname) })) } } #[cfg(not(any(target_os = "macos", target_os = "ios")))] fn print(w: &mut Writer, idx: int, addr: *mut libc::c_void) -> IoResult<()> { - use iter::{Iterator, IteratorExt}; use os; - use path::GenericPath; - use ptr::PtrExt; use ptr; - use slice::SliceExt; //////////////////////////////////////////////////////////////////////// // libbacktrace.h API @@ -368,15 +363,15 @@ fn print(w: &mut Writer, idx: int, addr: *mut libc::c_void) -> IoResult<()> { if ret == 0 || data.is_null() { output(w, idx, addr, None) } else { - output(w, idx, addr, Some(unsafe { CString::new(data, false) })) + output(w, idx, addr, Some(unsafe { ffi::c_str_to_bytes(&data) })) } } // Finally, after all that work above, we can emit a symbol. fn output(w: &mut Writer, idx: int, addr: *mut libc::c_void, - s: Option) -> IoResult<()> { + s: Option<&[u8]>) -> IoResult<()> { try!(write!(w, " {:2}: {:2$} - ", idx, addr, HEX_WIDTH)); - match s.as_ref().and_then(|c| c.as_str()) { + match s.and_then(|s| str::from_utf8(s).ok()) { Some(string) => try!(demangle(w, string)), None => try!(write!(w, "")), } diff --git a/src/libstd/sys/unix/fs.rs b/src/libstd/sys/unix/fs.rs index b49ace8e2f8d8..1ad775517bba7 100644 --- a/src/libstd/sys/unix/fs.rs +++ b/src/libstd/sys/unix/fs.rs @@ -12,7 +12,7 @@ use prelude::v1::*; -use c_str::{CString, ToCStr}; +use ffi::{self, CString}; use io::{FilePermission, Write, UnstableFileStat, Open, FileAccess, FileMode}; use io::{IoResult, FileStat, SeekStyle}; use io::{Read, Truncate, SeekCur, SeekSet, ReadWrite, SeekEnd, Append}; @@ -150,6 +150,10 @@ impl Drop for FileDesc { } } +fn cstr(path: &Path) -> CString { + CString::from_slice(path.as_vec()) +} + pub fn open(path: &Path, fm: FileMode, fa: FileAccess) -> IoResult { let flags = match fm { Open => 0, @@ -165,7 +169,7 @@ pub fn open(path: &Path, fm: FileMode, fa: FileAccess) -> IoResult { libc::S_IRUSR | libc::S_IWUSR), }; - let path = path.to_c_str(); + let path = cstr(path); match retry(|| unsafe { libc::open(path.as_ptr(), flags, mode) }) { -1 => Err(super::last_error()), fd => Ok(FileDesc::new(fd, true)), @@ -173,7 +177,7 @@ pub fn open(path: &Path, fm: FileMode, fa: FileAccess) -> IoResult { } pub fn mkdir(p: &Path, mode: uint) -> IoResult<()> { - let p = p.to_c_str(); + let p = cstr(p); mkerr_libc(unsafe { libc::mkdir(p.as_ptr(), mode as libc::mode_t) }) } @@ -182,7 +186,6 @@ pub fn readdir(p: &Path) -> IoResult> { use libc::{opendir, readdir_r, closedir}; fn prune(root: &CString, dirs: Vec) -> Vec { - let root = unsafe { CString::new(root.as_ptr(), false) }; let root = Path::new(root); dirs.into_iter().filter(|path| { @@ -199,7 +202,7 @@ pub fn readdir(p: &Path) -> IoResult> { let mut buf = Vec::::with_capacity(size as uint); let ptr = buf.as_mut_ptr() as *mut dirent_t; - let p = p.to_c_str(); + let p = CString::from_slice(p.as_vec()); let dir_ptr = unsafe {opendir(p.as_ptr())}; if dir_ptr as uint != 0 { @@ -207,10 +210,9 @@ pub fn readdir(p: &Path) -> IoResult> { let mut entry_ptr = 0 as *mut dirent_t; while unsafe { readdir_r(dir_ptr, ptr, &mut entry_ptr) == 0 } { if entry_ptr.is_null() { break } - let cstr = unsafe { - CString::new(rust_list_dir_val(entry_ptr), false) - }; - paths.push(Path::new(cstr)); + paths.push(unsafe { + Path::new(ffi::c_str_to_bytes(&rust_list_dir_val(entry_ptr))) + }); } assert_eq!(unsafe { closedir(dir_ptr) }, 0); Ok(prune(&p, paths)) @@ -220,39 +222,39 @@ pub fn readdir(p: &Path) -> IoResult> { } pub fn unlink(p: &Path) -> IoResult<()> { - let p = p.to_c_str(); + let p = cstr(p); mkerr_libc(unsafe { libc::unlink(p.as_ptr()) }) } pub fn rename(old: &Path, new: &Path) -> IoResult<()> { - let old = old.to_c_str(); - let new = new.to_c_str(); + let old = cstr(old); + let new = cstr(new); mkerr_libc(unsafe { libc::rename(old.as_ptr(), new.as_ptr()) }) } pub fn chmod(p: &Path, mode: uint) -> IoResult<()> { - let p = p.to_c_str(); + let p = cstr(p); mkerr_libc(retry(|| unsafe { libc::chmod(p.as_ptr(), mode as libc::mode_t) })) } pub fn rmdir(p: &Path) -> IoResult<()> { - let p = p.to_c_str(); + let p = cstr(p); mkerr_libc(unsafe { libc::rmdir(p.as_ptr()) }) } pub fn chown(p: &Path, uid: int, gid: int) -> IoResult<()> { - let p = p.to_c_str(); + let p = cstr(p); mkerr_libc(retry(|| unsafe { libc::chown(p.as_ptr(), uid as libc::uid_t, gid as libc::gid_t) })) } pub fn readlink(p: &Path) -> IoResult { - let c_path = p.to_c_str(); + let c_path = cstr(p); let p = c_path.as_ptr(); let mut len = unsafe { libc::pathconf(p as *mut _, libc::_PC_NAME_MAX) }; if len == -1 { @@ -273,14 +275,14 @@ pub fn readlink(p: &Path) -> IoResult { } pub fn symlink(src: &Path, dst: &Path) -> IoResult<()> { - let src = src.to_c_str(); - let dst = dst.to_c_str(); + let src = cstr(src); + let dst = cstr(dst); mkerr_libc(unsafe { libc::symlink(src.as_ptr(), dst.as_ptr()) }) } pub fn link(src: &Path, dst: &Path) -> IoResult<()> { - let src = src.to_c_str(); - let dst = dst.to_c_str(); + let src = cstr(src); + let dst = cstr(dst); mkerr_libc(unsafe { libc::link(src.as_ptr(), dst.as_ptr()) }) } @@ -328,7 +330,7 @@ fn mkstat(stat: &libc::stat) -> FileStat { } pub fn stat(p: &Path) -> IoResult { - let p = p.to_c_str(); + let p = cstr(p); let mut stat: libc::stat = unsafe { mem::zeroed() }; match unsafe { libc::stat(p.as_ptr(), &mut stat) } { 0 => Ok(mkstat(&stat)), @@ -337,7 +339,7 @@ pub fn stat(p: &Path) -> IoResult { } pub fn lstat(p: &Path) -> IoResult { - let p = p.to_c_str(); + let p = cstr(p); let mut stat: libc::stat = unsafe { mem::zeroed() }; match unsafe { libc::lstat(p.as_ptr(), &mut stat) } { 0 => Ok(mkstat(&stat)), @@ -346,7 +348,7 @@ pub fn lstat(p: &Path) -> IoResult { } pub fn utime(p: &Path, atime: u64, mtime: u64) -> IoResult<()> { - let p = p.to_c_str(); + let p = cstr(p); let buf = libc::utimbuf { actime: (atime / 1000) as libc::time_t, modtime: (mtime / 1000) as libc::time_t, diff --git a/src/libstd/sys/unix/mod.rs b/src/libstd/sys/unix/mod.rs index ea0d230e8b210..6a408aa60f0bf 100644 --- a/src/libstd/sys/unix/mod.rs +++ b/src/libstd/sys/unix/mod.rs @@ -15,12 +15,14 @@ #![allow(unused_unsafe)] #![allow(unused_mut)] -extern crate libc; - -use num; -use num::{Int, SignedInt}; use prelude::v1::*; + +use ffi; use io::{self, IoResult, IoError}; +use libc; +use num::{Int, SignedInt}; +use num; +use str; use sys_common::mkerr_libc; macro_rules! helper_init { (static $name:ident: Helper<$m:ty>) => ( @@ -78,11 +80,10 @@ extern "system" { } pub fn last_gai_error(s: libc::c_int) -> IoError { - use c_str::CString; let mut err = decode_error(s); err.detail = Some(unsafe { - CString::new(gai_strerror(s), false).as_str().unwrap().to_string() + str::from_utf8(ffi::c_str_to_bytes(&gai_strerror(s))).unwrap().to_string() }); err } diff --git a/src/libstd/sys/unix/os.rs b/src/libstd/sys/unix/os.rs index 181b8fdd0f8a1..175c4e2e353f9 100644 --- a/src/libstd/sys/unix/os.rs +++ b/src/libstd/sys/unix/os.rs @@ -12,18 +12,18 @@ use prelude::v1::*; -use c_str::ToCStr; use error::{FromError, Error}; +use ffi::{self, CString}; use fmt; use io::{IoError, IoResult}; use libc::{self, c_int, c_char, c_void}; +use os::TMPBUF_SZ; use os; use path::{BytesContainer}; use ptr; +use str; use sys::fs::FileDesc; -use os::TMPBUF_SZ; - const BUF_BYTES : uint = 2048u; /// Returns the platform-specific value of errno @@ -108,7 +108,8 @@ pub fn error_string(errno: i32) -> String { panic!("strerror_r failure"); } - String::from_raw_buf(p as *const u8) + let p = p as *const _; + str::from_utf8(ffi::c_str_to_bytes(&p)).unwrap().to_string() } } @@ -122,21 +123,17 @@ pub unsafe fn pipe() -> IoResult<(FileDesc, FileDesc)> { } pub fn getcwd() -> IoResult { - use c_str::CString; - let mut buf = [0 as c_char; BUF_BYTES]; unsafe { if libc::getcwd(buf.as_mut_ptr(), buf.len() as libc::size_t).is_null() { Err(IoError::last_error()) } else { - Ok(Path::new(CString::new(buf.as_ptr(), false))) + Ok(Path::new(ffi::c_str_to_bytes(&buf.as_ptr()))) } } } pub unsafe fn get_env_pairs() -> Vec> { - use c_str::CString; - extern { fn rust_env_pairs() -> *const *const c_char; } @@ -147,8 +144,7 @@ pub unsafe fn get_env_pairs() -> Vec> { } let mut result = Vec::new(); while *environ != 0 as *const _ { - let env_pair = - CString::new(*environ, false).as_bytes_no_nul().to_vec(); + let env_pair = ffi::c_str_to_bytes(&*environ).to_vec(); result.push(env_pair); environ = environ.offset(1); } @@ -234,14 +230,13 @@ pub fn load_self() -> Option> { } pub fn chdir(p: &Path) -> IoResult<()> { - p.with_c_str(|buf| { - unsafe { - match libc::chdir(buf) == (0 as c_int) { - true => Ok(()), - false => Err(IoError::last_error()), - } + let p = CString::from_slice(p.as_vec()); + unsafe { + match libc::chdir(p.as_ptr()) == (0 as c_int) { + true => Ok(()), + false => Err(IoError::last_error()), } - }) + } } pub fn page_size() -> uint { diff --git a/src/libstd/sys/unix/pipe.rs b/src/libstd/sys/unix/pipe.rs index 9063fbc2ba955..158a1ce220411 100644 --- a/src/libstd/sys/unix/pipe.rs +++ b/src/libstd/sys/unix/pipe.rs @@ -10,8 +10,8 @@ use prelude::v1::*; +use ffi::CString; use libc; -use c_str::CString; use mem; use sync::{Arc, Mutex}; use sync::atomic::{AtomicBool, Ordering}; @@ -48,7 +48,7 @@ fn addr_to_sockaddr_un(addr: &CString, } s.sun_family = libc::AF_UNIX as libc::sa_family_t; for (slot, value) in s.sun_path.iter_mut().zip(addr.iter()) { - *slot = value; + *slot = *value; } // count the null terminator diff --git a/src/libstd/sys/unix/process.rs b/src/libstd/sys/unix/process.rs index b73919fe2a2cc..5bc6b0c703b1c 100644 --- a/src/libstd/sys/unix/process.rs +++ b/src/libstd/sys/unix/process.rs @@ -11,8 +11,8 @@ use prelude::v1::*; use self::Req::*; -use c_str::{CString, ToCStr}; use collections; +use ffi::CString; use hash::Hash; use io::process::{ProcessExit, ExitStatus, ExitSignal}; use io::{self, IoResult, IoError, EndOfFile}; @@ -101,7 +101,7 @@ impl Process { // We may use this in the child, so perform allocations before the // fork - let devnull = "/dev/null".to_c_str(); + let devnull = b"/dev/null\0"; set_cloexec(output.fd()); @@ -204,7 +204,7 @@ impl Process { } else { libc::O_RDWR }; - libc::open(devnull.as_ptr(), flags, 0) + libc::open(devnull.as_ptr() as *const _, flags, 0) } Some(obj) => { let fd = obj.as_inner().fd(); diff --git a/src/libstd/sys/unix/timer.rs b/src/libstd/sys/unix/timer.rs index 11f29232a925d..62f3242a20625 100644 --- a/src/libstd/sys/unix/timer.rs +++ b/src/libstd/sys/unix/timer.rs @@ -54,7 +54,7 @@ use libc; use mem; use os; use ptr; -use sync::atomic::{mod, Ordering}; +use sync::atomic::{self, Ordering}; use sync::mpsc::{channel, Sender, Receiver, TryRecvError}; use sys::c; use sys::fs::FileDesc; diff --git a/src/libstd/sys/windows/backtrace.rs b/src/libstd/sys/windows/backtrace.rs index 319a458087b9b..4ccecfd1f5f2e 100644 --- a/src/libstd/sys/windows/backtrace.rs +++ b/src/libstd/sys/windows/backtrace.rs @@ -21,7 +21,8 @@ /// copy of that function in my mingw install (maybe it was broken?). Instead, /// this takes the route of using StackWalk64 in order to walk the stack. -use c_str::CString; +use dynamic_lib::DynamicLibrary; +use ffi; use intrinsics; use io::{IoResult, Writer}; use libc; @@ -30,10 +31,9 @@ use ops::Drop; use option::Option::{Some, None}; use path::Path; use result::Result::{Ok, Err}; -use sync::{StaticMutex, MUTEX_INIT}; use slice::SliceExt; -use str::StrExt; -use dynamic_lib::DynamicLibrary; +use str::{self, StrExt}; +use sync::{StaticMutex, MUTEX_INIT}; use sys_common::backtrace::*; @@ -357,11 +357,11 @@ pub fn write(w: &mut Writer) -> IoResult<()> { if ret == libc::TRUE { try!(write!(w, " - ")); - let cstr = unsafe { CString::new(info.Name.as_ptr(), false) }; - let bytes = cstr.as_bytes(); - match cstr.as_str() { - Some(s) => try!(demangle(w, s)), - None => try!(w.write(bytes[..bytes.len()-1])), + let ptr = info.Name.as_ptr() as *const libc::c_char; + let bytes = unsafe { ffi::c_str_to_bytes(&ptr) }; + match str::from_utf8(bytes) { + Ok(s) => try!(demangle(w, s)), + Err(..) => try!(w.write(bytes[..bytes.len()-1])), } } try!(w.write(&['\n' as u8])); diff --git a/src/libstd/sys/windows/c.rs b/src/libstd/sys/windows/c.rs index 1ee57434fb91a..945c2e8e7d156 100644 --- a/src/libstd/sys/windows/c.rs +++ b/src/libstd/sys/windows/c.rs @@ -133,7 +133,7 @@ pub mod compat { use intrinsics::{atomic_store_relaxed, transmute}; use libc::types::os::arch::extra::{LPCWSTR, HMODULE, LPCSTR, LPVOID}; use prelude::v1::*; - use c_str::ToCStr; + use ffi::CString; extern "system" { fn GetModuleHandleW(lpModuleName: LPCWSTR) -> HMODULE; @@ -147,14 +147,13 @@ pub mod compat { unsafe fn store_func(ptr: *mut uint, module: &str, symbol: &str, fallback: uint) { let mut module: Vec = module.utf16_units().collect(); module.push(0); - symbol.with_c_str(|symbol| { - let handle = GetModuleHandleW(module.as_ptr()); - let func: uint = transmute(GetProcAddress(handle, symbol)); - atomic_store_relaxed(ptr, if func == 0 { - fallback - } else { - func - }) + let symbol = CString::from_slice(symbol.as_bytes()); + let handle = GetModuleHandleW(module.as_ptr()); + let func: uint = transmute(GetProcAddress(handle, symbol.as_ptr())); + atomic_store_relaxed(ptr, if func == 0 { + fallback + } else { + func }) } diff --git a/src/libstd/sys/windows/fs.rs b/src/libstd/sys/windows/fs.rs index 9a94230065680..f8c75335b35dc 100644 --- a/src/libstd/sys/windows/fs.rs +++ b/src/libstd/sys/windows/fs.rs @@ -13,7 +13,6 @@ use alloc::arc::Arc; use libc::{self, c_int}; -use c_str::CString; use mem; use sys::os::fill_utf16_buf_and_decode; use path; diff --git a/src/libstd/sys/windows/pipe.rs b/src/libstd/sys/windows/pipe.rs index 9057515cad294..9996909f2f5bb 100644 --- a/src/libstd/sys/windows/pipe.rs +++ b/src/libstd/sys/windows/pipe.rs @@ -87,16 +87,21 @@ use prelude::v1::*; use libc; -use c_str::CString; +use ffi::CString; +use io::{self, IoError, IoResult}; use mem; use ptr; -use sync::{Arc, Mutex}; +use str; use sync::atomic::{AtomicBool, Ordering}; -use io::{self, IoError, IoResult}; +use sync::{Arc, Mutex}; use sys_common::{self, eof}; -use super::{c, os, timer, to_utf16, decode_error_detailed}; +use super::{c, os, timer, decode_error_detailed}; + +fn to_utf16(c: &CString) -> IoResult> { + super::to_utf16(str::from_utf8(c.as_bytes()).ok()) +} struct Event(libc::HANDLE); @@ -270,7 +275,7 @@ impl UnixStream { } pub fn connect(addr: &CString, timeout: Option) -> IoResult { - let addr = try!(to_utf16(addr.as_str())); + let addr = try!(to_utf16(addr)); let start = timer::now(); loop { match UnixStream::try_connect(addr.as_ptr()) { @@ -571,7 +576,7 @@ impl UnixListener { // Although we technically don't need the pipe until much later, we // create the initial handle up front to test the validity of the name // and such. - let addr_v = try!(to_utf16(addr.as_str())); + let addr_v = try!(to_utf16(addr)); let ret = unsafe { pipe(addr_v.as_ptr(), true) }; if ret == libc::INVALID_HANDLE_VALUE { Err(super::last_error()) @@ -661,7 +666,7 @@ impl UnixAcceptor { // proceed in accepting new clients in the future if self.inner.closed.load(Ordering::SeqCst) { return Err(eof()) } - let name = try!(to_utf16(self.listener.name.as_str())); + let name = try!(to_utf16(&self.listener.name)); // Once we've got a "server handle", we need to wait for a client to // connect. The ConnectNamedPipe function will block this thread until @@ -753,7 +758,7 @@ impl UnixAcceptor { impl Clone for UnixAcceptor { fn clone(&self) -> UnixAcceptor { - let name = to_utf16(self.listener.name.as_str()).ok().unwrap(); + let name = to_utf16(&self.listener.name).ok().unwrap(); UnixAcceptor { inner: self.inner.clone(), event: Event::new(true, false).ok().unwrap(), diff --git a/src/libstd/sys/windows/process.rs b/src/libstd/sys/windows/process.rs index 81e8f974a1223..9b3f2ca03736e 100644 --- a/src/libstd/sys/windows/process.rs +++ b/src/libstd/sys/windows/process.rs @@ -10,27 +10,26 @@ use prelude::v1::*; +use collections; +use ffi::CString; +use hash::Hash; +use io::fs::PathExtensions; +use io::process::{ProcessExit, ExitStatus, ExitSignal}; +use io::{IoResult, IoError}; +use io; use libc::{pid_t, c_void, c_int}; use libc; -use c_str::{CString, ToCStr}; -use io; use mem; use os; -use ptr; -use io::process::{ProcessExit, ExitStatus, ExitSignal}; -use collections; use path::BytesContainer; -use hash::Hash; -use io::{IoResult, IoError}; - +use ptr; +use str; +use sys::fs::FileDesc; use sys::fs; use sys::{self, retry, c, wouldblock, set_nonblocking, ms_to_timeval, timer}; -use sys::fs::FileDesc; use sys_common::helper_thread::Helper; use sys_common::{AsInner, mkerr_libc, timeout}; -use io::fs::PathExtensions; - pub use sys_common::ProcessConfig; /// A value representing a child process. @@ -142,10 +141,10 @@ impl Process { // Split the value and test each path to see if the // program exists. for path in os::split_paths(v.container_as_bytes()).into_iter() { - let path = path.join(cfg.program().as_bytes_no_nul()) + let path = path.join(cfg.program().as_bytes()) .with_extension(os::consts::EXE_EXTENSION); if path.exists() { - return Some(path.to_c_str()) + return Some(CString::from_slice(path.as_vec())) } } break @@ -363,11 +362,11 @@ fn zeroed_process_information() -> libc::types::os::arch::extra::PROCESS_INFORMA fn make_command_line(prog: &CString, args: &[CString]) -> String { let mut cmd = String::new(); - append_arg(&mut cmd, prog.as_str() + append_arg(&mut cmd, str::from_utf8(prog.as_bytes()).ok() .expect("expected program name to be utf-8 encoded")); for arg in args.iter() { cmd.push(' '); - append_arg(&mut cmd, arg.as_str() + append_arg(&mut cmd, str::from_utf8(arg.as_bytes()).ok() .expect("expected argument to be utf-8 encoded")); } return cmd; @@ -449,7 +448,7 @@ fn with_dirp(d: Option<&CString>, cb: F) -> T where { match d { Some(dir) => { - let dir_str = dir.as_str() + let dir_str = str::from_utf8(dir.as_bytes()).ok() .expect("expected workingdirectory to be utf-8 encoded"); let mut dir_str: Vec = dir_str.utf16_units().collect(); dir_str.push(0); diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 03b9eaf76b94f..a0fe4fb4a80cc 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -182,18 +182,34 @@ impl Name { /// A mark represents a unique id associated with a macro expansion pub type Mrk = u32; +#[cfg(stage0)] impl, E> Encodable for Ident { fn encode(&self, s: &mut S) -> Result<(), E> { s.emit_str(token::get_ident(*self).get()) } } +#[cfg(not(stage0))] +impl Encodable for Ident { + fn encode(&self, s: &mut S) -> Result<(), S::Error> { + s.emit_str(token::get_ident(*self).get()) + } +} + +#[cfg(stage0)] impl, E> Decodable for Ident { fn decode(d: &mut D) -> Result { Ok(str_to_ident(try!(d.read_str())[])) } } +#[cfg(not(stage0))] +impl Decodable for Ident { + fn decode(d: &mut D) -> Result { + Ok(str_to_ident(try!(d.read_str())[])) + } +} + /// Function name (not all functions have names) pub type FnIdent = Option; @@ -556,7 +572,7 @@ pub enum Pat_ { PatStruct(Path, Vec>, bool), PatTup(Vec>), PatBox(P), - PatRegion(P), // reference pattern + PatRegion(P, Mutability), // reference pattern PatLit(P), PatRange(P, P), /// [a, b, ..i, y, z] is represented as: @@ -1686,27 +1702,7 @@ mod test { // are ASTs encodable? #[test] fn check_asts_encodable() { - use std::io; - let e = Crate { - module: Mod { - inner: Span { - lo: BytePos(11), - hi: BytePos(19), - expn_id: NO_EXPANSION, - }, - view_items: Vec::new(), - items: Vec::new(), - }, - attrs: Vec::new(), - config: Vec::new(), - span: Span { - lo: BytePos(10), - hi: BytePos(20), - expn_id: NO_EXPANSION, - }, - exported_macros: Vec::new(), - }; - // doesn't matter which encoder we use.... - let _f = &e as &serialize::Encodable; + fn assert_encodable() {} + assert_encodable::(); } } diff --git a/src/libsyntax/ast_util.rs b/src/libsyntax/ast_util.rs index 4026da6cf8e47..5e03afec16cf8 100644 --- a/src/libsyntax/ast_util.rs +++ b/src/libsyntax/ast_util.rs @@ -633,7 +633,7 @@ pub fn walk_pat(pat: &Pat, mut it: F) -> bool where F: FnMut(&Pat) -> bool { PatEnum(_, Some(ref s)) | PatTup(ref s) => { s.iter().all(|p| walk_pat_(&**p, it)) } - PatBox(ref s) | PatRegion(ref s) => { + PatBox(ref s) | PatRegion(ref s, _) => { walk_pat_(&**s, it) } PatVec(ref before, ref slice, ref after) => { diff --git a/src/libsyntax/codemap.rs b/src/libsyntax/codemap.rs index 2c7bbcb6faf72..a49f2614cd787 100644 --- a/src/libsyntax/codemap.rs +++ b/src/libsyntax/codemap.rs @@ -120,6 +120,7 @@ impl PartialEq for Span { impl Eq for Span {} +#[cfg(stage0)] impl, E> Encodable for Span { /* Note #1972 -- spans are encoded but not decoded */ fn encode(&self, s: &mut S) -> Result<(), E> { @@ -127,12 +128,28 @@ impl, E> Encodable for Span { } } +#[cfg(not(stage0))] +impl Encodable for Span { + /* Note #1972 -- spans are encoded but not decoded */ + fn encode(&self, s: &mut S) -> Result<(), S::Error> { + s.emit_nil() + } +} + +#[cfg(stage0)] impl, E> Decodable for Span { fn decode(_d: &mut D) -> Result { Ok(DUMMY_SP) } } +#[cfg(not(stage0))] +impl Decodable for Span { + fn decode(_d: &mut D) -> Result { + Ok(DUMMY_SP) + } +} + pub fn spanned(lo: BytePos, hi: BytePos, t: T) -> Spanned { respan(mk_sp(lo, hi), t) } diff --git a/src/libsyntax/ext/deriving/decodable.rs b/src/libsyntax/ext/deriving/decodable.rs index 882136cb86259..c0631b8350b8c 100644 --- a/src/libsyntax/ext/deriving/decodable.rs +++ b/src/libsyntax/ext/deriving/decodable.rs @@ -52,27 +52,29 @@ fn expand_deriving_decodable_imp(cx: &mut ExtCtxt, let trait_def = TraitDef { span: span, attributes: Vec::new(), - path: Path::new_(vec!(krate, "Decodable"), None, - vec!(box Literal(Path::new_local("__D")), - box Literal(Path::new_local("__E"))), true), + path: Path::new_(vec!(krate, "Decodable"), None, vec!(), true), additional_bounds: Vec::new(), - generics: LifetimeBounds { - lifetimes: Vec::new(), - bounds: vec!(("__D", vec!(Path::new_( - vec!(krate, "Decoder"), None, - vec!(box Literal(Path::new_local("__E"))), true))), - ("__E", vec!())) - }, + generics: LifetimeBounds::empty(), methods: vec!( MethodDef { name: "decode", - generics: LifetimeBounds::empty(), + generics: LifetimeBounds { + lifetimes: Vec::new(), + bounds: vec!(("__D", vec!(Path::new_( + vec!(krate, "Decoder"), None, + vec!(), true)))) + }, explicit_self: None, args: vec!(Ptr(box Literal(Path::new_local("__D")), Borrowed(None, MutMutable))), - ret_ty: Literal(Path::new_(vec!("std", "result", "Result"), None, - vec!(box Self, - box Literal(Path::new_local("__E"))), true)), + ret_ty: Literal(Path::new_( + vec!("std", "result", "Result"), + None, + vec!(box Self, box Literal(Path::new_( + vec!["__D", "Error"], None, vec![], false + ))), + true + )), attributes: Vec::new(), combine_substructure: combine_substructure(|a, b, c| { decodable_substructure(a, b, c, krate) diff --git a/src/libsyntax/ext/deriving/encodable.rs b/src/libsyntax/ext/deriving/encodable.rs index b2c929123d586..4323d2979cc06 100644 --- a/src/libsyntax/ext/deriving/encodable.rs +++ b/src/libsyntax/ext/deriving/encodable.rs @@ -128,29 +128,29 @@ fn expand_deriving_encodable_imp(cx: &mut ExtCtxt, let trait_def = TraitDef { span: span, attributes: Vec::new(), - path: Path::new_(vec!(krate, "Encodable"), None, - vec!(box Literal(Path::new_local("__S")), - box Literal(Path::new_local("__E"))), true), + path: Path::new_(vec!(krate, "Encodable"), None, vec!(), true), additional_bounds: Vec::new(), - generics: LifetimeBounds { - lifetimes: Vec::new(), - bounds: vec!(("__S", vec!(Path::new_( - vec!(krate, "Encoder"), None, - vec!(box Literal(Path::new_local("__E"))), true))), - ("__E", vec!())) - }, + generics: LifetimeBounds::empty(), methods: vec!( MethodDef { name: "encode", - generics: LifetimeBounds::empty(), + generics: LifetimeBounds { + lifetimes: Vec::new(), + bounds: vec!(("__S", vec!(Path::new_( + vec!(krate, "Encoder"), None, + vec!(), true)))) + }, explicit_self: borrowed_explicit_self(), args: vec!(Ptr(box Literal(Path::new_local("__S")), Borrowed(None, MutMutable))), - ret_ty: Literal(Path::new_(vec!("std", "result", "Result"), - None, - vec!(box Tuple(Vec::new()), - box Literal(Path::new_local("__E"))), - true)), + ret_ty: Literal(Path::new_( + vec!("std", "result", "Result"), + None, + vec!(box Tuple(Vec::new()), box Literal(Path::new_( + vec!["__S", "Error"], None, vec![], false + ))), + true + )), attributes: Vec::new(), combine_substructure: combine_substructure(|a, b, c| { encodable_substructure(a, b, c) diff --git a/src/libsyntax/ext/deriving/generic/mod.rs b/src/libsyntax/ext/deriving/generic/mod.rs index 459abf15b33da..cedb9e094b4b9 100644 --- a/src/libsyntax/ext/deriving/generic/mod.rs +++ b/src/libsyntax/ext/deriving/generic/mod.rs @@ -941,7 +941,7 @@ impl<'a> MethodDef<'a> { &**variant, self_arg_name, ast::MutImmutable); - (cx.pat(sp, ast::PatRegion(p)), idents) + (cx.pat(sp, ast::PatRegion(p, ast::MutImmutable)), idents) }; // A single arm has form (&VariantK, &VariantK, ...) => BodyK diff --git a/src/libsyntax/ext/quote.rs b/src/libsyntax/ext/quote.rs index e46bd7ac4bc73..f1b52fa33c386 100644 --- a/src/libsyntax/ext/quote.rs +++ b/src/libsyntax/ext/quote.rs @@ -85,14 +85,14 @@ pub mod rt { */ // FIXME: Move this trait to pprust and get rid of *_to_str? - pub trait ToSource for Sized? { + pub trait ToSource { // Takes a thing and generates a string containing rust code for it. fn to_source(&self) -> String; } // FIXME (Issue #16472): This should go away after ToToken impls // are revised to go directly to token-trees. - trait ToSourceWithHygiene for Sized? : ToSource { + trait ToSourceWithHygiene : ToSource { // Takes a thing and generates a string containing rust code // for it, encoding Idents as special byte sequences to // maintain hygiene across serialization and deserialization. diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index 35b2e5dbc5381..b190ac78958c1 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -1268,7 +1268,7 @@ pub fn noop_fold_pat(p: P, folder: &mut T) -> P { } PatTup(elts) => PatTup(elts.move_map(|x| folder.fold_pat(x))), PatBox(inner) => PatBox(folder.fold_pat(inner)), - PatRegion(inner) => PatRegion(folder.fold_pat(inner)), + PatRegion(inner, mutbl) => PatRegion(folder.fold_pat(inner), mutbl), PatRange(e1, e2) => { PatRange(folder.fold_expr(e1), folder.fold_expr(e2)) }, diff --git a/src/libsyntax/owned_slice.rs b/src/libsyntax/owned_slice.rs index b87e2c6abbc0c..2a27431a0868c 100644 --- a/src/libsyntax/owned_slice.rs +++ b/src/libsyntax/owned_slice.rs @@ -82,12 +82,21 @@ impl FromIterator for OwnedSlice { } } +#[cfg(stage0)] impl, T: Encodable, E> Encodable for OwnedSlice { fn encode(&self, s: &mut S) -> Result<(), E> { self.as_slice().encode(s) } } +#[cfg(not(stage0))] +impl Encodable for OwnedSlice { + fn encode(&self, s: &mut S) -> Result<(), S::Error> { + self.as_slice().encode(s) + } +} + +#[cfg(stage0)] impl, T: Decodable, E> Decodable for OwnedSlice { fn decode(d: &mut D) -> Result, E> { Ok(OwnedSlice::from_vec(match Decodable::decode(d) { @@ -96,3 +105,13 @@ impl, T: Decodable, E> Decodable for OwnedSlice { })) } } + +#[cfg(not(stage0))] +impl Decodable for OwnedSlice { + fn decode(d: &mut D) -> Result, D::Error> { + Ok(OwnedSlice::from_vec(match Decodable::decode(d) { + Ok(t) => t, + Err(e) => return Err(e) + })) + } +} diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index cc67079e53879..a691474a5a916 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -2976,14 +2976,17 @@ impl<'a> Parser<'a> { /// actually, this seems to be the main entry point for /// parsing an arbitrary expression. pub fn parse_assign_expr(&mut self) -> P { - let lo = self.span.lo; let lhs = self.parse_binops(); + self.parse_assign_expr_with(lhs) + } + + pub fn parse_assign_expr_with(&mut self, lhs: P) -> P { let restrictions = self.restrictions & RESTRICTION_NO_STRUCT_LITERAL; match self.token { token::Eq => { self.bump(); let rhs = self.parse_expr_res(restrictions); - self.mk_expr(lo, rhs.span.hi, ExprAssign(lhs, rhs)) + self.mk_expr(lhs.span.lo, rhs.span.hi, ExprAssign(lhs, rhs)) } token::BinOpEq(op) => { self.bump(); @@ -3001,8 +3004,9 @@ impl<'a> Parser<'a> { token::Shr => BiShr }; let rhs_span = rhs.span; + let span = lhs.span; let assign_op = self.mk_assign_op(aop, lhs, rhs); - self.mk_expr(lo, rhs_span.hi, assign_op) + self.mk_expr(span.lo, rhs_span.hi, assign_op) } _ => { lhs @@ -3357,11 +3361,16 @@ impl<'a> Parser<'a> { }) } token::BinOp(token::And) | token::AndAnd => { - // parse &pat + // parse &pat and &mut pat let lo = self.span.lo; self.expect_and(); + let mutability = if self.eat_keyword(keywords::Mut) { + ast::MutMutable + } else { + ast::MutImmutable + }; let sub = self.parse_pat(); - pat = PatRegion(sub); + pat = PatRegion(sub, mutability); hi = self.last_span.hi; return P(ast::Pat { id: ast::DUMMY_NODE_ID, @@ -3896,8 +3905,9 @@ impl<'a> Parser<'a> { let e = self.mk_mac_expr(span.lo, span.hi, macro.and_then(|m| m.node)); - let e = - self.parse_dot_or_call_expr_with(e); + let e = self.parse_dot_or_call_expr_with(e); + let e = self.parse_more_binops(e, 0); + let e = self.parse_assign_expr_with(e); self.handle_expression_like_statement( e, ast::DUMMY_NODE_ID, @@ -4890,67 +4900,116 @@ impl<'a> Parser<'a> { self.span_err(ty.span, "`virtual` structs have been removed from the language"); } - self.parse_where_clause(&mut generics); + // There is a special case worth noting here, as reported in issue #17904. + // If we are parsing a tuple struct it is the case that the where clause + // should follow the field list. Like so: + // + // struct Foo(T) where T: Copy; + // + // If we are parsing a normal record-style struct it is the case + // that the where clause comes before the body, and after the generics. + // So if we look ahead and see a brace or a where-clause we begin + // parsing a record style struct. + // + // Otherwise if we look ahead and see a paren we parse a tuple-style + // struct. + + let (fields, ctor_id) = if self.token.is_keyword(keywords::Where) { + self.parse_where_clause(&mut generics); + if self.eat(&token::Semi) { + // If we see a: `struct Foo where T: Copy;` style decl. + (Vec::new(), Some(ast::DUMMY_NODE_ID)) + } else { + // If we see: `struct Foo where T: Copy { ... }` + (self.parse_record_struct_body(&class_name), None) + } + // No `where` so: `struct Foo;` + } else if self.eat(&token::Semi) { + (Vec::new(), Some(ast::DUMMY_NODE_ID)) + // Record-style struct definition + } else if self.token == token::OpenDelim(token::Brace) { + let fields = self.parse_record_struct_body(&class_name); + (fields, None) + // Tuple-style struct definition with optional where-clause. + } else { + let fields = self.parse_tuple_struct_body(&class_name, &mut generics); + (fields, Some(ast::DUMMY_NODE_ID)) + }; - let mut fields: Vec; - let is_tuple_like; + (class_name, + ItemStruct(P(ast::StructDef { + fields: fields, + ctor_id: ctor_id, + }), generics), + None) + } + pub fn parse_record_struct_body(&mut self, class_name: &ast::Ident) -> Vec { + let mut fields = Vec::new(); if self.eat(&token::OpenDelim(token::Brace)) { - // It's a record-like struct. - is_tuple_like = false; - fields = Vec::new(); while self.token != token::CloseDelim(token::Brace) { fields.push(self.parse_struct_decl_field(true)); } + if fields.len() == 0 { self.fatal(format!("unit-like struct definition should be \ - written as `struct {};`", - token::get_ident(class_name))[]); + written as `struct {};`", + token::get_ident(class_name.clone()))[]); } + self.bump(); - } else if self.check(&token::OpenDelim(token::Paren)) { - // It's a tuple-like struct. - is_tuple_like = true; - fields = self.parse_unspanned_seq( + } else { + let token_str = self.this_token_to_string(); + self.fatal(format!("expected `where`, or `{}` after struct \ + name, found `{}`", "{", + token_str)[]); + } + + fields + } + + pub fn parse_tuple_struct_body(&mut self, + class_name: &ast::Ident, + generics: &mut ast::Generics) + -> Vec { + // This is the case where we find `struct Foo(T) where T: Copy;` + if self.check(&token::OpenDelim(token::Paren)) { + let fields = self.parse_unspanned_seq( &token::OpenDelim(token::Paren), &token::CloseDelim(token::Paren), seq_sep_trailing_allowed(token::Comma), |p| { - let attrs = p.parse_outer_attributes(); - let lo = p.span.lo; - let struct_field_ = ast::StructField_ { - kind: UnnamedField(p.parse_visibility()), - id: ast::DUMMY_NODE_ID, - ty: p.parse_ty_sum(), - attrs: attrs, - }; - spanned(lo, p.span.hi, struct_field_) - }); + let attrs = p.parse_outer_attributes(); + let lo = p.span.lo; + let struct_field_ = ast::StructField_ { + kind: UnnamedField(p.parse_visibility()), + id: ast::DUMMY_NODE_ID, + ty: p.parse_ty_sum(), + attrs: attrs, + }; + spanned(lo, p.span.hi, struct_field_) + }); + if fields.len() == 0 { self.fatal(format!("unit-like struct definition should be \ - written as `struct {};`", - token::get_ident(class_name))[]); + written as `struct {};`", + token::get_ident(class_name.clone()))[]); } + + self.parse_where_clause(generics); self.expect(&token::Semi); - } else if self.eat(&token::Semi) { - // It's a unit-like struct. - is_tuple_like = true; - fields = Vec::new(); + fields + // This is the case where we just see struct Foo where T: Copy; + } else if self.token.is_keyword(keywords::Where) { + self.parse_where_clause(generics); + self.expect(&token::Semi); + Vec::new() + // This case is where we see: `struct Foo;` } else { let token_str = self.this_token_to_string(); - self.fatal(format!("expected `{}`, `(`, or `;` after struct \ - name, found `{}`", "{", - token_str)[]) + self.fatal(format!("expected `where`, `{}`, `(`, or `;` after struct \ + name, found `{}`", "{", token_str)[]); } - - let _ = ast::DUMMY_NODE_ID; // FIXME: Workaround for crazy bug. - let new_id = ast::DUMMY_NODE_ID; - (class_name, - ItemStruct(P(ast::StructDef { - fields: fields, - ctor_id: if is_tuple_like { Some(new_id) } else { None }, - }), generics), - None) } /// Parse a structure field declaration diff --git a/src/libsyntax/parse/token.rs b/src/libsyntax/parse/token.rs index 4bfcc94a083d4..b7e89b32b709e 100644 --- a/src/libsyntax/parse/token.rs +++ b/src/libsyntax/parse/token.rs @@ -653,6 +653,7 @@ impl<'a> PartialEq for &'a str { } } +#[cfg(stage0)] impl, E> Decodable for InternedString { fn decode(d: &mut D) -> Result { Ok(get_name(get_ident_interner().intern( @@ -660,12 +661,28 @@ impl, E> Decodable for InternedString { } } +#[cfg(not(stage0))] +impl Decodable for InternedString { + fn decode(d: &mut D) -> Result { + Ok(get_name(get_ident_interner().intern( + try!(d.read_str())[]))) + } +} + +#[cfg(stage0)] impl, E> Encodable for InternedString { fn encode(&self, s: &mut S) -> Result<(), E> { s.emit_str(self.string[]) } } +#[cfg(not(stage0))] +impl Encodable for InternedString { + fn encode(&self, s: &mut S) -> Result<(), S::Error> { + s.emit_str(self.string[]) + } +} + /// Returns the string contents of a name, using the task-local interner. #[inline] pub fn get_name(name: ast::Name) -> InternedString { diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index 61b7aa408a8d5..6cc5864be9ca3 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -2100,8 +2100,11 @@ impl<'a> State<'a> { try!(word(&mut self.s, "box ")); try!(self.print_pat(&**inner)); } - ast::PatRegion(ref inner) => { + ast::PatRegion(ref inner, mutbl) => { try!(word(&mut self.s, "&")); + if mutbl == ast::MutMutable { + try!(word(&mut self.s, "mut ")); + } try!(self.print_pat(&**inner)); } ast::PatLit(ref e) => try!(self.print_expr(&**e)), diff --git a/src/libsyntax/ptr.rs b/src/libsyntax/ptr.rs index 6eee1d903ea64..13eda7bb88f05 100644 --- a/src/libsyntax/ptr.rs +++ b/src/libsyntax/ptr.rs @@ -111,14 +111,30 @@ impl> Hash for P { } } +#[cfg(stage0)] impl, T: 'static + Decodable> Decodable for P { fn decode(d: &mut D) -> Result, E> { Decodable::decode(d).map(P) } } +#[cfg(not(stage0))] +impl Decodable for P { + fn decode(d: &mut D) -> Result, D::Error> { + Decodable::decode(d).map(P) + } +} + +#[cfg(stage0)] impl, T: Encodable> Encodable for P { fn encode(&self, s: &mut S) -> Result<(), E> { (**self).encode(s) } } + +#[cfg(not(stage0))] +impl Encodable for P { + fn encode(&self, s: &mut S) -> Result<(), S::Error> { + (**self).encode(s) + } +} diff --git a/src/libsyntax/show_span.rs b/src/libsyntax/show_span.rs index 354ba854b101a..51d655ec0f2c5 100644 --- a/src/libsyntax/show_span.rs +++ b/src/libsyntax/show_span.rs @@ -13,27 +13,73 @@ //! This module shows spans for all expressions in the crate //! to help with compiler debugging. +use std::str::FromStr; + use ast; use diagnostic; use visit; use visit::Visitor; +enum Mode { + Expression, + Pattern, + Type, +} + +impl FromStr for Mode { + fn from_str(s: &str) -> Option { + let mode = match s { + "expr" => Mode::Expression, + "pat" => Mode::Pattern, + "ty" => Mode::Type, + _ => return None + }; + Some(mode) + } +} + struct ShowSpanVisitor<'a> { span_diagnostic: &'a diagnostic::SpanHandler, + mode: Mode, } impl<'a, 'v> Visitor<'v> for ShowSpanVisitor<'a> { fn visit_expr(&mut self, e: &ast::Expr) { - self.span_diagnostic.span_note(e.span, "expression"); + if let Mode::Expression = self.mode { + self.span_diagnostic.span_note(e.span, "expression"); + } visit::walk_expr(self, e); } + fn visit_pat(&mut self, p: &ast::Pat) { + if let Mode::Pattern = self.mode { + self.span_diagnostic.span_note(p.span, "pattern"); + } + visit::walk_pat(self, p); + } + + fn visit_ty(&mut self, t: &ast::Ty) { + if let Mode::Type = self.mode { + self.span_diagnostic.span_note(t.span, "type"); + } + visit::walk_ty(self, t); + } + fn visit_mac(&mut self, macro: &ast::Mac) { visit::walk_mac(self, macro); } } -pub fn run(span_diagnostic: &diagnostic::SpanHandler, krate: &ast::Crate) { - let mut v = ShowSpanVisitor { span_diagnostic: span_diagnostic }; +pub fn run(span_diagnostic: &diagnostic::SpanHandler, + mode: &str, + krate: &ast::Crate) { + let mode = match mode.parse() { + Some(mode) => mode, + None => return + }; + let mut v = ShowSpanVisitor { + span_diagnostic: span_diagnostic, + mode: mode, + }; visit::walk_crate(&mut v, krate); } diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index 054a288a69e6d..a7a93ccc0683d 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -519,7 +519,7 @@ pub fn walk_pat<'v, V: Visitor<'v>>(visitor: &mut V, pattern: &'v Pat) { } } PatBox(ref subpattern) | - PatRegion(ref subpattern) => { + PatRegion(ref subpattern, _) => { visitor.visit_pat(&**subpattern) } PatIdent(_, ref pth1, ref optional_subpattern) => { diff --git a/src/libtest/lib.rs b/src/libtest/lib.rs index 3fb2211eff23a..45c9dd3e9f2e3 100644 --- a/src/libtest/lib.rs +++ b/src/libtest/lib.rs @@ -1332,10 +1332,11 @@ impl MetricMap { /// elimination. /// /// This function is a no-op, and does not even read from `dummy`. -pub fn black_box(dummy: T) { +pub fn black_box(dummy: T) -> T { // we need to "use" the argument in some way LLVM can't // introspect. unsafe {asm!("" : : "r"(&dummy))} + dummy } diff --git a/src/libtest/stats.rs b/src/libtest/stats.rs index 7e7f36f6e83fa..8daabf6101022 100644 --- a/src/libtest/stats.rs +++ b/src/libtest/stats.rs @@ -39,7 +39,7 @@ fn local_sort(v: &mut [T]) { } /// Trait that provides simple descriptive statistics on a univariate set of numeric samples. -pub trait Stats for Sized? { +pub trait Stats { /// Sum of the samples. /// @@ -169,7 +169,8 @@ impl Stats for [T] { fn sum(&self) -> T { let mut partials = vec![]; - for &mut x in self.iter() { + for &x in self.iter() { + let mut x = x; let mut j = 0; // This inner loop applies `hi`/`lo` summation to each // partial so that the list of partial sums remains exact. diff --git a/src/libunicode/u_str.rs b/src/libunicode/u_str.rs index 90949437774f1..13672a7b480af 100644 --- a/src/libunicode/u_str.rs +++ b/src/libunicode/u_str.rs @@ -37,7 +37,7 @@ pub struct Words<'a> { /// Methods for Unicode string slices #[allow(missing_docs)] // docs in libcollections -pub trait UnicodeStr for Sized? { +pub trait UnicodeStr { fn graphemes<'a>(&'a self, is_extended: bool) -> Graphemes<'a>; fn grapheme_indices<'a>(&'a self, is_extended: bool) -> GraphemeIndices<'a>; fn words<'a>(&'a self) -> Words<'a>; diff --git a/src/rust-installer b/src/rust-installer index 3a37981744a5a..b5ac4cd44321d 160000 --- a/src/rust-installer +++ b/src/rust-installer @@ -1 +1 @@ -Subproject commit 3a37981744a5af2433fed551f742465c78c9af7f +Subproject commit b5ac4cd44321da10dfd70f070dbc9094ca3f92ff diff --git a/src/test/auxiliary/lang-item-public.rs b/src/test/auxiliary/lang-item-public.rs index e6bae4628874c..e99a8f0b87737 100644 --- a/src/test/auxiliary/lang-item-public.rs +++ b/src/test/auxiliary/lang-item-public.rs @@ -12,7 +12,7 @@ #![feature(lang_items)] #[lang="sized"] -pub trait Sized for Sized? {} +pub trait Sized {} #[lang="panic"] fn panic(_: &(&'static str, &'static str, uint)) -> ! { loop {} } diff --git a/src/test/auxiliary/linkage-visibility.rs b/src/test/auxiliary/linkage-visibility.rs index 0b4bea49fa249..6cd94ee5602aa 100644 --- a/src/test/auxiliary/linkage-visibility.rs +++ b/src/test/auxiliary/linkage-visibility.rs @@ -27,7 +27,7 @@ fn bar() { } fn baz() { } pub fn test() { - let none: Option = None; // appease the typechecker + let none: Option<&Path> = None; // appease the typechecker let lib = DynamicLibrary::open(none).unwrap(); unsafe { assert!(lib.symbol::("foo").is_ok()); diff --git a/src/test/bench/rt-messaging-ping-pong.rs b/src/test/bench/rt-messaging-ping-pong.rs index adf773a2f252c..5ecc580de08d5 100644 --- a/src/test/bench/rt-messaging-ping-pong.rs +++ b/src/test/bench/rt-messaging-ping-pong.rs @@ -35,21 +35,24 @@ fn ping_pong_bench(n: uint, m: uint) { // Create a channel: B->A let (btx, brx) = channel(); - Thread::spawn(move|| { + let guard_a = Thread::spawn(move|| { let (tx, rx) = (atx, brx); for _ in range(0, n) { tx.send(()).unwrap(); rx.recv().unwrap(); } - }).detach(); + }); - Thread::spawn(move|| { + let guard_b = Thread::spawn(move|| { let (tx, rx) = (btx, arx); for _ in range(0, n) { rx.recv().unwrap(); tx.send(()).unwrap(); } - }).detach(); + }); + + guard_a.join().ok(); + guard_b.join().ok(); } for _ in range(0, m) { diff --git a/src/test/compile-fail/associated-types-ICE-when-projecting-out-of-err.rs b/src/test/compile-fail/associated-types-ICE-when-projecting-out-of-err.rs index 5743216b6ca69..6265392663dec 100644 --- a/src/test/compile-fail/associated-types-ICE-when-projecting-out-of-err.rs +++ b/src/test/compile-fail/associated-types-ICE-when-projecting-out-of-err.rs @@ -16,7 +16,7 @@ #![no_std] #[lang="sized"] -pub trait Sized for Sized? { +pub trait Sized { // Empty. } diff --git a/src/test/compile-fail/dst-object-from-unsized-type.rs b/src/test/compile-fail/dst-object-from-unsized-type.rs index 99c63c3c6e95e..4e5a6be1bc7c6 100644 --- a/src/test/compile-fail/dst-object-from-unsized-type.rs +++ b/src/test/compile-fail/dst-object-from-unsized-type.rs @@ -10,7 +10,7 @@ // Test that we cannot create objects from unsized types. -trait Foo for Sized? {} +trait Foo {} impl Foo for str {} fn test1(t: &T) { diff --git a/src/test/compile-fail/issue-17904.rs b/src/test/compile-fail/issue-17904.rs new file mode 100644 index 0000000000000..87bb0623c6ed0 --- /dev/null +++ b/src/test/compile-fail/issue-17904.rs @@ -0,0 +1,17 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +struct Baz where U: Eq(U); // This is parsed as the new Fn* style parenthesis syntax. +struct Baz where U: Eq(U) -> R; // Notice this parses as well. +struct Baz(U) where U: Eq; // This rightfully signals no error as well. +struct Foo where T: Copy, (T); //~ ERROR: unexpected token in `where` clause +struct Bar { x: T } where T: Copy //~ ERROR: expected item, found `where` + +fn main() {} diff --git a/src/test/compile-fail/issue-18959.rs b/src/test/compile-fail/issue-18959.rs index 1a792eb6e76ae..7aba1bc8e65c7 100644 --- a/src/test/compile-fail/issue-18959.rs +++ b/src/test/compile-fail/issue-18959.rs @@ -8,8 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -pub trait Foo for Sized? { fn foo(&self, ext_thing: &T); } -pub trait Bar for Sized?: Foo { } +pub trait Foo { fn foo(&self, ext_thing: &T); } +pub trait Bar: Foo { } impl Bar for T { } pub struct Thing; diff --git a/src/test/compile-fail/issue-19009.rs b/src/test/compile-fail/issue-19009.rs index aa7c4c3060bdb..3c1853b9990a7 100644 --- a/src/test/compile-fail/issue-19009.rs +++ b/src/test/compile-fail/issue-19009.rs @@ -11,7 +11,7 @@ #![feature(lang_items)] #![no_std] #![crate_type="rlib"] -#[lang="sized"] pub trait Sized for Sized? {} +#[lang="sized"] pub trait Sized {} fn ice(f: for <'s> || :'s //~ ERROR use of undeclared lifetime name `'s` diff --git a/src/test/compile-fail/lint-raw-ptr-deriving.rs b/src/test/compile-fail/lint-raw-ptr-derive.rs similarity index 97% rename from src/test/compile-fail/lint-raw-ptr-deriving.rs rename to src/test/compile-fail/lint-raw-ptr-derive.rs index 6fe8862d77e58..3198e782df893 100644 --- a/src/test/compile-fail/lint-raw-ptr-deriving.rs +++ b/src/test/compile-fail/lint-raw-ptr-derive.rs @@ -9,7 +9,7 @@ // except according to those terms. #![allow(dead_code)] -#![deny(raw_pointer_deriving)] +#![deny(raw_pointer_derive)] #[derive(Clone)] struct Foo { diff --git a/src/test/compile-fail/macros-no-semicolon.rs b/src/test/compile-fail/macros-no-semicolon.rs index fd5f5866f0940..0e85551e2161c 100644 --- a/src/test/compile-fail/macros-no-semicolon.rs +++ b/src/test/compile-fail/macros-no-semicolon.rs @@ -10,7 +10,7 @@ fn main() { assert!(1 == 2) - assert!(3 == 4) //~ ERROR expected one of `.`, `;`, or `}`, found `assert` + assert!(3 == 4) //~ ERROR expected one of `.`, `;`, `}`, or an operator, found `assert` println!("hello"); } diff --git a/src/test/compile-fail/mut-pattern-internal-mutability.rs b/src/test/compile-fail/mut-pattern-internal-mutability.rs new file mode 100644 index 0000000000000..05c6c4a96557c --- /dev/null +++ b/src/test/compile-fail/mut-pattern-internal-mutability.rs @@ -0,0 +1,24 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn main() { + let foo = &mut 1i; + + let &mut x = foo; + x += 1; //~ ERROR re-assignment of immutable variable + + // explicitly mut-ify internals + let &mut mut x = foo; + x += 1; + + // check borrowing is detected successfully + let &mut ref x = foo; + *foo += 1; //~ ERROR cannot assign to `*foo` because it is borrowed +} diff --git a/src/test/compile-fail/mut-pattern-mismatched.rs b/src/test/compile-fail/mut-pattern-mismatched.rs new file mode 100644 index 0000000000000..74e6141a2b3ff --- /dev/null +++ b/src/test/compile-fail/mut-pattern-mismatched.rs @@ -0,0 +1,26 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn main() { + let foo = &mut 1i; + + // (separate lines to ensure the spans are accurate) + + // SNAP c894171 uncomment this after the next snapshot + // NOTE(stage0) just in case tidy doesn't check SNAP's in tests + // let &_ // ~ ERROR expected `&mut int`, found `&_` + // = foo; + let &mut _ = foo; + + let bar = &1i; + let &_ = bar; + let &mut _ //~ ERROR expected `&int`, found `&mut _` + = bar; +} diff --git a/src/test/compile-fail/privacy4.rs b/src/test/compile-fail/privacy4.rs index 70e7e2df98a69..3d8b3eda044d4 100644 --- a/src/test/compile-fail/privacy4.rs +++ b/src/test/compile-fail/privacy4.rs @@ -11,7 +11,7 @@ #![feature(globs, lang_items)] #![no_std] // makes debugging this test *a lot* easier (during resolve) -#[lang = "sized"] pub trait Sized for Sized? {} +#[lang = "sized"] pub trait Sized {} #[lang="copy"] pub trait Copy {} // Test to make sure that private items imported through globs remain private diff --git a/src/test/compile-fail/regions-pattern-typing-issue-19552.rs b/src/test/compile-fail/regions-pattern-typing-issue-19552.rs new file mode 100644 index 0000000000000..3f722c9433bb2 --- /dev/null +++ b/src/test/compile-fail/regions-pattern-typing-issue-19552.rs @@ -0,0 +1,18 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn assert_send(_t: T) {} + +fn main() { + let line = String::new(); + match [line.as_slice()] { //~ ERROR `line` does not live long enough + [ word ] => { assert_send(word); } + } +} diff --git a/src/test/compile-fail/regions-pattern-typing-issue-19997.rs b/src/test/compile-fail/regions-pattern-typing-issue-19997.rs new file mode 100644 index 0000000000000..da839d7217261 --- /dev/null +++ b/src/test/compile-fail/regions-pattern-typing-issue-19997.rs @@ -0,0 +1,20 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn main() { + let a0 = 0u8; + let f = 1u8; + let mut a1 = &a0; + match (&a1,) { + (&ref b0,) => { + a1 = &f; //~ ERROR cannot assign + } + } +} diff --git a/src/test/compile-fail/required-lang-item.rs b/src/test/compile-fail/required-lang-item.rs index dd11ec645b42e..ae561878e9ba0 100644 --- a/src/test/compile-fail/required-lang-item.rs +++ b/src/test/compile-fail/required-lang-item.rs @@ -11,7 +11,7 @@ #![feature(lang_items)] #![no_std] -#[lang="sized"] pub trait Sized for Sized? {} +#[lang="sized"] pub trait Sized {} // error-pattern:requires `start` lang_item diff --git a/src/test/compile-fail/unboxed-closure-sugar-default.rs b/src/test/compile-fail/unboxed-closure-sugar-default.rs index 06a934063927a..75f2a1744db15 100644 --- a/src/test/compile-fail/unboxed-closure-sugar-default.rs +++ b/src/test/compile-fail/unboxed-closure-sugar-default.rs @@ -18,7 +18,7 @@ trait Foo { fn dummy(&self, t: T, u: U, v: V); } -trait Eq for Sized? { } +trait Eq { } impl Eq for X { } fn eq() where A : Eq { } diff --git a/src/test/compile-fail/unboxed-closure-sugar-equiv.rs b/src/test/compile-fail/unboxed-closure-sugar-equiv.rs index 16d6b217872ae..2b2327277a2d1 100644 --- a/src/test/compile-fail/unboxed-closure-sugar-equiv.rs +++ b/src/test/compile-fail/unboxed-closure-sugar-equiv.rs @@ -20,7 +20,7 @@ trait Foo { fn dummy(&self, t: T, u: U); } -trait Eq for Sized? { } +trait Eq { } impl Eq for X { } fn eq>() { } diff --git a/src/test/compile-fail/unboxed-closure-sugar-lifetime-elision.rs b/src/test/compile-fail/unboxed-closure-sugar-lifetime-elision.rs index e08d84944c02a..9ec6428de27a0 100644 --- a/src/test/compile-fail/unboxed-closure-sugar-lifetime-elision.rs +++ b/src/test/compile-fail/unboxed-closure-sugar-lifetime-elision.rs @@ -20,7 +20,7 @@ trait Foo { fn dummy(&self, t: T, u: U); } -trait Eq for Sized? { } +trait Eq { } impl Eq for X { } fn eq>() { } diff --git a/src/test/compile-fail/unboxed-closure-sugar-region.rs b/src/test/compile-fail/unboxed-closure-sugar-region.rs index a938f126c1607..a2225b0615b01 100644 --- a/src/test/compile-fail/unboxed-closure-sugar-region.rs +++ b/src/test/compile-fail/unboxed-closure-sugar-region.rs @@ -21,7 +21,7 @@ trait Foo<'a,T,U> { fn dummy(&'a self) -> &'a (T,U); } -trait Eq for Sized? { } +trait Eq { } impl Eq for X { } fn eq>() { } diff --git a/src/test/compile-fail/unsized.rs b/src/test/compile-fail/unsized.rs index 43db4dfd395b0..92dbea0424b6f 100644 --- a/src/test/compile-fail/unsized.rs +++ b/src/test/compile-fail/unsized.rs @@ -10,7 +10,7 @@ // Test syntax checks for `type` keyword. -struct S1 for type; //~ ERROR expected `{`, `(`, or `;` after struct name, found `for` +struct S1 for type; //~ ERROR expected `where`, `{`, `(`, or `;` after struct name, found `for` pub fn main() { } diff --git a/src/test/compile-fail/unsized3.rs b/src/test/compile-fail/unsized3.rs index 0a75240f2d89d..76a6f01b18322 100644 --- a/src/test/compile-fail/unsized3.rs +++ b/src/test/compile-fail/unsized3.rs @@ -20,7 +20,7 @@ fn f2(x: &X) { } // Bounded. -trait T for Sized? {} +trait T {} fn f3(x: &X) { f4::(x); //~^ ERROR the trait `core::kinds::Sized` is not implemented diff --git a/src/test/compile-fail/unsized6.rs b/src/test/compile-fail/unsized6.rs index 0efd178f75b8c..4fcf7707f07fe 100644 --- a/src/test/compile-fail/unsized6.rs +++ b/src/test/compile-fail/unsized6.rs @@ -11,7 +11,7 @@ // Test `Sized?` local variables. -trait T for Sized? {} +trait T {} fn f1(x: &X) { let _: X; // <-- this is OK, no bindings created, no initializer. diff --git a/src/test/compile-fail/unsized7.rs b/src/test/compile-fail/unsized7.rs index c0e6ae1db92c4..e919f04971319 100644 --- a/src/test/compile-fail/unsized7.rs +++ b/src/test/compile-fail/unsized7.rs @@ -10,7 +10,7 @@ // Test sized-ness checking in substitution in impls. -trait T for Sized? {} +trait T {} // I would like these to fail eventually. // impl - bounded diff --git a/src/test/run-pass/associated-types-conditional-dispatch.rs b/src/test/run-pass/associated-types-conditional-dispatch.rs index 3b53203d218e0..213775d86f40d 100644 --- a/src/test/run-pass/associated-types-conditional-dispatch.rs +++ b/src/test/run-pass/associated-types-conditional-dispatch.rs @@ -18,7 +18,7 @@ use std::ops::Deref; -pub trait MyEq for Sized? { +pub trait MyEq { fn eq(&self, u: &U) -> bool; } diff --git a/src/test/run-pass/associated-types-normalize-in-bounds-ufcs.rs b/src/test/run-pass/associated-types-normalize-in-bounds-ufcs.rs index 0fd477204215e..8f1523e736dc5 100644 --- a/src/test/run-pass/associated-types-normalize-in-bounds-ufcs.rs +++ b/src/test/run-pass/associated-types-normalize-in-bounds-ufcs.rs @@ -16,7 +16,7 @@ struct Splits<'a, T, P>; struct SplitsN; -trait SliceExt2 for Sized? { +trait SliceExt2 { type Item; fn split2<'a, P>(&'a self, pred: P) -> Splits<'a, Self::Item, P> diff --git a/src/test/run-pass/associated-types-normalize-in-bounds.rs b/src/test/run-pass/associated-types-normalize-in-bounds.rs index f09c27029d7fa..f00c822bee0a5 100644 --- a/src/test/run-pass/associated-types-normalize-in-bounds.rs +++ b/src/test/run-pass/associated-types-normalize-in-bounds.rs @@ -16,7 +16,7 @@ struct Splits<'a, T, P>; struct SplitsN; -trait SliceExt2 for Sized? { +trait SliceExt2 { type Item; fn split2<'a, P>(&'a self, pred: P) -> Splits<'a, Self::Item, P> diff --git a/src/test/run-pass/c-stack-returning-int64.rs b/src/test/run-pass/c-stack-returning-int64.rs index c95cf0bfdee45..22c322b86c979 100644 --- a/src/test/run-pass/c-stack-returning-int64.rs +++ b/src/test/run-pass/c-stack-returning-int64.rs @@ -12,7 +12,7 @@ extern crate libc; -use std::c_str::ToCStr; +use std::ffi::CString; mod mlibc { use libc::{c_char, c_long, c_longlong}; @@ -24,11 +24,13 @@ mod mlibc { } fn atol(s: String) -> int { - s.as_slice().with_c_str(|x| unsafe { mlibc::atol(x) as int }) + let c = CString::from_slice(s.as_bytes()); + unsafe { mlibc::atol(c.as_ptr()) as int } } fn atoll(s: String) -> i64 { - s.as_slice().with_c_str(|x| unsafe { mlibc::atoll(x) as i64 }) + let c = CString::from_slice(s.as_bytes()); + unsafe { mlibc::atoll(c.as_ptr()) as i64 } } pub fn main() { diff --git a/src/test/run-pass/const-str-ptr.rs b/src/test/run-pass/const-str-ptr.rs index 5e028d3774fc5..e846501be6ee5 100644 --- a/src/test/run-pass/const-str-ptr.rs +++ b/src/test/run-pass/const-str-ptr.rs @@ -9,7 +9,6 @@ // except according to those terms. use std::{str, string}; -use std::c_str::ToCStr; const A: [u8; 2] = ['h' as u8, 'i' as u8]; const B: &'static [u8; 2] = &A; @@ -19,12 +18,7 @@ pub fn main() { unsafe { let foo = &A as *const u8; assert_eq!(str::from_utf8_unchecked(&A), "hi"); - assert_eq!(String::from_raw_buf_len(foo, A.len()), "hi".to_string()); - assert_eq!(String::from_raw_buf_len(C, B.len()), "hi".to_string()); assert!(*C == A[0]); assert!(*(&B[0] as *const u8) == A[0]); - - let bar = str::from_utf8_unchecked(&A).to_c_str(); - assert_eq!(bar.as_str(), "hi".to_c_str().as_str()); } } diff --git a/src/test/run-pass/foreign-fn-linkname.rs b/src/test/run-pass/foreign-fn-linkname.rs index 8a75fdd685dd1..dff1a1eaa0473 100644 --- a/src/test/run-pass/foreign-fn-linkname.rs +++ b/src/test/run-pass/foreign-fn-linkname.rs @@ -11,7 +11,7 @@ // ignore-fast doesn't like extern crate extern crate libc; -use std::c_str::ToCStr; +use std::ffi::CString; mod mlibc { use libc::{c_char, size_t}; @@ -24,11 +24,10 @@ mod mlibc { fn strlen(str: String) -> uint { // C string is terminated with a zero - str.as_slice().with_c_str(|buf| { - unsafe { - mlibc::my_strlen(buf) as uint - } - }) + let s = CString::from_slice(str.as_bytes()); + unsafe { + mlibc::my_strlen(s.as_ptr()) as uint + } } pub fn main() { diff --git a/src/test/run-pass/issue-11881.rs b/src/test/run-pass/issue-11881.rs index 24deb7c2e4b40..d0d8a8589a4e2 100644 --- a/src/test/run-pass/issue-11881.rs +++ b/src/test/run-pass/issue-11881.rs @@ -40,16 +40,10 @@ enum WireProtocol { // ... } -fn encode_json< - T: for<'a> Encodable, - fmt::Error>>(val: &T, - wr: &mut SeekableMemWriter) { +fn encode_json(val: &T, wr: &mut SeekableMemWriter) { write!(wr, "{}", json::as_json(val)); } -fn encode_rbml<'a, - T: Encodable, - io::IoError>>(val: &T, - wr: &'a mut SeekableMemWriter) { +fn encode_rbml(val: &T, wr: &mut SeekableMemWriter) { let mut encoder = writer::Encoder::new(wr); val.encode(&mut encoder); } diff --git a/src/test/run-pass/issue-15924.rs b/src/test/run-pass/issue-15924.rs index 1ab8deda3830e..db9f1cc9df7c9 100644 --- a/src/test/run-pass/issue-15924.rs +++ b/src/test/run-pass/issue-15924.rs @@ -21,7 +21,7 @@ struct Foo { } #[unsafe_destructor] -impl Encodable, fmt::Error>> Drop for Foo { +impl Drop for Foo { fn drop(&mut self) { json::encode(&self.v); } diff --git a/src/test/run-pass/issue-17904.rs b/src/test/run-pass/issue-17904.rs new file mode 100644 index 0000000000000..d5e8de6a54a1b --- /dev/null +++ b/src/test/run-pass/issue-17904.rs @@ -0,0 +1,20 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// ignore-pretty + +struct Foo where T: Copy; +struct Bar(T) where T: Copy; +struct Bleh(T, U) where T: Copy, U: Sized; +struct Baz where T: Copy { + field: T +} + +fn main() {} diff --git a/src/test/run-pass/issue-4016.rs b/src/test/run-pass/issue-4016.rs index e5cc8414f064b..220332f63548a 100644 --- a/src/test/run-pass/issue-4016.rs +++ b/src/test/run-pass/issue-4016.rs @@ -13,7 +13,7 @@ extern crate serialize; use serialize::{json, Decodable}; -trait JD : Decodable { } +trait JD : Decodable {} fn exec() { let doc = json::from_str("").unwrap(); diff --git a/src/test/compile-fail/variance-trait-matching-2.rs b/src/test/run-pass/parse-complex-macro-invoc-op.rs similarity index 50% rename from src/test/compile-fail/variance-trait-matching-2.rs rename to src/test/run-pass/parse-complex-macro-invoc-op.rs index cae7a4cefadb0..e9ec624c13edf 100644 --- a/src/test/compile-fail/variance-trait-matching-2.rs +++ b/src/test/run-pass/parse-complex-macro-invoc-op.rs @@ -8,23 +8,36 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -extern crate serialize; - -use std::fmt; -use serialize::{Encodable, Encoder}; - -pub fn buffer_encode<'a, - T:Encodable,fmt::Error>>( - to_encode_object: &T) - -> String { - let mut m = String::new(); - { - let mut encoder = - serialize::json::Encoder::new(&mut m); - //~^ ERROR `m` does not live long enough - to_encode_object.encode(&mut encoder); - } - m +// Test parsing binary operators after macro invocations. + +#![feature(macro_rules)] + +macro_rules! id { + ($e: expr) => { $e } +} + +fn foo() { + id!(1i) + 1; + id![1i] - 1; + id!(1i) * 1; + id![1i] / 1; + id!(1i) % 1; + + id!(1i) & 1; + id![1i] | 1; + id!(1i) ^ 1; + + let mut x = 1i; + id![x] = 2; + id!(x) += 1; + + id!(1f64).clone(); + + id!([1i, 2, 3])[1]; + id![drop](1i); + + id!(true) && true; + id![true] || true; } fn main() {} diff --git a/src/test/run-pass/regions-reassign-let-bound-pointer.rs b/src/test/run-pass/regions-reassign-let-bound-pointer.rs new file mode 100644 index 0000000000000..ecf79de622222 --- /dev/null +++ b/src/test/run-pass/regions-reassign-let-bound-pointer.rs @@ -0,0 +1,23 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Check that the type checker permits us to reassign `z` which +// started out with a longer lifetime and was reassigned to a shorter +// one (it should infer to be the intersection). + +fn foo(x: &int) { + let a = 1; + let mut z = x; + z = &a; +} + +pub fn main() { + foo(&1); +} diff --git a/src/test/run-pass/regions-reassign-match-bound-pointer.rs b/src/test/run-pass/regions-reassign-match-bound-pointer.rs new file mode 100644 index 0000000000000..18312b17339ce --- /dev/null +++ b/src/test/run-pass/regions-reassign-match-bound-pointer.rs @@ -0,0 +1,26 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Check that the type checker permits us to reassign `z` which +// started out with a longer lifetime and was reassigned to a shorter +// one (it should infer to be the intersection). + +fn foo(x: &int) { + let a = 1; + match x { + mut z => { + z = &a; + } + } +} + +pub fn main() { + foo(&1); +} diff --git a/src/test/run-pass/regions-relate-bound-regions-on-closures-to-inference-variables.rs b/src/test/run-pass/regions-relate-bound-regions-on-closures-to-inference-variables.rs new file mode 100644 index 0000000000000..aa0ed023da3e2 --- /dev/null +++ b/src/test/run-pass/regions-relate-bound-regions-on-closures-to-inference-variables.rs @@ -0,0 +1,65 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Test that this fairly specialized, but also reasonable, pattern +// typechecks. The pattern involves regions bound in closures that +// wind up related to inference variables. +// +// NB. Changes to the region implementatiosn have broken this pattern +// a few times, but it happens to be used in the compiler so those +// changes were caught. However, those uses in the compiler could +// easily get changed or refactored away in the future. + +struct Ctxt<'tcx> { + x: &'tcx Vec +} + +struct Foo<'a,'tcx:'a> { + cx: &'a Ctxt<'tcx>, +} + +impl<'a,'tcx> Foo<'a,'tcx> { + fn bother(&mut self) -> int { + self.elaborate_bounds(|this| { + // (*) Here: type of `this` is `&'f0 Foo<&'f1, '_2>`, + // where `'f0` and `'f1` are fresh, free regions that + // result from the bound regions on the closure, and `'2` + // is a region inference variable created by the call. Due + // to the constraints on the type, we find that `'_2 : 'f1 + // + 'f2` must hold (and can be assumed by the callee). + // Region inference has to do some clever stuff to avoid + // inferring `'_2` to be `'static` in this case, because + // it is created outside the closure but then related to + // regions bound by the closure itself. See the + // `region_inference.rs` file (and the `givens` field, in + // particular) for more details. + this.foo() + }) + } + + fn foo(&mut self) -> int { + 22 + } + + fn elaborate_bounds( + &mut self, + mk_cand: for<'b>|this: &mut Foo<'b, 'tcx>| -> int) + -> int + { + mk_cand(self) + } +} + +fn main() { + let v = vec!(); + let cx = Ctxt { x: &v }; + let mut foo = Foo { cx: &cx }; + assert_eq!(foo.bother(), 22); // just so the code is not dead, basically +} diff --git a/src/test/run-pass/rename-directory.rs b/src/test/run-pass/rename-directory.rs index c7aa405b513e4..d610bf09edb95 100644 --- a/src/test/run-pass/rename-directory.rs +++ b/src/test/run-pass/rename-directory.rs @@ -13,8 +13,8 @@ extern crate libc; +use std::ffi::CString; use std::io::TempDir; -use std::c_str::ToCStr; use std::io::fs::PathExtensions; use std::io::fs; use std::io; @@ -31,20 +31,17 @@ fn rename_directory() { let test_file = &old_path.join("temp.txt"); /* Write the temp input file */ - let ostream = test_file.with_c_str(|fromp| { - "w+b".with_c_str(|modebuf| { - libc::fopen(fromp, modebuf) - }) - }); + let fromp = CString::from_slice(test_file.as_vec()); + let modebuf = CString::from_slice(b"w+b"); + let ostream = libc::fopen(fromp.as_ptr(), modebuf.as_ptr()); assert!((ostream as uint != 0u)); let s = "hello".to_string(); - "hello".with_c_str(|buf| { - let write_len = libc::fwrite(buf as *const libc::c_void, - 1u as libc::size_t, - (s.len() + 1u) as libc::size_t, - ostream); - assert_eq!(write_len, (s.len() + 1) as libc::size_t) - }); + let buf = CString::from_slice(b"hello"); + let write_len = libc::fwrite(buf.as_ptr() as *mut _, + 1u as libc::size_t, + (s.len() + 1u) as libc::size_t, + ostream); + assert_eq!(write_len, (s.len() + 1) as libc::size_t); assert_eq!(libc::fclose(ostream), (0u as libc::c_int)); let new_path = tmpdir.join_many(&["quux", "blat"]); diff --git a/src/test/run-pass/running-with-no-runtime.rs b/src/test/run-pass/running-with-no-runtime.rs index fc53737bb445a..6f807fc34995e 100644 --- a/src/test/run-pass/running-with-no-runtime.rs +++ b/src/test/run-pass/running-with-no-runtime.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use std::ffi; use std::io::process::{Command, ProcessOutput}; use std::os; use std::rt::unwind::try; @@ -34,7 +35,8 @@ fn start(argc: int, argv: *const *const u8) -> int { let args = unsafe { range(0, argc as uint).map(|i| { - String::from_raw_buf(*argv.offset(i as int)).into_bytes() + let ptr = *argv.offset(i as int) as *const _; + ffi::c_str_to_bytes(&ptr).to_vec() }).collect::>() }; let me = args[0].as_slice(); diff --git a/src/test/run-pass/variadic-ffi.rs b/src/test/run-pass/variadic-ffi.rs index ec320c1f8a309..de9d7880411a1 100644 --- a/src/test/run-pass/variadic-ffi.rs +++ b/src/test/run-pass/variadic-ffi.rs @@ -10,7 +10,7 @@ extern crate libc; -use std::c_str::{CString, ToCStr}; +use std::ffi::{self, CString}; use libc::{c_char, c_int}; // ignore-fast doesn't like extern crate @@ -22,40 +22,35 @@ extern { unsafe fn check(expected: &str, f: |*mut c_char| -> T) { let mut x = [0 as c_char; 50]; f(&mut x[0] as *mut c_char); - let res = CString::new(&x[0], false); - assert_eq!(expected, res.as_str().unwrap()); + assert_eq!(expected.as_bytes(), ffi::c_str_to_bytes(&x.as_ptr())); } pub fn main() { unsafe { // Call with just the named parameter - "Hello World\n".with_c_str(|c| { - check("Hello World\n", |s| sprintf(s, c)); - }); + let c = CString::from_slice(b"Hello World\n"); + check("Hello World\n", |s| sprintf(s, c.as_ptr())); // Call with variable number of arguments - "%d %f %c %s\n".with_c_str(|c| { - check("42 42.500000 a %d %f %c %s\n\n", |s| { - sprintf(s, c, 42i, 42.5f64, 'a' as c_int, c); - }) + let c = CString::from_slice(b"%d %f %c %s\n"); + check("42 42.500000 a %d %f %c %s\n\n", |s| { + sprintf(s, c.as_ptr(), 42i, 42.5f64, 'a' as c_int, c.as_ptr()); }); // Make a function pointer - let x: unsafe extern "C" fn(*mut c_char, *const c_char, ...) -> c_int = sprintf; + let x: unsafe extern fn(*mut c_char, *const c_char, ...) -> c_int = sprintf; // A function that takes a function pointer - unsafe fn call(p: unsafe extern "C" fn(*mut c_char, *const c_char, ...) -> c_int) { - // Call with just the named parameter via fn pointer - "Hello World\n".with_c_str(|c| { - check("Hello World\n", |s| p(s, c)); - }); + unsafe fn call(p: unsafe extern fn(*mut c_char, *const c_char, ...) -> c_int) { + // Call with just the named parameter + let c = CString::from_slice(b"Hello World\n"); + check("Hello World\n", |s| sprintf(s, c.as_ptr())); // Call with variable number of arguments - "%d %f %c %s\n".with_c_str(|c| { - check("42 42.500000 a %d %f %c %s\n\n", |s| { - p(s, c, 42i, 42.5f64, 'a' as c_int, c); - }) + let c = CString::from_slice(b"%d %f %c %s\n"); + check("42 42.500000 a %d %f %c %s\n\n", |s| { + sprintf(s, c.as_ptr(), 42i, 42.5f64, 'a' as c_int, c.as_ptr()); }); }