From ba707fb3a0735c0ca19baac426b88218c656a34b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adolfo=20Ochagav=C3=ADa?= Date: Sat, 19 Jul 2014 11:34:51 +0200 Subject: [PATCH 01/23] Remove OwnedStr trait This trait was only implemented by `String`. It provided the methods `into_bytes` and `append`, both of which **are already implemented as normal methods** of `String` (not as trait methods). This change improves the consistency of strings. This shouldn't break any code, except if somebody has implemented `OwnedStr` for a user-defined type. --- src/libcollections/str.rs | 29 ----------------------------- src/libstd/ascii.rs | 2 +- src/libstd/os.rs | 4 ---- src/libstd/prelude.rs | 2 +- 4 files changed, 2 insertions(+), 35 deletions(-) diff --git a/src/libcollections/str.rs b/src/libcollections/str.rs index c0e903677de..ae1fb87ef7f 100644 --- a/src/libcollections/str.rs +++ b/src/libcollections/str.rs @@ -603,11 +603,6 @@ pub mod raw { from_utf8_owned(vec![u]) } - /// Sets the length of a string - /// - /// This will explicitly set the size of the string, without actually - /// modifying its buffers, so it is up to the caller to ensure that - /// the string is actually the specified size. #[test] fn test_from_buf_len() { use slice::ImmutableVector; @@ -785,30 +780,6 @@ impl<'a> StrAllocating for &'a str { } } -/// Methods for owned strings -pub trait OwnedStr { - /// Consumes the string, returning the underlying byte buffer. - /// - /// The buffer does not have a null terminator. - fn into_bytes(self) -> Vec; - - /// Pushes the given string onto this string, returning the concatenation of the two strings. - fn append(self, rhs: &str) -> String; -} - -impl OwnedStr for String { - #[inline] - fn into_bytes(self) -> Vec { - unsafe { mem::transmute(self) } - } - - #[inline] - fn append(mut self, rhs: &str) -> String { - self.push_str(rhs); - self - } -} - #[cfg(test)] mod tests { use std::iter::AdditiveIterator; diff --git a/src/libstd/ascii.rs b/src/libstd/ascii.rs index 02cb5dd245b..bcc0761d92a 100644 --- a/src/libstd/ascii.rs +++ b/src/libstd/ascii.rs @@ -20,7 +20,7 @@ use iter::Iterator; use mem; use option::{Option, Some, None}; use slice::{ImmutableVector, MutableVector, Vector}; -use str::{OwnedStr, Str, StrAllocating, StrSlice}; +use str::{Str, StrAllocating, StrSlice}; use string::String; use to_string::IntoStr; use vec::Vec; diff --git a/src/libstd/os.rs b/src/libstd/os.rs index f71f1d22d00..ca76be40cb5 100644 --- a/src/libstd/os.rs +++ b/src/libstd/os.rs @@ -56,8 +56,6 @@ use vec::Vec; use c_str::ToCStr; #[cfg(unix)] use libc::c_char; -#[cfg(windows)] -use str::OwnedStr; /// Get the number of cores available pub fn num_cpus() -> uint { @@ -708,8 +706,6 @@ pub fn self_exe_name() -> Option { #[cfg(windows)] fn load_self() -> Option> { - use str::OwnedStr; - unsafe { use os::win32::fill_utf16_buf_and_decode; fill_utf16_buf_and_decode(|buf, sz| { diff --git a/src/libstd/prelude.rs b/src/libstd/prelude.rs index 0ce7497cf30..96d5c0785f4 100644 --- a/src/libstd/prelude.rs +++ b/src/libstd/prelude.rs @@ -76,7 +76,7 @@ #[doc(no_inline)] pub use path::{GenericPath, Path, PosixPath, WindowsPath}; #[doc(no_inline)] pub use ptr::RawPtr; #[doc(no_inline)] pub use io::{Buffer, Writer, Reader, Seek}; -#[doc(no_inline)] pub use str::{Str, StrVector, StrSlice, OwnedStr}; +#[doc(no_inline)] pub use str::{Str, StrVector, StrSlice}; #[doc(no_inline)] pub use str::{IntoMaybeOwned, StrAllocating, UnicodeStrSlice}; #[doc(no_inline)] pub use to_string::{ToString, IntoStr}; #[doc(no_inline)] pub use tuple::{Tuple1, Tuple2, Tuple3, Tuple4}; From eacc5d779fe4080dd2b45e035ca2af099b8b906d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adolfo=20Ochagav=C3=ADa?= Date: Sat, 19 Jul 2014 12:08:34 +0200 Subject: [PATCH 02/23] Deprecated `str::raw::from_c_str` Use `string::raw::from_buf` instead [breaking-change] --- src/libcollections/str.rs | 15 +++------------ src/libcoretest/ptr.rs | 16 +++++++--------- src/librustc/middle/trans/type_.rs | 11 +++++------ src/librustuv/lib.rs | 6 +++--- src/libstd/os.rs | 2 +- src/test/run-pass/const-str-ptr.rs | 2 +- 6 files changed, 20 insertions(+), 32 deletions(-) diff --git a/src/libcollections/str.rs b/src/libcollections/str.rs index ae1fb87ef7f..69372b6d89c 100644 --- a/src/libcollections/str.rs +++ b/src/libcollections/str.rs @@ -555,9 +555,9 @@ impl<'a> fmt::Show for MaybeOwned<'a> { /// Unsafe operations pub mod raw { - use core::prelude::*; use core::mem; use core::raw::Slice; + use core::ptr::RawPtr; use string::String; use vec::Vec; @@ -577,7 +577,8 @@ pub mod raw { result } - /// Create a Rust string from a null-terminated C string + /// Deprecated. Use `CString::as_str().unwrap().to_string()` + #[deprecated = "Use CString::as_str().unwrap().to_string()"] pub unsafe fn from_c_str(c_string: *const i8) -> String { let mut buf = String::new(); let mut len = 0; @@ -1348,16 +1349,6 @@ mod tests { [0x50d7, 0xd824, 0x5010, 0xb369, 0x22ea]); } - #[test] - fn test_raw_from_c_str() { - unsafe { - let a = vec![65, 65, 65, 65, 65, 65, 65, 0]; - let b = a.as_ptr(); - let c = raw::from_c_str(b); - assert_eq!(c, String::from_str("AAAAAAA")); - } - } - #[test] fn test_as_bytes() { // no null diff --git a/src/libcoretest/ptr.rs b/src/libcoretest/ptr.rs index 2a4ef5e275d..9058ae56c45 100644 --- a/src/libcoretest/ptr.rs +++ b/src/libcoretest/ptr.rs @@ -11,8 +11,8 @@ use core::ptr::*; use libc::c_char; use core::mem; -use std::str; use libc; +use std::c_str::CString; #[test] fn test() { @@ -186,9 +186,8 @@ fn test_ptr_array_each_with_len() { let mut ctr = 0; let mut iteration_count = 0; array_each_with_len(arr.as_ptr(), arr.len(), |e| { - let actual = str::raw::from_c_str(e); - let expected = str::raw::from_c_str(expected_arr[ctr].as_ptr()); - assert_eq!(actual.as_slice(), expected.as_slice()); + let actual = CString::new(e, false); + assert_eq!(actual.as_str(), expected_arr[ctr].as_str()); ctr += 1; iteration_count += 1; }); @@ -217,9 +216,8 @@ fn test_ptr_array_each() { let mut ctr = 0u; let mut iteration_count = 0u; array_each(arr_ptr, |e| { - let actual = str::raw::from_c_str(e); - let expected = str::raw::from_c_str(expected_arr[ctr].as_ptr()); - assert_eq!(actual.as_slice(), expected.as_slice()); + let actual = CString::new(e, false); + assert_eq!(actual.as_str(), expected_arr[ctr].as_str()); ctr += 1; iteration_count += 1; }); @@ -232,7 +230,7 @@ fn test_ptr_array_each() { fn test_ptr_array_each_with_len_null_ptr() { unsafe { array_each_with_len(0 as *const *const libc::c_char, 1, |e| { - str::raw::from_c_str(e); + CString::new(e, false).as_str().unwrap(); }); } } @@ -241,7 +239,7 @@ fn test_ptr_array_each_with_len_null_ptr() { fn test_ptr_array_each_null_ptr() { unsafe { array_each(0 as *const *const libc::c_char, |e| { - str::raw::from_c_str(e); + CString::new(e, false).as_str().unwrap(); }); } } diff --git a/src/librustc/middle/trans/type_.rs b/src/librustc/middle/trans/type_.rs index 573965108ad..3833d4cd0c8 100644 --- a/src/librustc/middle/trans/type_.rs +++ b/src/librustc/middle/trans/type_.rs @@ -19,11 +19,10 @@ use middle::trans::context::CrateContext; use syntax::ast; use syntax::abi::{X86, X86_64, Arm, Mips, Mipsel}; -use std::c_str::ToCStr; +use std::c_str::{CString, ToCStr}; use std::mem; use std::cell::RefCell; use std::collections::HashMap; -use std::str::raw::from_c_str; use libc::{c_uint, c_void, free}; @@ -334,9 +333,9 @@ impl TypeNames { pub fn type_to_string(&self, ty: Type) -> String { unsafe { let s = llvm::LLVMTypeToString(ty.to_ref()); - let ret = from_c_str(s); + let ret = CString::new(s, false).as_str().unwrap().to_string(); free(s as *mut c_void); - ret.to_string() + ret } } @@ -348,9 +347,9 @@ impl TypeNames { pub fn val_to_string(&self, val: ValueRef) -> String { unsafe { let s = llvm::LLVMValueToString(val); - let ret = from_c_str(s); + let ret = CString::new(s, false).as_str().unwrap().to_string(); free(s as *mut c_void); - ret.to_string() + ret } } } diff --git a/src/librustuv/lib.rs b/src/librustuv/lib.rs index 2c2e134d882..dc43a68e64d 100644 --- a/src/librustuv/lib.rs +++ b/src/librustuv/lib.rs @@ -55,6 +55,7 @@ extern crate libc; extern crate alloc; use libc::{c_int, c_void}; +use std::c_str::CString; use std::fmt; use std::mem; use std::ptr; @@ -62,7 +63,6 @@ use std::rt::local::Local; use std::rt::rtio; use std::rt::rtio::{IoResult, IoError}; use std::rt::task::{BlockedTask, Task}; -use std::str::raw::from_c_str; use std::task; pub use self::async::AsyncWatcher; @@ -363,7 +363,7 @@ impl UvError { let inner = match self { &UvError(a) => a }; let name_str = uvll::uv_err_name(inner); assert!(name_str.is_not_null()); - from_c_str(name_str).to_string() + CString::new(name_str, false).as_str().unwrap().to_string() } } @@ -372,7 +372,7 @@ impl UvError { let inner = match self { &UvError(a) => a }; let desc_str = uvll::uv_strerror(inner); assert!(desc_str.is_not_null()); - from_c_str(desc_str).to_string() + CString::new(desc_str, false).as_str().unwrap().to_string() } } diff --git a/src/libstd/os.rs b/src/libstd/os.rs index ca76be40cb5..1b61dec99b4 100644 --- a/src/libstd/os.rs +++ b/src/libstd/os.rs @@ -998,7 +998,7 @@ pub fn error_string(errnum: uint) -> String { fail!("strerror_r failure"); } - str::raw::from_c_str(p as *const c_char).into_string() + ::c_str::CString::new(p as *const c_char, false).as_str().unwrap().to_string() } } diff --git a/src/test/run-pass/const-str-ptr.rs b/src/test/run-pass/const-str-ptr.rs index 6790e237e26..57d262d3268 100644 --- a/src/test/run-pass/const-str-ptr.rs +++ b/src/test/run-pass/const-str-ptr.rs @@ -24,6 +24,6 @@ pub fn main() { assert!(*(&B[0] as *const u8) == A[0]); let bar = str::raw::from_utf8(A).to_c_str(); - assert_eq!(str::raw::from_c_str(bar.as_ptr()), "hi".to_string()); + assert_eq!(bar.as_str(), "hi".to_c_str().as_str()); } } From 9ec19373af8aaad641b39a25fa4ac7bfef513fc2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adolfo=20Ochagav=C3=ADa?= Date: Sat, 19 Jul 2014 12:23:47 +0200 Subject: [PATCH 03/23] Deprecated `str::raw::from_utf8_owned` Replaced by `string::raw::from_utf8` [breaking-change] --- src/libcollections/str.rs | 9 ++++----- src/libcollections/string.rs | 13 +++++++++++++ src/libserialize/base64.rs | 4 ++-- src/libserialize/hex.rs | 4 ++-- 4 files changed, 21 insertions(+), 9 deletions(-) diff --git a/src/libcollections/str.rs b/src/libcollections/str.rs index 69372b6d89c..05107f5dda5 100644 --- a/src/libcollections/str.rs +++ b/src/libcollections/str.rs @@ -559,7 +559,7 @@ pub mod raw { use core::raw::Slice; use core::ptr::RawPtr; - use string::String; + use string::{mod, String}; use vec::Vec; use MutableSeq; @@ -592,11 +592,10 @@ pub mod raw { buf } - /// Converts an owned vector of bytes to a new owned string. This assumes - /// that the utf-8-ness of the vector has already been validated - #[inline] + /// Deprecated. Replaced by `string::raw::from_utf8` + #[deprecated = "Use string::raw::from_utf8"] pub unsafe fn from_utf8_owned(v: Vec) -> String { - mem::transmute(v) + string::raw::from_utf8(v) } /// Converts a byte to a string. diff --git a/src/libcollections/string.rs b/src/libcollections/string.rs index d58dfdd10d1..05321f46b11 100644 --- a/src/libcollections/string.rs +++ b/src/libcollections/string.rs @@ -570,6 +570,19 @@ impl Add for String { } } +pub mod raw { + use super::String; + use vec::Vec; + + /// 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. + #[inline] + pub unsafe fn from_utf8(bytes: Vec) -> String { + String { vec: bytes } + } +} + #[cfg(test)] mod tests { use std::prelude::*; diff --git a/src/libserialize/base64.rs b/src/libserialize/base64.rs index 5e8648d355e..9a30e87647a 100644 --- a/src/libserialize/base64.rs +++ b/src/libserialize/base64.rs @@ -11,8 +11,8 @@ // ignore-lexer-test FIXME #15679 //! Base64 binary-to-text encoding -use std::str; use std::fmt; +use std::string; /// Available encoding character sets pub enum CharacterSet { @@ -148,7 +148,7 @@ impl<'a> ToBase64 for &'a [u8] { } unsafe { - str::raw::from_utf8_owned(v) + string::raw::from_utf8(v) } } } diff --git a/src/libserialize/hex.rs b/src/libserialize/hex.rs index d6a029c583c..fa5b3ca4040 100644 --- a/src/libserialize/hex.rs +++ b/src/libserialize/hex.rs @@ -11,8 +11,8 @@ // ignore-lexer-test FIXME #15679 //! Hex binary-to-text encoding -use std::str; use std::fmt; +use std::string; /// A trait for converting a value to hexadecimal encoding pub trait ToHex { @@ -47,7 +47,7 @@ impl<'a> ToHex for &'a [u8] { } unsafe { - str::raw::from_utf8_owned(v) + string::raw::from_utf8(v) } } } From feeae27a56f034a0d041a4985fa731ee5b42d315 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adolfo=20Ochagav=C3=ADa?= Date: Sat, 19 Jul 2014 12:30:35 +0200 Subject: [PATCH 04/23] Deprecated `str::raw::from_byte` Use `string:raw::from_utf8` instead [breaking-change] --- src/libcollections/str.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/libcollections/str.rs b/src/libcollections/str.rs index 05107f5dda5..e83e617dba7 100644 --- a/src/libcollections/str.rs +++ b/src/libcollections/str.rs @@ -598,9 +598,10 @@ pub mod raw { string::raw::from_utf8(v) } - /// Converts a byte to a string. + /// Deprecated. Use `String::from_bytes` + #[deprecated = "Use String::from_bytes"] pub unsafe fn from_byte(u: u8) -> String { - from_utf8_owned(vec![u]) + String::from_bytes(vec![u]) } #[test] From 6e509d3462d20b696a1b5d18f14884b4e391a6ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adolfo=20Ochagav=C3=ADa?= Date: Sun, 20 Jul 2014 12:08:40 +0200 Subject: [PATCH 05/23] Deprecated `str::raw::from_buf_len` Replaced by `string::raw::from_buf_len` [breaking-change] --- src/libcollections/str.rs | 29 ++++++----------------------- src/libcollections/string.rs | 25 +++++++++++++++++++++++++ src/librustc/metadata/loader.rs | 4 ++-- src/librustdoc/html/markdown.rs | 3 ++- src/libstd/os.rs | 10 +++++----- src/test/run-pass/const-str-ptr.rs | 6 +++--- 6 files changed, 43 insertions(+), 34 deletions(-) diff --git a/src/libcollections/str.rs b/src/libcollections/str.rs index e83e617dba7..731c761351c 100644 --- a/src/libcollections/str.rs +++ b/src/libcollections/str.rs @@ -558,7 +558,6 @@ pub mod raw { use core::mem; use core::raw::Slice; use core::ptr::RawPtr; - use string::{mod, String}; use vec::Vec; @@ -567,14 +566,10 @@ pub mod raw { pub use core::str::raw::{from_utf8, c_str_to_static_slice, slice_bytes}; pub use core::str::raw::{slice_unchecked}; - /// Create a Rust string from a *u8 buffer of the given length + /// Deprecated. Replaced by `string::raw::from_buf_len` + #[deprecated = "Use string::raw::from_buf_len"] pub unsafe fn from_buf_len(buf: *const u8, len: uint) -> String { - let mut result = String::new(); - result.push_bytes(mem::transmute(Slice { - data: buf, - len: len, - })); - result + string::raw::from_buf_len(buf, len) } /// Deprecated. Use `CString::as_str().unwrap().to_string()` @@ -598,22 +593,10 @@ pub mod raw { string::raw::from_utf8(v) } - /// Deprecated. Use `String::from_bytes` - #[deprecated = "Use String::from_bytes"] + /// Deprecated. Use `string::raw::from_utf8` + #[deprecated = "Use string::raw::from_utf8"] pub unsafe fn from_byte(u: u8) -> String { - String::from_bytes(vec![u]) - } - - #[test] - fn test_from_buf_len() { - use slice::ImmutableVector; - - unsafe { - let a = vec![65u8, 65u8, 65u8, 65u8, 65u8, 65u8, 65u8, 0u8]; - let b = a.as_ptr(); - let c = from_buf_len(b, 3u); - assert_eq!(c, String::from_str("AAA")); - } + string::raw::from_utf8(vec![u]) } } diff --git a/src/libcollections/string.rs b/src/libcollections/string.rs index 05321f46b11..bb8424bd363 100644 --- a/src/libcollections/string.rs +++ b/src/libcollections/string.rs @@ -571,6 +571,9 @@ impl Add for String { } pub mod raw { + use core::mem; + use core::raw::Slice; + use super::String; use vec::Vec; @@ -581,6 +584,20 @@ pub mod raw { pub unsafe fn from_utf8(bytes: Vec) -> String { String { vec: bytes } } + + /// Create a Rust string from a *u8 buffer of the given length + /// + /// This function is unsafe because of two reasons: + /// * A raw pointer is dereferenced and transmuted to `&[u8]` + /// * The slice is not checked to see whether it contains valid UTF-8 + pub unsafe fn from_buf_len(buf: *const u8, len: uint) -> String { + use slice::CloneableVector; + let slice: &[u8] = mem::transmute(Slice { + data: buf, + len: len, + }); + self::from_utf8(slice.to_vec()) + } } #[cfg(test)] @@ -740,6 +757,14 @@ mod tests { String::from_str("\uFFFD𐒋\uFFFD")); } + #[test] + fn test_from_buf_len() { + unsafe { + let a = vec![65u8, 65, 65, 65, 65, 65, 65, 0]; + assert_eq!(super::raw::from_buf_len(a.as_ptr(), 3), String::from_str("AAA")); + } + } + #[test] fn test_push_bytes() { let mut s = String::from_str("ABC"); diff --git a/src/librustc/metadata/loader.rs b/src/librustc/metadata/loader.rs index e7d52ef3b3d..1811c4f8612 100644 --- a/src/librustc/metadata/loader.rs +++ b/src/librustc/metadata/loader.rs @@ -233,7 +233,7 @@ use std::io; use std::mem; use std::ptr; use std::slice; -use std::str; +use std::string; use std::collections::{HashMap, HashSet}; use flate; @@ -772,7 +772,7 @@ fn get_metadata_section_imp(os: abi::Os, filename: &Path) -> Result fmt::Result { "".to_string() } else { unsafe { - str::raw::from_buf_len((*text).data, (*text).size as uint) + string::raw::from_buf_len((*text).data, (*text).size as uint) } }; diff --git a/src/libstd/os.rs b/src/libstd/os.rs index 1b61dec99b4..f5183ab7188 100644 --- a/src/libstd/os.rs +++ b/src/libstd/os.rs @@ -47,9 +47,9 @@ use ptr; use result::{Err, Ok, Result}; use slice::{Vector, ImmutableVector, MutableVector, ImmutableEqVector}; use str::{Str, StrSlice, StrAllocating}; -use str; use string::String; use sync::atomics::{AtomicInt, INIT_ATOMIC_INT, SeqCst}; +use to_str::ToString; use vec::Vec; #[cfg(unix)] @@ -135,7 +135,7 @@ pub fn getcwd() -> Path { fail!(); } } - Path::new(String::from_utf16(str::truncate_utf16_at_nul(buf)) + Path::new(String::from_utf16(::str::truncate_utf16_at_nul(buf)) .expect("GetCurrentDirectoryW returned invalid UTF-16")) } @@ -413,7 +413,7 @@ pub fn setenv(n: &str, v: T) { fn _setenv(n: &str, v: &[u8]) { let n: Vec = n.utf16_units().collect(); let n = n.append_one(0); - let v: Vec = str::from_utf8(v).unwrap().utf16_units().collect(); + let v: Vec = ::str::from_utf8(v).unwrap().utf16_units().collect(); let v = v.append_one(0); unsafe { @@ -1045,7 +1045,7 @@ pub fn error_string(errnum: uint) -> String { return format!("OS Error {} (FormatMessageW() returned error {})", errnum, fm_err); } - let msg = String::from_utf16(str::truncate_utf16_at_nul(buf)); + let msg = String::from_utf16(::str::truncate_utf16_at_nul(buf)); match msg { Some(msg) => format!("OS Error {}: {}", errnum, msg), None => format!("OS Error {} (FormatMessageW() returned invalid UTF-16)", errnum), @@ -1202,7 +1202,7 @@ fn real_args() -> Vec { // Push it onto the list. let opt_s = slice::raw::buf_as_slice(ptr as *const _, len, |buf| { - String::from_utf16(str::truncate_utf16_at_nul(buf)) + String::from_utf16(::str::truncate_utf16_at_nul(buf)) }); opt_s.expect("CommandLineToArgvW returned invalid UTF-16") }); diff --git a/src/test/run-pass/const-str-ptr.rs b/src/test/run-pass/const-str-ptr.rs index 57d262d3268..0fef3dd4aac 100644 --- a/src/test/run-pass/const-str-ptr.rs +++ b/src/test/run-pass/const-str-ptr.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use std::str; +use std::{str, string}; static A: [u8, ..2] = ['h' as u8, 'i' as u8]; static B: &'static [u8, ..2] = &A; @@ -18,8 +18,8 @@ pub fn main() { unsafe { let foo = &A as *const u8; assert_eq!(str::raw::from_utf8(A), "hi"); - assert_eq!(str::raw::from_buf_len(foo, A.len()), "hi".to_string()); - assert_eq!(str::raw::from_buf_len(C, B.len()), "hi".to_string()); + assert_eq!(string::raw::from_buf_len(foo, A.len()), "hi".to_string()); + assert_eq!(string::raw::from_buf_len(C, B.len()), "hi".to_string()); assert!(*C == A[0]); assert!(*(&B[0] as *const u8) == A[0]); From 0fe894e49be235ff0ac22231d7fa3579a4192f0a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adolfo=20Ochagav=C3=ADa?= Date: Mon, 21 Jul 2014 20:44:56 +0200 Subject: [PATCH 06/23] Deprecated `String::from_raw_parts` Replaced by `string::raw::from_parts` [breaking-change] --- src/libcollections/str.rs | 3 ++- src/libcollections/string.rs | 27 +++++++++++++++++++-------- 2 files changed, 21 insertions(+), 9 deletions(-) diff --git a/src/libcollections/str.rs b/src/libcollections/str.rs index 731c761351c..db859bbf5bf 100644 --- a/src/libcollections/str.rs +++ b/src/libcollections/str.rs @@ -558,7 +558,8 @@ pub mod raw { use core::mem; use core::raw::Slice; use core::ptr::RawPtr; - use string::{mod, String}; + use string; + use string::String; use vec::Vec; use MutableSeq; diff --git a/src/libcollections/string.rs b/src/libcollections/string.rs index bb8424bd363..aeb323a9caf 100644 --- a/src/libcollections/string.rs +++ b/src/libcollections/string.rs @@ -49,14 +49,6 @@ impl String { } } - /// Creates a new string buffer from length, capacity, and a pointer. - #[inline] - pub unsafe fn from_raw_parts(length: uint, capacity: uint, ptr: *mut u8) -> String { - String { - vec: Vec::from_raw_parts(length, capacity, ptr), - } - } - /// Creates a new string buffer from the given string. #[inline] pub fn from_str(string: &str) -> String { @@ -65,6 +57,13 @@ impl String { } } + /// Deprecated. Replaced by `string::raw::from_parts` + #[inline] + #[deprecated = "Replaced by string::raw::from_parts"] + pub unsafe fn from_raw_parts(length: uint, capacity: uint, ptr: *mut u8) -> String { + raw::from_parts(length, capacity, ptr) + } + #[allow(missing_doc)] #[deprecated = "obsoleted by the removal of ~str"] #[inline] @@ -577,6 +576,18 @@ pub mod raw { use super::String; use vec::Vec; + /// Creates a new `String` from length, capacity, and a pointer. + /// + /// This is unsafe because: + /// * We call `Vec::from_raw_parts` to get a `Vec` + /// * We assume that the `Vec` contains valid UTF-8 + #[inline] + pub unsafe fn from_parts(length: uint, capacity: uint, ptr: *mut u8) -> String { + String { + vec: Vec::from_raw_parts(length, capacity, ptr), + } + } + /// 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. From 684479ab915afcbd1b3a82e0df550e3ce06ffab2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adolfo=20Ochagav=C3=ADa?= Date: Tue, 22 Jul 2014 16:02:54 +0200 Subject: [PATCH 07/23] Fix travis errors --- src/libstd/os.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libstd/os.rs b/src/libstd/os.rs index f5183ab7188..d2a2d9ff64b 100644 --- a/src/libstd/os.rs +++ b/src/libstd/os.rs @@ -49,7 +49,7 @@ use slice::{Vector, ImmutableVector, MutableVector, ImmutableEqVector}; use str::{Str, StrSlice, StrAllocating}; use string::String; use sync::atomics::{AtomicInt, INIT_ATOMIC_INT, SeqCst}; -use to_str::ToString; +use to_string::ToString; use vec::Vec; #[cfg(unix)] From 75a0062d88fdfe3dd08b19613b5d5c8b0a434437 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adolfo=20Ochagav=C3=ADa?= Date: Tue, 22 Jul 2014 17:55:12 +0200 Subject: [PATCH 08/23] Add `string::raw::from_buf` --- src/libcollections/str.rs | 18 ++--------- src/libcollections/string.rs | 48 ++++++++++++++++++++++-------- src/librustc/middle/trans/type_.rs | 7 +++-- src/librustuv/lib.rs | 6 ++-- src/libstd/os.rs | 3 +- 5 files changed, 47 insertions(+), 35 deletions(-) diff --git a/src/libcollections/str.rs b/src/libcollections/str.rs index db859bbf5bf..f013557f9a5 100644 --- a/src/libcollections/str.rs +++ b/src/libcollections/str.rs @@ -555,9 +555,6 @@ impl<'a> fmt::Show for MaybeOwned<'a> { /// Unsafe operations pub mod raw { - use core::mem; - use core::raw::Slice; - use core::ptr::RawPtr; use string; use string::String; use vec::Vec; @@ -573,19 +570,10 @@ pub mod raw { string::raw::from_buf_len(buf, len) } - /// Deprecated. Use `CString::as_str().unwrap().to_string()` - #[deprecated = "Use CString::as_str().unwrap().to_string()"] + /// Deprecated. Use `string::raw::from_buf` + #[deprecated = "Use string::raw::from_buf"] pub unsafe fn from_c_str(c_string: *const i8) -> String { - let mut buf = String::new(); - let mut len = 0; - while *c_string.offset(len) != 0 { - len += 1; - } - buf.push_bytes(mem::transmute(Slice { - data: c_string, - len: len as uint, - })); - buf + string::raw::from_buf(c_string as *const u8) } /// Deprecated. Replaced by `string::raw::from_utf8` diff --git a/src/libcollections/string.rs b/src/libcollections/string.rs index aeb323a9caf..282193d08aa 100644 --- a/src/libcollections/string.rs +++ b/src/libcollections/string.rs @@ -61,7 +61,7 @@ impl String { #[inline] #[deprecated = "Replaced by string::raw::from_parts"] pub unsafe fn from_raw_parts(length: uint, capacity: uint, ptr: *mut u8) -> String { - raw::from_parts(length, capacity, ptr) + raw::from_parts(ptr, length, capacity) } #[allow(missing_doc)] @@ -571,6 +571,7 @@ impl Add for String { pub mod raw { use core::mem; + use core::ptr::RawPtr; use core::raw::Slice; use super::String; @@ -582,21 +583,13 @@ pub mod raw { /// * We call `Vec::from_raw_parts` to get a `Vec` /// * We assume that the `Vec` contains valid UTF-8 #[inline] - pub unsafe fn from_parts(length: uint, capacity: uint, ptr: *mut u8) -> String { + pub unsafe fn from_parts(buf: *mut u8, length: uint, capacity: uint) -> String { String { - vec: Vec::from_raw_parts(length, capacity, ptr), + vec: Vec::from_raw_parts(length, capacity, buf), } } - /// 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. - #[inline] - pub unsafe fn from_utf8(bytes: Vec) -> String { - String { vec: bytes } - } - - /// Create a Rust string from a *u8 buffer of the given length + /// Create `String` from a *u8 buffer of the given length /// /// This function is unsafe because of two reasons: /// * A raw pointer is dereferenced and transmuted to `&[u8]` @@ -609,6 +602,27 @@ pub mod raw { }); self::from_utf8(slice.to_vec()) } + + /// Create a `String` from a null-terminated *u8 buffer + /// + /// This function is unsafe because we dereference memory until we find the NUL character, + /// which is not guaranteed to be present. Additionaly, the slice is not checked to see + /// whether it contains valid UTF-8 + pub unsafe fn from_buf(buf: *const u8) -> String { + let mut len = 0; + while *buf.offset(len) != 0 { + len += 1; + } + self::from_buf_len(buf, len as uint) + } + + /// 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. + #[inline] + pub unsafe fn from_utf8(bytes: Vec) -> String { + String { vec: bytes } + } } #[cfg(test)] @@ -776,6 +790,16 @@ mod tests { } } + #[test] + fn test_from_buf() { + unsafe { + let a = vec![65, 65, 65, 65, 65, 65, 65, 0]; + let b = a.as_ptr(); + let c = super::raw::from_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/librustc/middle/trans/type_.rs b/src/librustc/middle/trans/type_.rs index 3833d4cd0c8..e9d92e45f62 100644 --- a/src/librustc/middle/trans/type_.rs +++ b/src/librustc/middle/trans/type_.rs @@ -19,8 +19,9 @@ use middle::trans::context::CrateContext; use syntax::ast; use syntax::abi::{X86, X86_64, Arm, Mips, Mipsel}; -use std::c_str::{CString, ToCStr}; +use std::c_str::ToCStr; use std::mem; +use std::string; use std::cell::RefCell; use std::collections::HashMap; @@ -333,7 +334,7 @@ impl TypeNames { pub fn type_to_string(&self, ty: Type) -> String { unsafe { let s = llvm::LLVMTypeToString(ty.to_ref()); - let ret = CString::new(s, false).as_str().unwrap().to_string(); + let ret = string::raw::from_buf(s as *const u8); free(s as *mut c_void); ret } @@ -347,7 +348,7 @@ impl TypeNames { pub fn val_to_string(&self, val: ValueRef) -> String { unsafe { let s = llvm::LLVMValueToString(val); - let ret = CString::new(s, false).as_str().unwrap().to_string(); + let ret = string::raw::from_buf(s as *const u8); free(s as *mut c_void); ret } diff --git a/src/librustuv/lib.rs b/src/librustuv/lib.rs index dc43a68e64d..4d23397cd38 100644 --- a/src/librustuv/lib.rs +++ b/src/librustuv/lib.rs @@ -55,10 +55,10 @@ extern crate libc; extern crate alloc; use libc::{c_int, c_void}; -use std::c_str::CString; use std::fmt; use std::mem; use std::ptr; +use std::string; use std::rt::local::Local; use std::rt::rtio; use std::rt::rtio::{IoResult, IoError}; @@ -363,7 +363,7 @@ impl UvError { let inner = match self { &UvError(a) => a }; let name_str = uvll::uv_err_name(inner); assert!(name_str.is_not_null()); - CString::new(name_str, false).as_str().unwrap().to_string() + string::raw::from_buf(name_str as *const u8) } } @@ -372,7 +372,7 @@ impl UvError { let inner = match self { &UvError(a) => a }; let desc_str = uvll::uv_strerror(inner); assert!(desc_str.is_not_null()); - CString::new(desc_str, false).as_str().unwrap().to_string() + string::raw::from_buf(desc_str as *const u8) } } diff --git a/src/libstd/os.rs b/src/libstd/os.rs index d2a2d9ff64b..ebcb60253f5 100644 --- a/src/libstd/os.rs +++ b/src/libstd/os.rs @@ -49,7 +49,6 @@ use slice::{Vector, ImmutableVector, MutableVector, ImmutableEqVector}; use str::{Str, StrSlice, StrAllocating}; use string::String; use sync::atomics::{AtomicInt, INIT_ATOMIC_INT, SeqCst}; -use to_string::ToString; use vec::Vec; #[cfg(unix)] @@ -998,7 +997,7 @@ pub fn error_string(errnum: uint) -> String { fail!("strerror_r failure"); } - ::c_str::CString::new(p as *const c_char, false).as_str().unwrap().to_string() + ::string::raw::from_buf(p as *const u8) } } From 8836048c76a867f3feee95887d54bd93cc261f41 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adolfo=20Ochagav=C3=ADa?= Date: Mon, 21 Jul 2014 16:04:24 +0200 Subject: [PATCH 09/23] Fix deprecation warning in deque.rs --- src/libcollections/deque.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libcollections/deque.rs b/src/libcollections/deque.rs index 1faa9be99e3..c56b265b43a 100644 --- a/src/libcollections/deque.rs +++ b/src/libcollections/deque.rs @@ -71,7 +71,7 @@ pub mod bench { // measure let mut i = 0; b.iter(|| { - map.find(keys.get(i)); + map.find(&keys[i]); i = (i + 1) % n; }) } From 6988bcd74c6ab85d0a5f85c8b96c61f7fb75ad1d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adolfo=20Ochagav=C3=ADa?= Date: Mon, 21 Jul 2014 18:06:24 +0200 Subject: [PATCH 10/23] Implement Show for CString We use use `from_utf8_lossy` to convert it to a MaybeOwned string, to avoid failing in case the CString contains invalid UTF-8 --- src/librustrt/c_str.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/librustrt/c_str.rs b/src/librustrt/c_str.rs index 0f2fcaff310..c30b267219b 100644 --- a/src/librustrt/c_str.rs +++ b/src/librustrt/c_str.rs @@ -73,6 +73,7 @@ use collections::hash; use core::kinds::marker; use core::mem; use core::ptr; +use core::fmt; use core::raw::Slice; use core::slice; use core::str; @@ -344,6 +345,12 @@ impl Collection for CString { } } +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 { /// Copy the receiver into a CString. From 4ea1dd54943bb208d585c7ae8138df5699995a77 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adolfo=20Ochagav=C3=ADa?= Date: Tue, 22 Jul 2014 18:24:33 +0200 Subject: [PATCH 11/23] Add a null pointer check to CString::new This also removes checks in other methods of `CString` Breaking changes: * `CString::new` now fails if `buf` is null. To avoid this add a check before creatng a new `CString` . * The `is_null` and `is_not_null` methods are deprecated, because a `CString` cannot be null. * Other methods which used to fail if the `CString` was null do not fail anymore [breaking-change] --- src/libnative/io/addrinfo.rs | 10 +-- src/librustrt/c_str.rs | 123 ++++------------------------------- 2 files changed, 19 insertions(+), 114 deletions(-) diff --git a/src/libnative/io/addrinfo.rs b/src/libnative/io/addrinfo.rs index 0977b55d8b9..343fe05ed42 100644 --- a/src/libnative/io/addrinfo.rs +++ b/src/libnative/io/addrinfo.rs @@ -10,7 +10,6 @@ use libc::{c_char, c_int}; use libc; -use std::c_str::CString; use std::mem; use std::ptr::{null, mut_null}; use std::rt::rtio; @@ -27,8 +26,8 @@ impl GetAddrInfoRequest { { assert!(host.is_some() || servname.is_some()); - let c_host = host.map_or(unsafe { CString::new(null(), true) }, |x| x.to_c_str()); - let c_serv = servname.map_or(unsafe { CString::new(null(), true) }, |x| x.to_c_str()); + let c_host = host.map(|x| x.to_c_str()); + let c_serv = servname.map(|x| x.to_c_str()); let hint = hint.map(|hint| { libc::addrinfo { @@ -50,8 +49,8 @@ impl GetAddrInfoRequest { // Make the call let s = unsafe { - let ch = if c_host.is_null() { null() } else { c_host.as_ptr() }; - let cs = if c_serv.is_null() { null() } else { c_serv.as_ptr() }; + let ch = if c_host.is_none() { null() } else { c_host.unwrap().as_ptr() }; + let cs = if c_serv.is_none() { null() } else { c_serv.unwrap().as_ptr() }; getaddrinfo(ch, cs, hint_ptr, &mut res) }; @@ -104,6 +103,7 @@ fn get_error(_: c_int) -> IoError { #[cfg(not(windows))] fn get_error(s: c_int) -> IoError { + use std::c_str::CString; let err_str = unsafe { CString::new(gai_strerror(s), false).as_str().unwrap().to_string() diff --git a/src/librustrt/c_str.rs b/src/librustrt/c_str.rs index c30b267219b..5dd61c03d17 100644 --- a/src/librustrt/c_str.rs +++ b/src/librustrt/c_str.rs @@ -70,10 +70,10 @@ use core::prelude::*; use alloc::libc_heap::malloc_raw; use collections::string::String; use collections::hash; +use core::fmt; use core::kinds::marker; use core::mem; use core::ptr; -use core::fmt; use core::raw::Slice; use core::slice; use core::str; @@ -93,23 +93,18 @@ impl Clone for CString { /// reasons, this is always a deep clone, rather than the usual shallow /// clone. fn clone(&self) -> CString { - if self.buf.is_null() { - CString { buf: self.buf, owns_buffer_: self.owns_buffer_ } - } else { - let len = self.len() + 1; - let buf = unsafe { malloc_raw(len) } as *mut libc::c_char; - unsafe { ptr::copy_nonoverlapping_memory(buf, self.buf, len); } - CString { buf: buf as *const libc::c_char, owns_buffer_: true } - } + let len = self.len() + 1; + let buf = unsafe { malloc_raw(len) } as *mut libc::c_char; + 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 if self.buf.is_null() || other.buf.is_null() { - false } else { unsafe { libc::strcmp(self.buf, other.buf) == 0 @@ -136,7 +131,12 @@ impl hash::Hash for CString { impl CString { /// Create a C String from a pointer. + /// + ///# Failure + /// + /// Fails 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 } } @@ -158,10 +158,6 @@ impl CString { /// let p = foo.to_c_str().as_ptr(); /// ``` /// - /// # Failure - /// - /// Fails if the CString is null. - /// /// # Example /// /// ```rust @@ -175,8 +171,6 @@ impl CString { /// } /// ``` pub fn as_ptr(&self) -> *const libc::c_char { - if self.buf.is_null() { fail!("CString is null!"); } - self.buf } @@ -197,44 +191,30 @@ impl CString { /// // wrong (the CString will be freed, invalidating `p`) /// let p = foo.to_c_str().as_mut_ptr(); /// ``` - /// - /// # Failure - /// - /// Fails if the CString is null. pub fn as_mut_ptr(&mut self) -> *mut libc::c_char { - if self.buf.is_null() { fail!("CString is null!") } - self.buf as *mut _ } /// Calls a closure with a reference to the underlying `*libc::c_char`. - /// - /// # Failure - /// - /// Fails if the CString is null. #[deprecated="use `.as_ptr()`"] pub fn with_ref(&self, f: |*const libc::c_char| -> T) -> T { - if self.buf.is_null() { fail!("CString is null!"); } f(self.buf) } /// Calls a closure with a mutable reference to the underlying `*libc::c_char`. - /// - /// # Failure - /// - /// Fails if the CString is null. #[deprecated="use `.as_mut_ptr()`"] pub fn with_mut_ref(&mut self, f: |*mut libc::c_char| -> T) -> T { - if self.buf.is_null() { fail!("CString is null!"); } f(self.buf as *mut libc::c_char) } /// Returns true if the CString is a null. + #[deprecated="a CString cannot be null"] pub fn is_null(&self) -> bool { self.buf.is_null() } /// Returns true if the CString is not null. + #[deprecated="a CString cannot be null"] pub fn is_not_null(&self) -> bool { self.buf.is_not_null() } @@ -246,13 +226,8 @@ impl CString { /// Converts the CString into a `&[u8]` without copying. /// Includes the terminating NUL byte. - /// - /// # Failure - /// - /// Fails if the CString is null. #[inline] pub fn as_bytes<'a>(&'a self) -> &'a [u8] { - if self.buf.is_null() { fail!("CString is null!"); } unsafe { mem::transmute(Slice { data: self.buf, len: self.len() + 1 }) } @@ -260,13 +235,8 @@ impl CString { /// Converts the CString into a `&[u8]` without copying. /// Does not include the terminating NUL byte. - /// - /// # Failure - /// - /// Fails if the CString is null. #[inline] pub fn as_bytes_no_nul<'a>(&'a self) -> &'a [u8] { - if self.buf.is_null() { fail!("CString is null!"); } unsafe { mem::transmute(Slice { data: self.buf, len: self.len() }) } @@ -274,10 +244,6 @@ impl CString { /// Converts the CString into a `&str` without copying. /// Returns None if the CString is not UTF-8. - /// - /// # Failure - /// - /// Fails if the CString is null. #[inline] pub fn as_str<'a>(&'a self) -> Option<&'a str> { let buf = self.as_bytes_no_nul(); @@ -285,12 +251,7 @@ impl CString { } /// Return a CString iterator. - /// - /// # Failure - /// - /// Fails if the CString is null. pub fn iter<'a>(&'a self) -> CChars<'a> { - if self.buf.is_null() { fail!("CString is null!"); } CChars { ptr: self.buf, marker: marker::ContravariantLifetime, @@ -326,13 +287,8 @@ impl Drop for CString { impl Collection for CString { /// Return the number of bytes in the CString (not including the NUL terminator). - /// - /// # Failure - /// - /// Fails if the CString is null. #[inline] fn len(&self) -> uint { - if self.buf.is_null() { fail!("CString is null!"); } let mut cur = self.buf; let mut len = 0; unsafe { @@ -631,13 +587,6 @@ mod tests { } } - #[test] - fn test_is_null() { - let c_str = unsafe { CString::new(ptr::null(), false) }; - assert!(c_str.is_null()); - assert!(!c_str.is_not_null()); - } - #[test] fn test_unwrap() { let c_str = "hello".to_c_str(); @@ -648,16 +597,8 @@ mod tests { fn test_as_ptr() { let c_str = "hello".to_c_str(); let len = unsafe { libc::strlen(c_str.as_ptr()) }; - assert!(!c_str.is_null()); - assert!(c_str.is_not_null()); assert_eq!(len, 5); } - #[test] - #[should_fail] - fn test_as_ptr_empty_fail() { - let c_str = unsafe { CString::new(ptr::null(), false) }; - c_str.as_ptr(); - } #[test] fn test_iterator() { @@ -716,20 +657,6 @@ mod tests { assert_eq!(c_str.as_bytes_no_nul(), b"foo\xFF"); } - #[test] - #[should_fail] - fn test_as_bytes_fail() { - let c_str = unsafe { CString::new(ptr::null(), false) }; - c_str.as_bytes(); - } - - #[test] - #[should_fail] - fn test_as_bytes_no_nul_fail() { - let c_str = unsafe { CString::new(ptr::null(), false) }; - c_str.as_bytes_no_nul(); - } - #[test] fn test_as_str() { let c_str = "hello".to_c_str(); @@ -742,23 +669,8 @@ mod tests { #[test] #[should_fail] - fn test_as_str_fail() { + fn test_new_fail() { let c_str = unsafe { CString::new(ptr::null(), false) }; - c_str.as_str(); - } - - #[test] - #[should_fail] - fn test_len_fail() { - let c_str = unsafe { CString::new(ptr::null(), false) }; - c_str.len(); - } - - #[test] - #[should_fail] - fn test_iter_fail() { - let c_str = unsafe { CString::new(ptr::null(), false) }; - c_str.iter(); } #[test] @@ -791,13 +703,6 @@ mod tests { // force a copy, reading the memory c_.as_bytes().to_vec(); } - - #[test] - fn test_clone_eq_null() { - let x = unsafe { CString::new(ptr::null(), false) }; - let y = x.clone(); - assert!(x == y); - } } #[cfg(test)] From 57cade574418e9507c67ba5177bc177cc7771721 Mon Sep 17 00:00:00 2001 From: Valerii Hiora Date: Wed, 23 Jul 2014 09:14:58 +0300 Subject: [PATCH 12/23] Updated LLVM for iOS There should be no more problems during SjLj pass --- src/llvm | 2 +- src/rustllvm/RustWrapper.cpp | 11 ++++++----- src/rustllvm/llvm-auto-clean-trigger | 2 +- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/llvm b/src/llvm index d66318a4aae..cd24b5c6633 160000 --- a/src/llvm +++ b/src/llvm @@ -1 +1 @@ -Subproject commit d66318a4aae089bae5c3c38ee42daaa1bd8fadb7 +Subproject commit cd24b5c6633b27df2b84249a65a46a610b734494 diff --git a/src/rustllvm/RustWrapper.cpp b/src/rustllvm/RustWrapper.cpp index a1a88d1b14d..a4437ea7c7b 100644 --- a/src/rustllvm/RustWrapper.cpp +++ b/src/rustllvm/RustWrapper.cpp @@ -658,13 +658,14 @@ LLVMRustLinkInExternalBitcode(LLVMModuleRef dst, char *bc, size_t len) { #if LLVM_VERSION_MINOR >= 5 extern "C" void* LLVMRustOpenArchive(char *path) { - std::unique_ptr buf; - std::error_code err = MemoryBuffer::getFile(path, buf); - if (err) { - LLVMRustSetLastError(err.message().c_str()); + ErrorOr> buf_or = MemoryBuffer::getFile(path); + if (!buf_or) { + LLVMRustSetLastError(buf_or.getError().message().c_str()); return NULL; } - Archive *ret = new Archive(buf.release(), err); + + std::error_code err; + Archive *ret = new Archive(std::move(buf_or.get()), err); if (err) { LLVMRustSetLastError(err.message().c_str()); return NULL; diff --git a/src/rustllvm/llvm-auto-clean-trigger b/src/rustllvm/llvm-auto-clean-trigger index fd5c87db22c..bdc5bfdc10a 100644 --- a/src/rustllvm/llvm-auto-clean-trigger +++ b/src/rustllvm/llvm-auto-clean-trigger @@ -1,4 +1,4 @@ # If this file is modified, then llvm will be forcibly cleaned and then rebuilt. # The actual contents of this file do not matter, but to trigger a change on the # build bots then the contents should be changed so git updates the mtime. -2014-07-21 +2014-07-22 From bb165eb5c21b057cb63a4421d6233e82deac4cba Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Wed, 23 Jul 2014 10:21:50 -0700 Subject: [PATCH 13/23] libsyntax: Remove `~self` and `mut ~self` from the language. This eliminates the last vestige of the `~` syntax. Instead of `~self`, write `self: Box`; instead of `mut ~self`, write `mut self: Box`, replacing `TypeOfSelf` with the self-type parameter as specified in the implementation. Closes #13885. [breaking-change] --- src/doc/rust.md | 4 +-- src/doc/tutorial.md | 6 ++--- src/libgreen/sched.rs | 38 +++++++++++++++------------ src/libgreen/simple.rs | 14 +++++----- src/libgreen/task.rs | 24 +++++++++-------- src/libnative/io/net.rs | 3 ++- src/libnative/io/pipe_unix.rs | 3 ++- src/libnative/io/pipe_win32.rs | 3 ++- src/libnative/task.rs | 14 +++++----- src/librustc/middle/typeck/astconv.rs | 1 - src/librustdoc/clean/mod.rs | 1 - src/librustdoc/html/format.rs | 2 +- src/librustrt/lib.rs | 14 +++++----- src/librustrt/rtio.rs | 4 +-- src/librustrt/task.rs | 19 ++++++++------ src/librustuv/lib.rs | 2 +- src/librustuv/net.rs | 3 ++- src/librustuv/pipe.rs | 3 ++- src/libsyntax/ast.rs | 2 -- src/libsyntax/fold.rs | 2 +- src/libsyntax/parse/obsolete.rs | 5 ++++ src/libsyntax/parse/parser.rs | 15 ++++++----- src/libsyntax/print/pprust.rs | 3 --- src/libsyntax/visit.rs | 2 +- 24 files changed, 104 insertions(+), 83 deletions(-) diff --git a/src/doc/rust.md b/src/doc/rust.md index 9fe61eb3fe3..b015cb0fbb8 100644 --- a/src/doc/rust.md +++ b/src/doc/rust.md @@ -3864,13 +3864,13 @@ Function parameters are immutable unless declared with `mut`. The and `fn f(mut x: Box, y: Box)` declare one mutable variable `x` and one immutable variable `y`). -Methods that take either `self` or `~self` can optionally place them in a +Methods that take either `self` or `Box` can optionally place them in a mutable slot by prefixing them with `mut` (similar to regular arguments): ~~~ trait Changer { fn change(mut self) -> Self; - fn modify(mut ~self) -> Box; + fn modify(mut self: Box) -> Box; } ~~~ diff --git a/src/doc/tutorial.md b/src/doc/tutorial.md index 2b85bc50de3..b6485f711ee 100644 --- a/src/doc/tutorial.md +++ b/src/doc/tutorial.md @@ -1971,7 +1971,7 @@ like any other function, except for the name `self`. The type of `self` is the type on which the method is implemented, or a pointer thereof. As an argument it is written either `self`, -`&self`, or `~self`. +`&self`, or `self: TYPE`. A caller must in turn have a compatible pointer type to call the method. ~~~ @@ -1984,7 +1984,7 @@ A caller must in turn have a compatible pointer type to call the method. # } impl Shape { fn draw_reference(&self) { /* ... */ } - fn draw_owned(~self) { /* ... */ } + fn draw_owned(self: Box) { /* ... */ } fn draw_value(self) { /* ... */ } } @@ -2009,7 +2009,7 @@ to a reference. # } # impl Shape { # fn draw_reference(&self) { /* ... */ } -# fn draw_owned(~self) { /* ... */ } +# fn draw_owned(self: Box) { /* ... */ } # fn draw_value(self) { /* ... */ } # } # let s = Circle(Point { x: 1.0, y: 2.0 }, 3.0); diff --git a/src/libgreen/sched.rs b/src/libgreen/sched.rs index 7151a78eacd..38bb6e355a7 100644 --- a/src/libgreen/sched.rs +++ b/src/libgreen/sched.rs @@ -180,7 +180,7 @@ impl Scheduler { // Take a main task to run, and a scheduler to run it in. Create a // scheduler task and bootstrap into it. - pub fn bootstrap(mut ~self) { + pub fn bootstrap(mut self: Box) { // Build an Idle callback. let cb = box SchedRunner as Box; @@ -224,7 +224,8 @@ impl Scheduler { // This does not return a scheduler, as the scheduler is placed // inside the task. - pub fn run(mut ~self, stask: Box) -> Box { + pub fn run(mut self: Box, stask: Box) + -> Box { // This is unsafe because we need to place the scheduler, with // the event_loop inside, inside our task. But we still need a @@ -271,7 +272,7 @@ impl Scheduler { // If we try really hard to do some work, but no work is available to be // done, then we fall back to epoll() to block this thread waiting for more // work (instead of busy waiting). - fn run_sched_once(mut ~self, stask: Box) { + fn run_sched_once(mut self: Box, stask: Box) { // Make sure that we're not lying in that the `stask` argument is indeed // the scheduler task for this scheduler. assert!(self.sched_task.is_none()); @@ -349,11 +350,10 @@ impl Scheduler { // returns the still-available scheduler. At this point all // message-handling will count as a turn of work, and as a result // return None. - fn interpret_message_queue(mut ~self, stask: Box, + fn interpret_message_queue(mut self: Box, + stask: Box, effort: EffortLevel) - -> (Box, Box, bool) - { - + -> (Box, Box, bool) { let msg = if effort == DontTryTooHard { self.message_queue.casual_pop() } else { @@ -432,7 +432,7 @@ impl Scheduler { } } - fn do_work(mut ~self, stask: Box) + fn do_work(mut self: Box, stask: Box) -> (Box, Box, bool) { rtdebug!("scheduler calling do work"); match self.find_work() { @@ -517,7 +517,7 @@ impl Scheduler { // * Task Routing Functions - Make sure tasks send up in the right // place. - fn process_task(mut ~self, + fn process_task(mut self: Box, cur: Box, mut next: Box, schedule_fn: SchedulingFn) @@ -610,7 +610,7 @@ impl Scheduler { // cleanup function f, which takes the scheduler and the // old task as inputs. - pub fn change_task_context(mut ~self, + pub fn change_task_context(mut self: Box, mut current_task: Box, mut next_task: Box, f: |&mut Scheduler, Box|) @@ -693,7 +693,7 @@ impl Scheduler { // * Context Swapping Helpers - Here be ugliness! - pub fn resume_task_immediately(~self, + pub fn resume_task_immediately(self: Box, cur: Box, next: Box) -> (Box, Box) { @@ -733,7 +733,7 @@ impl Scheduler { /// This situation is currently prevented, or in other words it is /// guaranteed that this function will not return before the given closure /// has returned. - pub fn deschedule_running_task_and_then(mut ~self, + pub fn deschedule_running_task_and_then(mut self: Box, cur: Box, f: |&mut Scheduler, BlockedTask|) { // Trickier - we need to get the scheduler task out of self @@ -743,7 +743,7 @@ impl Scheduler { self.switch_running_tasks_and_then(cur, stask, f) } - pub fn switch_running_tasks_and_then(~self, + pub fn switch_running_tasks_and_then(self: Box, cur: Box, next: Box, f: |&mut Scheduler, BlockedTask|) { @@ -795,7 +795,9 @@ impl Scheduler { /// Called by a running task to end execution, after which it will /// be recycled by the scheduler for reuse in a new task. - pub fn terminate_current_task(mut ~self, cur: Box) -> ! { + pub fn terminate_current_task(mut self: Box, + cur: Box) + -> ! { // Similar to deschedule running task and then, but cannot go through // the task-blocking path. The task is already dying. let stask = self.sched_task.take_unwrap(); @@ -807,7 +809,9 @@ impl Scheduler { fail!("should never return!"); } - pub fn run_task(~self, cur: Box, next: Box) { + pub fn run_task(self: Box, + cur: Box, + next: Box) { let (sched, task) = self.process_task(cur, next, Scheduler::switch_task); task.put_with_sched(sched); @@ -823,7 +827,7 @@ impl Scheduler { /// to introduce some amount of randomness to the scheduler. Currently the /// randomness is a result of performing a round of work stealing (which /// may end up stealing from the current scheduler). - pub fn yield_now(mut ~self, cur: Box) { + pub fn yield_now(mut self: Box, cur: Box) { // Async handles trigger the scheduler by calling yield_now on the local // task, which eventually gets us to here. See comments in SchedRunner // for more info on this. @@ -842,7 +846,7 @@ impl Scheduler { } } - pub fn maybe_yield(mut ~self, cur: Box) { + pub fn maybe_yield(mut self: Box, cur: Box) { // It's possible for sched tasks to possibly call this function, and it // just means that they're likely sending on channels (which // occasionally call this function). Sched tasks follow different paths diff --git a/src/libgreen/simple.rs b/src/libgreen/simple.rs index 874ddbfe7ed..6254e8c55f0 100644 --- a/src/libgreen/simple.rs +++ b/src/libgreen/simple.rs @@ -27,7 +27,9 @@ struct SimpleTask { impl Runtime for SimpleTask { // Implement the simple tasks of descheduling and rescheduling, but only in // a simple number of cases. - fn deschedule(mut ~self, times: uint, mut cur_task: Box, + fn deschedule(mut self: Box, + times: uint, + mut cur_task: Box, f: |BlockedTask| -> Result<(), BlockedTask>) { assert!(times == 1); @@ -54,7 +56,7 @@ impl Runtime for SimpleTask { } Local::put(cur_task); } - fn reawaken(mut ~self, mut to_wake: Box) { + fn reawaken(mut self: Box, mut to_wake: Box) { let me = &mut *self as *mut SimpleTask; to_wake.put_runtime(self); unsafe { @@ -69,9 +71,9 @@ impl Runtime for SimpleTask { // purpose. A "simple task" is just that, a very simple task that can't // really do a whole lot. The only purpose of the task is to get us off our // feet and running. - fn yield_now(~self, _cur_task: Box) { fail!() } - fn maybe_yield(~self, _cur_task: Box) { fail!() } - fn spawn_sibling(~self, + fn yield_now(self: Box, _cur_task: Box) { fail!() } + fn maybe_yield(self: Box, _cur_task: Box) { fail!() } + fn spawn_sibling(self: Box, _cur_task: Box, _opts: TaskOpts, _f: proc():Send) { @@ -80,7 +82,7 @@ impl Runtime for SimpleTask { fn local_io<'a>(&'a mut self) -> Option> { None } fn stack_bounds(&self) -> (uint, uint) { fail!() } fn can_block(&self) -> bool { true } - fn wrap(~self) -> Box { fail!() } + fn wrap(self: Box) -> Box { fail!() } } pub fn task() -> Box { diff --git a/src/libgreen/task.rs b/src/libgreen/task.rs index 68a454233cf..3d3b4133840 100644 --- a/src/libgreen/task.rs +++ b/src/libgreen/task.rs @@ -265,7 +265,7 @@ impl GreenTask { // Runtime glue functions and helpers - pub fn put_with_sched(mut ~self, sched: Box) { + pub fn put_with_sched(mut self: Box, sched: Box) { assert!(self.sched.is_none()); self.sched = Some(sched); self.put(); @@ -276,18 +276,18 @@ impl GreenTask { self.task = Some(task); } - pub fn swap(mut ~self) -> Box { + pub fn swap(mut self: Box) -> Box { let mut task = self.task.take_unwrap(); task.put_runtime(self); return task; } - pub fn put(~self) { + pub fn put(self: Box) { assert!(self.sched.is_some()); Local::put(self.swap()); } - fn terminate(mut ~self) -> ! { + fn terminate(mut self: Box) -> ! { let sched = self.sched.take_unwrap(); sched.terminate_current_task(self) } @@ -311,7 +311,7 @@ impl GreenTask { // *not* a cheap operation to clone a handle. Until the day comes that we // need to optimize this, a lock should do just fine (it's completely // uncontended except for when the task is rescheduled). - fn reawaken_remotely(mut ~self) { + fn reawaken_remotely(mut self: Box) { unsafe { let mtx = &mut self.nasty_deschedule_lock as *mut NativeMutex; let handle = self.handle.get_mut_ref() as *mut SchedHandle; @@ -322,19 +322,21 @@ impl GreenTask { } impl Runtime for GreenTask { - fn yield_now(mut ~self, cur_task: Box) { + fn yield_now(mut self: Box, cur_task: Box) { self.put_task(cur_task); let sched = self.sched.take_unwrap(); sched.yield_now(self); } - fn maybe_yield(mut ~self, cur_task: Box) { + fn maybe_yield(mut self: Box, cur_task: Box) { self.put_task(cur_task); let sched = self.sched.take_unwrap(); sched.maybe_yield(self); } - fn deschedule(mut ~self, times: uint, cur_task: Box, + fn deschedule(mut self: Box, + times: uint, + cur_task: Box, f: |BlockedTask| -> Result<(), BlockedTask>) { self.put_task(cur_task); let mut sched = self.sched.take_unwrap(); @@ -383,7 +385,7 @@ impl Runtime for GreenTask { } } - fn reawaken(mut ~self, to_wake: Box) { + fn reawaken(mut self: Box, to_wake: Box) { self.put_task(to_wake); assert!(self.sched.is_none()); @@ -434,7 +436,7 @@ impl Runtime for GreenTask { } } - fn spawn_sibling(mut ~self, + fn spawn_sibling(mut self: Box, cur_task: Box, opts: TaskOpts, f: proc():Send) { @@ -471,7 +473,7 @@ impl Runtime for GreenTask { fn can_block(&self) -> bool { false } - fn wrap(~self) -> Box { self as Box } + fn wrap(self: Box) -> Box { self as Box } } #[cfg(test)] diff --git a/src/libnative/io/net.rs b/src/libnative/io/net.rs index f052826d303..c3eb5e91e90 100644 --- a/src/libnative/io/net.rs +++ b/src/libnative/io/net.rs @@ -484,7 +484,8 @@ impl TcpListener { } impl rtio::RtioTcpListener for TcpListener { - fn listen(~self) -> IoResult> { + fn listen(self: Box) + -> IoResult> { self.native_listen(128).map(|a| { box a as Box }) diff --git a/src/libnative/io/pipe_unix.rs b/src/libnative/io/pipe_unix.rs index 0e019fa7e8f..075ca769d07 100644 --- a/src/libnative/io/pipe_unix.rs +++ b/src/libnative/io/pipe_unix.rs @@ -229,7 +229,8 @@ impl UnixListener { } impl rtio::RtioUnixListener for UnixListener { - fn listen(~self) -> IoResult> { + fn listen(self: Box) + -> IoResult> { self.native_listen(128).map(|a| { box a as Box }) diff --git a/src/libnative/io/pipe_win32.rs b/src/libnative/io/pipe_win32.rs index ec40ff89bd2..79ca23abed2 100644 --- a/src/libnative/io/pipe_win32.rs +++ b/src/libnative/io/pipe_win32.rs @@ -588,7 +588,8 @@ impl Drop for UnixListener { } impl rtio::RtioUnixListener for UnixListener { - fn listen(~self) -> IoResult> { + fn listen(self: Box) + -> IoResult> { self.native_listen().map(|a| { box a as Box }) diff --git a/src/libnative/task.rs b/src/libnative/task.rs index 7ba588ac21c..35367ff2efa 100644 --- a/src/libnative/task.rs +++ b/src/libnative/task.rs @@ -131,21 +131,21 @@ struct Ops { } impl rt::Runtime for Ops { - fn yield_now(~self, mut cur_task: Box) { + fn yield_now(self: Box, mut cur_task: Box) { // put the task back in TLS and then invoke the OS thread yield cur_task.put_runtime(self); Local::put(cur_task); Thread::yield_now(); } - fn maybe_yield(~self, mut cur_task: Box) { + fn maybe_yield(self: Box, mut cur_task: Box) { // just put the task back in TLS, on OS threads we never need to // opportunistically yield b/c the OS will do that for us (preemption) cur_task.put_runtime(self); Local::put(cur_task); } - fn wrap(~self) -> Box { + fn wrap(self: Box) -> Box { self as Box } @@ -192,7 +192,9 @@ impl rt::Runtime for Ops { // `awoken` field which indicates whether we were actually woken up via some // invocation of `reawaken`. This flag is only ever accessed inside the // lock, so there's no need to make it atomic. - fn deschedule(mut ~self, times: uint, mut cur_task: Box, + fn deschedule(mut self: Box, + times: uint, + mut cur_task: Box, f: |BlockedTask| -> Result<(), BlockedTask>) { let me = &mut *self as *mut Ops; cur_task.put_runtime(self); @@ -250,7 +252,7 @@ impl rt::Runtime for Ops { // See the comments on `deschedule` for why the task is forgotten here, and // why it's valid to do so. - fn reawaken(mut ~self, mut to_wake: Box) { + fn reawaken(mut self: Box, mut to_wake: Box) { unsafe { let me = &mut *self as *mut Ops; to_wake.put_runtime(self); @@ -261,7 +263,7 @@ impl rt::Runtime for Ops { } } - fn spawn_sibling(~self, + fn spawn_sibling(self: Box, mut cur_task: Box, opts: TaskOpts, f: proc():Send) { diff --git a/src/librustc/middle/typeck/astconv.rs b/src/librustc/middle/typeck/astconv.rs index e129492dbc2..8f450fe3d76 100644 --- a/src/librustc/middle/typeck/astconv.rs +++ b/src/librustc/middle/typeck/astconv.rs @@ -1051,7 +1051,6 @@ fn determine_explicit_self_category ty::ByBoxExplicitSelfCategory, ast::SelfExplicit(ast_type, _) => { let explicit_type = ast_ty_to_ty(this, rscope, &*ast_type); diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 3cb2e9c6ec9..57cda6c4817 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -779,7 +779,6 @@ impl Clean for ast::ExplicitSelf_ { match *self { ast::SelfStatic => SelfStatic, ast::SelfValue(_) => SelfValue, - ast::SelfUniq(_) => SelfOwned, ast::SelfRegion(lt, mt, _) => { SelfBorrowed(lt.clean(), mt.clean()) } diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index d0f9b37cc4c..e7f93703399 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -491,7 +491,7 @@ impl<'a> fmt::Show for Method<'a> { match *selfty { clean::SelfStatic => {}, clean::SelfValue => args.push_str("self"), - clean::SelfOwned => args.push_str("~self"), + clean::SelfOwned => args.push_str("self: Box"), clean::SelfBorrowed(Some(ref lt), mtbl) => { args.push_str(format!("&{} {}self", *lt, MutableSpace(mtbl)).as_slice()); diff --git a/src/librustrt/lib.rs b/src/librustrt/lib.rs index 2fe0c32153a..e2d7f91d1a6 100644 --- a/src/librustrt/lib.rs +++ b/src/librustrt/lib.rs @@ -74,15 +74,17 @@ pub mod unwind; pub trait Runtime { // Necessary scheduling functions, used for channels and blocking I/O // (sometimes). - fn yield_now(~self, cur_task: Box); - fn maybe_yield(~self, cur_task: Box); - fn deschedule(~self, times: uint, cur_task: Box, + fn yield_now(self: Box, cur_task: Box); + fn maybe_yield(self: Box, cur_task: Box); + fn deschedule(self: Box, + times: uint, + cur_task: Box, f: |BlockedTask| -> Result<(), BlockedTask>); - fn reawaken(~self, to_wake: Box); + fn reawaken(self: Box, to_wake: Box); // Miscellaneous calls which are very different depending on what context // you're in. - fn spawn_sibling(~self, + fn spawn_sibling(self: Box, cur_task: Box, opts: TaskOpts, f: proc():Send); @@ -92,7 +94,7 @@ pub trait Runtime { fn can_block(&self) -> bool; // FIXME: This is a serious code smell and this should not exist at all. - fn wrap(~self) -> Box; + fn wrap(self: Box) -> Box; } /// The default error code of the rust runtime if the main task fails instead diff --git a/src/librustrt/rtio.rs b/src/librustrt/rtio.rs index 81a033e4c98..134453659db 100644 --- a/src/librustrt/rtio.rs +++ b/src/librustrt/rtio.rs @@ -238,7 +238,7 @@ pub trait IoFactory { } pub trait RtioTcpListener : RtioSocket { - fn listen(~self) -> IoResult>; + fn listen(self: Box) -> IoResult>; } pub trait RtioTcpAcceptor : RtioSocket { @@ -329,7 +329,7 @@ pub trait RtioPipe { } pub trait RtioUnixListener { - fn listen(~self) -> IoResult>; + fn listen(self: Box) -> IoResult>; } pub trait RtioUnixAcceptor { diff --git a/src/librustrt/task.rs b/src/librustrt/task.rs index 78c32889277..d27a4f25b4e 100644 --- a/src/librustrt/task.rs +++ b/src/librustrt/task.rs @@ -203,7 +203,7 @@ impl Task { /// }).destroy(); /// # } /// ``` - pub fn run(~self, f: ||) -> Box { + pub fn run(self: Box, f: ||) -> Box { assert!(!self.is_destroyed(), "cannot re-use a destroyed task"); // First, make sure that no one else is in TLS. This does not allow @@ -239,7 +239,7 @@ impl Task { /// /// The returned task cannot be used for running any more code, but it may /// be used to extract the runtime as necessary. - pub fn destroy(~self) -> Box { + pub fn destroy(self: Box) -> Box { if self.is_destroyed() { self } else { @@ -252,7 +252,7 @@ impl Task { /// This function consumes ownership of the task, deallocating it once it's /// done being processed. It is assumed that TLD and the local heap have /// already been destroyed and/or annihilated. - fn cleanup(~self, result: Result) -> Box { + fn cleanup(self: Box, result: Result) -> Box { // The first thing to do when cleaning up is to deallocate our local // resources, such as TLD and GC data. // @@ -394,7 +394,9 @@ impl Task { /// Spawns a sibling to this task. The newly spawned task is configured with /// the `opts` structure and will run `f` as the body of its code. - pub fn spawn_sibling(mut ~self, opts: TaskOpts, f: proc(): Send) { + pub fn spawn_sibling(mut self: Box, + opts: TaskOpts, + f: proc(): Send) { let ops = self.imp.take_unwrap(); ops.spawn_sibling(self, opts, f) } @@ -402,7 +404,8 @@ impl Task { /// Deschedules the current task, invoking `f` `amt` times. It is not /// recommended to use this function directly, but rather communication /// primitives in `std::comm` should be used. - pub fn deschedule(mut ~self, amt: uint, + pub fn deschedule(mut self: Box, + amt: uint, f: |BlockedTask| -> ::core::result::Result<(), BlockedTask>) { let ops = self.imp.take_unwrap(); ops.deschedule(amt, self, f) @@ -411,7 +414,7 @@ impl Task { /// Wakes up a previously blocked task, optionally specifying whether the /// current task can accept a change in scheduling. This function can only /// be called on tasks that were previously blocked in `deschedule`. - pub fn reawaken(mut ~self) { + pub fn reawaken(mut self: Box) { let ops = self.imp.take_unwrap(); ops.reawaken(self); } @@ -419,14 +422,14 @@ impl Task { /// Yields control of this task to another task. This function will /// eventually return, but possibly not immediately. This is used as an /// opportunity to allow other tasks a chance to run. - pub fn yield_now(mut ~self) { + pub fn yield_now(mut self: Box) { let ops = self.imp.take_unwrap(); ops.yield_now(self); } /// Similar to `yield_now`, except that this function may immediately return /// without yielding (depending on what the runtime decides to do). - pub fn maybe_yield(mut ~self) { + pub fn maybe_yield(mut self: Box) { let ops = self.imp.take_unwrap(); ops.maybe_yield(self); } diff --git a/src/librustuv/lib.rs b/src/librustuv/lib.rs index 4d23397cd38..24b8c297858 100644 --- a/src/librustuv/lib.rs +++ b/src/librustuv/lib.rs @@ -154,7 +154,7 @@ pub trait UvHandle { mem::transmute(uvll::get_data_for_uv_handle(*h)) } - fn install(~self) -> Box { + fn install(self: Box) -> Box { unsafe { let myptr = mem::transmute::<&Box, &*mut u8>(&self); uvll::set_data_for_uv_handle(self.uv_handle(), *myptr); diff --git a/src/librustuv/net.rs b/src/librustuv/net.rs index 45f93d9d128..3cc10ae3823 100644 --- a/src/librustuv/net.rs +++ b/src/librustuv/net.rs @@ -389,7 +389,8 @@ impl rtio::RtioSocket for TcpListener { } impl rtio::RtioTcpListener for TcpListener { - fn listen(~self) -> Result, IoError> { + fn listen(self: Box) + -> Result, IoError> { // create the acceptor object from ourselves let mut acceptor = box TcpAcceptor { listener: self, diff --git a/src/librustuv/pipe.rs b/src/librustuv/pipe.rs index 1c53814ac24..f0a57546ed4 100644 --- a/src/librustuv/pipe.rs +++ b/src/librustuv/pipe.rs @@ -248,7 +248,8 @@ impl PipeListener { } impl rtio::RtioUnixListener for PipeListener { - fn listen(~self) -> IoResult> { + fn listen(self: Box) + -> IoResult> { // create the acceptor object from ourselves let mut acceptor = box PipeAcceptor { listener: self, diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 614bbd1c3ed..f05d17569f6 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -955,8 +955,6 @@ pub enum ExplicitSelf_ { SelfValue(Ident), /// `&'lt self`, `&'lt mut self` SelfRegion(Option, Mutability, Ident), - /// `~self` - SelfUniq(Ident), /// `self: TYPE` SelfExplicit(P, Ident), } diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index 271eee7d08a..f48306bc6ee 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -340,7 +340,7 @@ pub trait Folder { fn fold_explicit_self_(&mut self, es: &ExplicitSelf_) -> ExplicitSelf_ { match *es { - SelfStatic | SelfValue(_) | SelfUniq(_) => *es, + SelfStatic | SelfValue(_) => *es, SelfRegion(ref lifetime, m, id) => { SelfRegion(fold_opt_lifetime(lifetime, self), m, id) } diff --git a/src/libsyntax/parse/obsolete.rs b/src/libsyntax/parse/obsolete.rs index ba401d313d8..afcf84753a6 100644 --- a/src/libsyntax/parse/obsolete.rs +++ b/src/libsyntax/parse/obsolete.rs @@ -31,6 +31,7 @@ pub enum ObsoleteSyntax { ObsoleteOwnedExpr, ObsoleteOwnedPattern, ObsoleteOwnedVector, + ObsoleteOwnedSelf, ObsoleteManagedType, ObsoleteManagedExpr, } @@ -70,6 +71,10 @@ impl<'a> ParserObsoleteMethods for parser::Parser<'a> { "`~[T]` is no longer a type", "use the `Vec` type instead" ), + ObsoleteOwnedSelf => ( + "`~self` is no longer supported", + "write `self: Box` instead" + ), ObsoleteManagedType => ( "`@` notation for managed pointers", "use `Gc` in `std::gc` instead" diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index bfc01afd457..ac363163673 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -45,7 +45,7 @@ use ast::{RetStyle, Return, BiShl, BiShr, Stmt, StmtDecl}; use ast::{StmtExpr, StmtSemi, StmtMac, StructDef, StructField}; use ast::{StructVariantKind, BiSub}; use ast::StrStyle; -use ast::{SelfExplicit, SelfRegion, SelfStatic, SelfUniq, SelfValue}; +use ast::{SelfExplicit, SelfRegion, SelfStatic, SelfValue}; use ast::{TokenTree, TraitMethod, TraitRef, TTDelim, TTSeq, TTTok}; use ast::{TTNonterminal, TupleVariantKind, Ty, Ty_, TyBot, TyBox}; use ast::{TypeField, TyFixedLengthVec, TyClosure, TyProc, TyBareFn}; @@ -3826,10 +3826,11 @@ impl<'a> Parser<'a> { // We need to make sure it isn't a type if self.look_ahead(1, |t| token::is_keyword(keywords::Self, t)) { self.bump(); - SelfUniq(self.expect_self_ident()) - } else { - SelfStatic + drop(self.expect_self_ident()); + let last_span = self.last_span; + self.obsolete(last_span, ObsoleteOwnedSelf) } + SelfStatic } token::IDENT(..) if self.is_self_ident() => { let self_ident = self.expect_self_ident(); @@ -3877,7 +3878,10 @@ impl<'a> Parser<'a> { self.look_ahead(2, |t| token::is_keyword(keywords::Self, t)) => { mutbl_self = self.parse_mutability(); self.bump(); - SelfUniq(self.expect_self_ident()) + drop(self.expect_self_ident()); + let last_span = self.last_span; + self.obsolete(last_span, ObsoleteOwnedSelf); + SelfStatic } _ => SelfStatic }; @@ -3921,7 +3925,6 @@ impl<'a> Parser<'a> { } SelfValue(id) => parse_remaining_arguments!(id), SelfRegion(_,_,id) => parse_remaining_arguments!(id), - SelfUniq(id) => parse_remaining_arguments!(id), SelfExplicit(_,id) => parse_remaining_arguments!(id), }; diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index 305e67a916e..ac835565191 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -1892,9 +1892,6 @@ impl<'a> State<'a> { ast::SelfValue(_) => { try!(word(&mut self.s, "self")); } - ast::SelfUniq(_) => { - try!(word(&mut self.s, "~self")); - } ast::SelfRegion(ref lt, m, _) => { try!(word(&mut self.s, "&")); try!(self.print_opt_lifetime(lt)); diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index 3c6f06ddfc3..371fae53b41 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -216,7 +216,7 @@ pub fn walk_explicit_self>(visitor: &mut V, explicit_self: &ExplicitSelf, env: E) { match explicit_self.node { - SelfStatic | SelfValue(_) | SelfUniq(_) => {}, + SelfStatic | SelfValue(_) => {}, SelfRegion(ref lifetime, _, _) => { visitor.visit_opt_lifetime_ref(explicit_self.span, lifetime, env) } From 62bddfa0a5bf7753f835aa9c299232eb75c7bdaa Mon Sep 17 00:00:00 2001 From: nham Date: Wed, 23 Jul 2014 15:57:30 -0400 Subject: [PATCH 14/23] Add examples for Checked[Add|Sub|Mul|Div] --- src/libcore/num/mod.rs | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index df90d81c57a..48a3db4258f 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -1217,6 +1217,14 @@ impl Saturating for T /// Performs addition that returns `None` instead of wrapping around on overflow. pub trait CheckedAdd: Add { /// Adds two numbers, checking for overflow. If overflow happens, `None` is returned. + /// + /// # Example + /// + /// ```rust + /// use std::num::CheckedAdd; + /// assert_eq!(5u16.checked_add(&65530), Some(65535)); + /// assert_eq!(6u16.checked_add(&65530), None); + /// ``` fn checked_add(&self, v: &Self) -> Option; } @@ -1270,6 +1278,14 @@ checked_impl!(CheckedAdd, checked_add, i64, intrinsics::i64_add_with_overflow) /// Performs subtraction that returns `None` instead of wrapping around on underflow. pub trait CheckedSub: Sub { /// Subtracts two numbers, checking for underflow. If underflow happens, `None` is returned. + /// + /// # Example + /// + /// ```rust + /// use std::num::CheckedSub; + /// assert_eq!((-127i8).checked_sub(&1), Some(-128)); + /// assert_eq!((-128i8).checked_sub(&1), None); + /// ``` fn checked_sub(&self, v: &Self) -> Option; } @@ -1298,6 +1314,14 @@ checked_impl!(CheckedSub, checked_sub, i64, intrinsics::i64_sub_with_overflow) pub trait CheckedMul: Mul { /// Multiplies two numbers, checking for underflow or overflow. If underflow or overflow /// happens, `None` is returned. + /// + /// # Example + /// + /// ```rust + /// use std::num::CheckedMul; + /// assert_eq!(5u8.checked_mul(&51), Some(255)); + /// assert_eq!(5u8.checked_mul(&52), None); + /// ``` fn checked_mul(&self, v: &Self) -> Option; } @@ -1325,6 +1349,14 @@ checked_impl!(CheckedMul, checked_mul, i64, intrinsics::i64_mul_with_overflow) pub trait CheckedDiv: Div { /// Divides two numbers, checking for underflow or overflow. If underflow or overflow happens, /// `None` is returned. + /// + /// # Example + /// + /// ```rust + /// use std::num::CheckedDiv; + /// assert_eq!((-127i8).checked_div(&-1), Some(127)); + /// assert_eq!((-128i8).checked_div(&-1), None); + /// ``` fn checked_div(&self, v: &Self) -> Option; } From 31ac8a90f1fbe66c3ad34ef0e5f48bc5f7026059 Mon Sep 17 00:00:00 2001 From: Aaron Turon Date: Wed, 23 Jul 2014 15:43:03 -0700 Subject: [PATCH 15/23] rustdoc: make table of contents optional rustdoc currently determines whether to produce a table of contents (along with numbered sections) from the input type: yes for markdown input, no for Rust input. This commit adds a flag to disable the table of contents for markdown input, which is useful for embedding the output in a larger context. --- src/librustdoc/lib.rs | 6 ++++-- src/librustdoc/markdown.rs | 12 +++++++++--- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index b992a11bc64..70dc230b541 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -131,7 +131,8 @@ pub fn opts() -> Vec { Markdown file or generated documentation", "FILES"), optopt("", "markdown-playground-url", - "URL to send code snippets to", "URL") + "URL to send code snippets to", "URL"), + optflag("", "markdown-no-toc", "don't include table of contents") ) } @@ -220,7 +221,8 @@ pub fn main_args(args: &[String]) -> int { return test::run(input, cfgs, libs, externs, test_args) } (false, true) => return markdown::render(input, output.unwrap_or(Path::new("doc")), - &matches, &external_html), + &matches, &external_html, + !matches.opt_present("markdown-no-toc")), (false, false) => {} } diff --git a/src/librustdoc/markdown.rs b/src/librustdoc/markdown.rs index 416018cadd2..29da9462c7f 100644 --- a/src/librustdoc/markdown.rs +++ b/src/librustdoc/markdown.rs @@ -20,7 +20,7 @@ use externalfiles::ExternalHtml; use html::escape::Escape; use html::markdown; -use html::markdown::{MarkdownWithToc, find_testable_code, reset_headers}; +use html::markdown::{Markdown, MarkdownWithToc, find_testable_code, reset_headers}; use test::Collector; /// Separate any lines at the start of the file that begin with `%`. @@ -42,7 +42,7 @@ fn extract_leading_metadata<'a>(s: &'a str) -> (Vec<&'a str>, &'a str) { /// Render `input` (e.g. "foo.md") into an HTML file in `output` /// (e.g. output = "bar" => "bar/foo.html"). pub fn render(input: &str, mut output: Path, matches: &getopts::Matches, - external_html: &ExternalHtml) -> int { + external_html: &ExternalHtml, include_toc: bool) -> int { let input_p = Path::new(input); output.push(input_p.filestem().unwrap()); output.set_extension("html"); @@ -80,6 +80,12 @@ pub fn render(input: &str, mut output: Path, matches: &getopts::Matches, reset_headers(); + let rendered = if include_toc { + format!("{}", MarkdownWithToc(text)) + } else { + format!("{}", Markdown(text)) + }; + let err = write!( &mut out, r#" @@ -113,7 +119,7 @@ pub fn render(input: &str, mut output: Path, matches: &getopts::Matches, css = css, in_header = external_html.in_header, before_content = external_html.before_content, - text = MarkdownWithToc(text), + text = rendered, after_content = external_html.after_content, playground = playground, ); From 3550068b531703bc492b0f97331c6a2bcafecf37 Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Wed, 23 Jul 2014 19:57:30 -0700 Subject: [PATCH 16/23] librustc: Make bare functions implement the `FnMut` trait. This is done entirely in the libraries for functions up to 16 arguments. A macro is used so that more arguments can be easily added if we need. Note that I had to adjust the overloaded call algorithm to not try calling the overloaded call operator if the callee is a built-in function type, to prevent loops. Closes #15448. --- src/libcore/ops.rs | 34 +++++++++++++++++ src/librustc/middle/typeck/check/mod.rs | 7 ++++ src/libsyntax/parse/parser.rs | 8 +++- .../run-pass/bare-fn-implements-fn-mut.rs | 37 +++++++++++++++++++ 4 files changed, 85 insertions(+), 1 deletion(-) create mode 100644 src/test/run-pass/bare-fn-implements-fn-mut.rs diff --git a/src/libcore/ops.rs b/src/libcore/ops.rs index 0ebb6e94b9a..839243970ac 100644 --- a/src/libcore/ops.rs +++ b/src/libcore/ops.rs @@ -769,3 +769,37 @@ pub trait FnOnce { fn call_once(self, args: Args) -> Result; } +macro_rules! def_fn_mut( + ($($args:ident)*) => ( + #[cfg(not(stage0))] + impl + FnMut<($($args,)*),Result> + for extern "Rust" fn($($args: $args,)*) -> Result { + #[rust_call_abi_hack] + #[allow(uppercase_variables)] + fn call_mut(&mut self, args: ($($args,)*)) -> Result { + let ($($args,)*) = args; + (*self)($($args,)*) + } + } + ) +) + +def_fn_mut!() +def_fn_mut!(A0) +def_fn_mut!(A0 A1) +def_fn_mut!(A0 A1 A2) +def_fn_mut!(A0 A1 A2 A3) +def_fn_mut!(A0 A1 A2 A3 A4) +def_fn_mut!(A0 A1 A2 A3 A4 A5) +def_fn_mut!(A0 A1 A2 A3 A4 A5 A6) +def_fn_mut!(A0 A1 A2 A3 A4 A5 A6 A7) +def_fn_mut!(A0 A1 A2 A3 A4 A5 A6 A7 A8) +def_fn_mut!(A0 A1 A2 A3 A4 A5 A6 A7 A8 A9) +def_fn_mut!(A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 A10) +def_fn_mut!(A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 A10 A11) +def_fn_mut!(A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 A10 A11 A12) +def_fn_mut!(A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 A10 A11 A12 A13) +def_fn_mut!(A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 A10 A11 A12 A13 A14) +def_fn_mut!(A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 A10 A11 A12 A13 A14 A15) + diff --git a/src/librustc/middle/typeck/check/mod.rs b/src/librustc/middle/typeck/check/mod.rs index 557fd522fa9..39e79040e83 100644 --- a/src/librustc/middle/typeck/check/mod.rs +++ b/src/librustc/middle/typeck/check/mod.rs @@ -1541,6 +1541,13 @@ fn try_overloaded_call(fcx: &FnCtxt, callee_type: ty::t, args: &[Gc]) -> bool { + // Bail out if the callee is a bare function or a closure. We check those + // manually. + match *structure_of(fcx, callee.span, callee_type) { + ty::ty_bare_fn(_) | ty::ty_closure(_) => return false, + _ => {} + } + // Try `FnOnce`, then `FnMut`, then `Fn`. for &(maybe_function_trait, method_name) in [ (fcx.tcx().lang_items.fn_once_trait(), token::intern("call_once")), diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index ac363163673..0116518d537 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -4045,7 +4045,8 @@ impl<'a> Parser<'a> { /// Parse a method in a trait impl, starting with `attrs` attributes. pub fn parse_method(&mut self, - already_parsed_attrs: Option>) -> Gc { + already_parsed_attrs: Option>) + -> Gc { let next_attrs = self.parse_outer_attributes(); let attrs = match already_parsed_attrs { Some(mut a) => { a.push_all_move(next_attrs); a } @@ -4083,6 +4084,11 @@ impl<'a> Parser<'a> { let visa = self.parse_visibility(); let abi = if self.eat_keyword(keywords::Extern) { self.parse_opt_abi().unwrap_or(abi::C) + } else if attr::contains_name(attrs.as_slice(), + "rust_call_abi_hack") { + // FIXME(stage0, pcwalton): Remove this awful hack after a + // snapshot, and change to `extern "rust-call" fn`. + abi::RustCall } else { abi::Rust }; diff --git a/src/test/run-pass/bare-fn-implements-fn-mut.rs b/src/test/run-pass/bare-fn-implements-fn-mut.rs new file mode 100644 index 00000000000..37c551734de --- /dev/null +++ b/src/test/run-pass/bare-fn-implements-fn-mut.rs @@ -0,0 +1,37 @@ +// 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. + +#![feature(overloaded_calls)] + +use std::ops::FnMut; + +fn call_f>(mut f: F) { + f(); +} + +fn f() { + println!("hello"); +} + +fn call_g>(mut g: G, x: String, y: String) + -> String { + g(x, y) +} + +fn g(x: String, y: String) -> String { + x.append(y.as_slice()) +} + +fn main() { + call_f(f); + assert_eq!(call_g(g, "foo".to_string(), "bar".to_string()).as_slice(), + "foobar"); +} + From 103d888f659f642d251e47eed4ded2e1e4ce03d1 Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Wed, 23 Jul 2014 21:33:33 -0700 Subject: [PATCH 17/23] librustc: Check structure constructors against their types. This breaks code like: struct Point { x: T, y: T, } let pt = Point:: { x: 1, y: 2, }; Change this code to not contain a type error. For example: let pt = Point:: { x: 1, y: 2, }; Closes #9620. Closes #15875. [breaking-change] --- src/librustc/middle/typeck/astconv.rs | 42 ++++++++++++++ src/librustc/middle/typeck/check/mod.rs | 39 ++++++++++++- .../structure-constructor-type-mismatch.rs | 56 +++++++++++++++++++ 3 files changed, 136 insertions(+), 1 deletion(-) create mode 100644 src/test/compile-fail/structure-constructor-type-mismatch.rs diff --git a/src/librustc/middle/typeck/astconv.rs b/src/librustc/middle/typeck/astconv.rs index 8f450fe3d76..d202e61abf3 100644 --- a/src/librustc/middle/typeck/astconv.rs +++ b/src/librustc/middle/typeck/astconv.rs @@ -53,6 +53,7 @@ use middle::const_eval; use middle::def; use middle::lang_items::FnMutTraitLangItem; use middle::subst::{FnSpace, TypeSpace, SelfSpace, Subst, Substs}; +use middle::subst::{VecPerParamSpace}; use middle::ty; use middle::ty_fold::TypeFolder; use middle::typeck::rscope::{ExplicitRscope, ImpliedSingleRscope}; @@ -299,6 +300,47 @@ pub fn ast_path_to_ty( TypeAndSubsts { substs: substs, ty: ty } } +/// Returns the type that this AST path refers to. If the path has no type +/// parameters and the corresponding type has type parameters, fresh type +/// and/or region variables are substituted. +/// +/// This is used when checking the constructor in struct literals. +pub fn ast_path_to_ty_relaxed( + this: &AC, + rscope: &RS, + did: ast::DefId, + path: &ast::Path) + -> TypeAndSubsts { + let tcx = this.tcx(); + let ty::Polytype { + generics: generics, + ty: decl_ty + } = this.get_item_ty(did); + + let substs = if (generics.has_type_params(TypeSpace) || + generics.has_region_params(TypeSpace)) && + path.segments.iter().all(|s| { + s.lifetimes.len() == 0 && s.types.len() == 0 + }) { + let type_params = Vec::from_fn(generics.types.len(TypeSpace), + |_| this.ty_infer(path.span)); + let region_params = + rscope.anon_regions(path.span, generics.regions.len(TypeSpace)) + .unwrap(); + Substs::new(VecPerParamSpace::params_from_type(type_params), + VecPerParamSpace::params_from_type(region_params)) + } else { + ast_path_substs(this, rscope, &generics, None, path) + }; + + let ty = decl_ty.subst(tcx, &substs); + TypeAndSubsts { + substs: substs, + ty: ty, + } +} + pub static NO_REGIONS: uint = 1; pub static NO_TPS: uint = 2; diff --git a/src/librustc/middle/typeck/check/mod.rs b/src/librustc/middle/typeck/check/mod.rs index 39e79040e83..747ba26f590 100644 --- a/src/librustc/middle/typeck/check/mod.rs +++ b/src/librustc/middle/typeck/check/mod.rs @@ -3416,10 +3416,11 @@ fn check_expr_with_unifier(fcx: &FnCtxt, ast::ExprStruct(ref path, ref fields, base_expr) => { // Resolve the path. let def = tcx.def_map.borrow().find(&id).map(|i| *i); - match def { + let struct_id = match def { Some(def::DefVariant(enum_id, variant_id, _)) => { check_struct_enum_variant(fcx, id, expr.span, enum_id, variant_id, fields.as_slice()); + enum_id } Some(def) => { // Verify that this was actually a struct. @@ -3439,11 +3440,47 @@ fn check_expr_with_unifier(fcx: &FnCtxt, pprust::path_to_string(path)); } } + + def.def_id() } _ => { tcx.sess.span_bug(path.span, "structure constructor wasn't resolved") } + }; + + // Turn the path into a type and verify that that type unifies with + // the resulting structure type. This is needed to handle type + // parameters correctly. + let actual_structure_type = fcx.expr_ty(&*expr); + if !ty::type_is_error(actual_structure_type) { + let type_and_substs = astconv::ast_path_to_ty_relaxed(fcx, + fcx.infcx(), + struct_id, + path); + match fcx.mk_subty(false, + infer::Misc(path.span), + actual_structure_type, + type_and_substs.ty) { + Ok(()) => {} + Err(type_error) => { + let type_error_description = + ty::type_err_to_str(tcx, &type_error); + fcx.tcx() + .sess + .span_err(path.span, + format!("structure constructor specifies a \ + structure of type `{}`, but this \ + structure has type `{}`: {}", + fcx.infcx() + .ty_to_string(type_and_substs.ty), + fcx.infcx() + .ty_to_string( + actual_structure_type), + type_error_description).as_slice()); + ty::note_and_explain_type_err(tcx, &type_error); + } + } } } ast::ExprField(ref base, ref field, ref tys) => { diff --git a/src/test/compile-fail/structure-constructor-type-mismatch.rs b/src/test/compile-fail/structure-constructor-type-mismatch.rs new file mode 100644 index 00000000000..2c8bbee783b --- /dev/null +++ b/src/test/compile-fail/structure-constructor-type-mismatch.rs @@ -0,0 +1,56 @@ +// 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 Point { + x: T, + y: T, +} + +type PointF = Point; + +struct Pair { + x: T, + y: U, +} + +type PairF = Pair; + +fn main() { + let pt = PointF { + //~^ ERROR expected f32 but found int + x: 1i, + y: 2i, + }; + + let pt2 = Point:: { + //~^ ERROR expected f32 but found int + x: 3i, + y: 4i, + }; + + let pair = PairF { + //~^ ERROR expected f32 but found int + x: 5i, + y: 6i, + }; + + let pair2 = PairF:: { + //~^ ERROR expected f32 but found int + x: 7i, + y: 8i, + }; + + let pt3 = PointF:: { + //~^ ERROR wrong number of type arguments + x: 9i, + y: 10i, + }; +} + From 237738fa3ea266fb33f5a0c774347bf73bb20825 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Wed, 23 Jul 2014 21:46:49 -0700 Subject: [PATCH 18/23] rustdoc: Add a --crate-name option Like rustc, this is required by cargo to build documentation. --- src/librustdoc/lib.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index 70dc230b541..39b2511fde4 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -102,6 +102,7 @@ pub fn opts() -> Vec { optopt("w", "output-format", "the output type to write", "[html|json]"), optopt("o", "output", "where to place the output", "PATH"), + optopt("", "crate-name", "specify the name of this crate", "NAME"), optmulti("L", "library-path", "directory to add to crate search path", "DIR"), optmulti("", "cfg", "pass a --cfg to rustc", ""), @@ -323,7 +324,7 @@ fn rust_input(cratefile: &str, externs: core::Externs, matches: &getopts::Matche let cr = Path::new(cratefile); info!("starting to run rustc"); - let (krate, analysis) = std::task::try(proc() { + let (mut krate, analysis) = std::task::try(proc() { let cr = cr; core::run_core(libs.move_iter().collect(), cfgs, @@ -333,6 +334,11 @@ fn rust_input(cratefile: &str, externs: core::Externs, matches: &getopts::Matche info!("finished with rustc"); analysiskey.replace(Some(analysis)); + match matches.opt_str("crate-name") { + Some(name) => krate.name = name, + None => {} + } + // Process all of the crate attributes, extracting plugin metadata along // with the passes which we are supposed to run. match krate.module.get_ref().doc_list() { From a5249289519300553d183ef9fa3844b947015e77 Mon Sep 17 00:00:00 2001 From: Jonas Hietala Date: Thu, 24 Jul 2014 14:08:14 +0200 Subject: [PATCH 19/23] Document TrieSet and TrieMap methods. --- src/libcollections/trie.rs | 207 ++++++++++++++++++++++++++++++++++--- 1 file changed, 191 insertions(+), 16 deletions(-) diff --git a/src/libcollections/trie.rs b/src/libcollections/trie.rs index 5a00c4b85da..fd0e0971b15 100644 --- a/src/libcollections/trie.rs +++ b/src/libcollections/trie.rs @@ -8,7 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! Ordered containers with integer keys, implemented as radix tries (`TrieSet` and `TrieMap` types) +//! Ordered containers with unsigned integer keys, +//! implemented as radix tries (`TrieSet` and `TrieMap` types). use core::prelude::*; @@ -35,7 +36,7 @@ enum Child { Nothing } -#[allow(missing_doc)] +/// A map as a radix trie. pub struct TrieMap { root: TrieNode, length: uint @@ -51,7 +52,7 @@ impl PartialEq for TrieMap { impl Eq for TrieMap {} impl Collection for TrieMap { - /// Return the number of elements in the map + /// Return the number of elements in the map. #[inline] fn len(&self) -> uint { self.length } } @@ -66,7 +67,7 @@ impl Mutable for TrieMap { } impl Map for TrieMap { - /// Return a reference to the value corresponding to the key + /// Return a reference to the value corresponding to the key. #[inline] fn find<'a>(&'a self, key: &uint) -> Option<&'a T> { let mut node: &'a TrieNode = &self.root; @@ -89,7 +90,7 @@ impl Map for TrieMap { } impl MutableMap for TrieMap { - /// Return a mutable reference to the value corresponding to the key + /// Return a mutable reference to the value corresponding to the key. #[inline] fn find_mut<'a>(&'a mut self, key: &uint) -> Option<&'a mut T> { find_mut(&mut self.root.children[chunk(*key, 0)], *key, 1) @@ -122,19 +123,54 @@ impl Default for TrieMap { } impl TrieMap { - /// Create an empty TrieMap + /// Create an empty TrieMap. + /// + /// # Example + /// + /// ``` + /// use std::collections::TrieMap; + /// let mut map: TrieMap<&str> = TrieMap::new(); + /// ``` #[inline] pub fn new() -> TrieMap { TrieMap{root: TrieNode::new(), length: 0} } - /// Visit all key-value pairs in reverse order + /// Visit all key-value pairs in reverse order. Abort traversal when f returns false. + /// Return true if f returns true for all elements. + /// + /// # Example + /// + /// ``` + /// use std::collections::TrieMap; + /// let map: TrieMap<&str> = [(1, "a"), (2, "b"), (3, "c")].iter().map(|&x| x).collect(); + /// + /// let mut vec = Vec::new(); + /// assert_eq!(true, map.each_reverse(|&key, &value| { vec.push((key, value)); true })); + /// assert_eq!(vec, vec![(3, "c"), (2, "b"), (1, "a")]); + /// + /// // Stop when we reach 2 + /// let mut vec = Vec::new(); + /// assert_eq!(false, map.each_reverse(|&key, &value| { vec.push(value); key != 2 })); + /// assert_eq!(vec, vec!["c", "b"]); + /// ``` #[inline] pub fn each_reverse<'a>(&'a self, f: |&uint, &'a T| -> bool) -> bool { self.root.each_reverse(f) } - /// Get an iterator over the key-value pairs in the map + /// Get an iterator over the key-value pairs in the map, ordered by keys. + /// + /// # Example + /// + /// ``` + /// use std::collections::TrieMap; + /// let map: TrieMap<&str> = [(3, "c"), (1, "a"), (2, "b")].iter().map(|&x| x).collect(); + /// + /// for (key, value) in map.iter() { + /// println!("{}: {}", key, value); + /// } + /// ``` pub fn iter<'a>(&'a self) -> Entries<'a, T> { let mut iter = unsafe {Entries::new()}; iter.stack[0] = self.root.children.iter(); @@ -147,6 +183,21 @@ impl TrieMap { /// Get an iterator over the key-value pairs in the map, with the /// ability to mutate the values. + /// + /// # Example + /// + /// ``` + /// use std::collections::TrieMap; + /// let mut map: TrieMap = [(1, 2), (2, 4), (3, 6)].iter().map(|&x| x).collect(); + /// + /// for (key, value) in map.mut_iter() { + /// *value = -(key as int); + /// } + /// + /// assert_eq!(map.find(&1), Some(&-1)); + /// assert_eq!(map.find(&2), Some(&-2)); + /// assert_eq!(map.find(&3), Some(&-3)); + /// ``` pub fn mut_iter<'a>(&'a mut self) -> MutEntries<'a, T> { let mut iter = unsafe {MutEntries::new()}; iter.stack[0] = self.root.children.mut_iter(); @@ -255,12 +306,34 @@ impl TrieMap { /// Get an iterator pointing to the first key-value pair whose key is not less than `key`. /// If all keys in the map are less than `key` an empty iterator is returned. + /// + /// # Example + /// + /// ``` + /// use std::collections::TrieMap; + /// let map: TrieMap<&str> = [(2, "a"), (4, "b"), (6, "c")].iter().map(|&x| x).collect(); + /// + /// assert_eq!(map.lower_bound(4).next(), Some((4, &"b"))); + /// assert_eq!(map.lower_bound(5).next(), Some((6, &"c"))); + /// assert_eq!(map.lower_bound(10).next(), None); + /// ``` pub fn lower_bound<'a>(&'a self, key: uint) -> Entries<'a, T> { self.bound(key, false) } /// Get an iterator pointing to the first key-value pair whose key is greater than `key`. /// If all keys in the map are not greater than `key` an empty iterator is returned. + /// + /// # Example + /// + /// ``` + /// use std::collections::TrieMap; + /// let map: TrieMap<&str> = [(2, "a"), (4, "b"), (6, "c")].iter().map(|&x| x).collect(); + /// + /// assert_eq!(map.upper_bound(4).next(), Some((6, &"c"))); + /// assert_eq!(map.upper_bound(5).next(), Some((6, &"c"))); + /// assert_eq!(map.upper_bound(10).next(), None); + /// ``` pub fn upper_bound<'a>(&'a self, key: uint) -> Entries<'a, T> { self.bound(key, true) } @@ -275,12 +348,50 @@ impl TrieMap { /// Get an iterator pointing to the first key-value pair whose key is not less than `key`. /// If all keys in the map are less than `key` an empty iterator is returned. + /// + /// # Example + /// + /// ``` + /// use std::collections::TrieMap; + /// let mut map: TrieMap<&str> = [(2, "a"), (4, "b"), (6, "c")].iter().map(|&x| x).collect(); + /// + /// assert_eq!(map.mut_lower_bound(4).next(), Some((4, &mut "b"))); + /// assert_eq!(map.mut_lower_bound(5).next(), Some((6, &mut "c"))); + /// assert_eq!(map.mut_lower_bound(10).next(), None); + /// + /// for (key, value) in map.mut_lower_bound(4) { + /// *value = "changed"; + /// } + /// + /// assert_eq!(map.find(&2), Some(&"a")); + /// assert_eq!(map.find(&4), Some(&"changed")); + /// assert_eq!(map.find(&6), Some(&"changed")); + /// ``` pub fn mut_lower_bound<'a>(&'a mut self, key: uint) -> MutEntries<'a, T> { self.mut_bound(key, false) } /// Get an iterator pointing to the first key-value pair whose key is greater than `key`. /// If all keys in the map are not greater than `key` an empty iterator is returned. + /// + /// # Example + /// + /// ``` + /// use std::collections::TrieMap; + /// let mut map: TrieMap<&str> = [(2, "a"), (4, "b"), (6, "c")].iter().map(|&x| x).collect(); + /// + /// assert_eq!(map.mut_upper_bound(4).next(), Some((6, &mut "c"))); + /// assert_eq!(map.mut_upper_bound(5).next(), Some((6, &mut "c"))); + /// assert_eq!(map.mut_upper_bound(10).next(), None); + /// + /// for (key, value) in map.mut_upper_bound(4) { + /// *value = "changed"; + /// } + /// + /// assert_eq!(map.find(&2), Some(&"a")); + /// assert_eq!(map.find(&4), Some(&"b")); + /// assert_eq!(map.find(&6), Some(&"changed")); + /// ``` pub fn mut_upper_bound<'a>(&'a mut self, key: uint) -> MutEntries<'a, T> { self.mut_bound(key, true) } @@ -310,14 +421,14 @@ impl> Hash for TrieMap { } } -#[allow(missing_doc)] +/// A set as a radix trie. #[deriving(Hash, PartialEq, Eq)] pub struct TrieSet { map: TrieMap<()> } impl Collection for TrieSet { - /// Return the number of elements in the set + /// Return the number of elements in the set. #[inline] fn len(&self) -> uint { self.map.len() } } @@ -368,19 +479,61 @@ impl Default for TrieSet { } impl TrieSet { - /// Create an empty TrieSet + /// Create an empty TrieSet. + /// + /// # Example + /// + /// ``` + /// use std::collections::TrieSet; + /// let mut set = TrieSet::new(); + /// ``` #[inline] pub fn new() -> TrieSet { TrieSet{map: TrieMap::new()} } - /// Visit all values in reverse order + /// Visit all values in reverse order. Abort traversal when `f` returns false. + /// Return `true` if `f` returns `true` for all elements. + /// + /// # Example + /// + /// ``` + /// use std::collections::TrieSet; + /// + /// let set: TrieSet = [1, 2, 3, 4, 5].iter().map(|&x| x).collect(); + /// + /// let mut vec = Vec::new(); + /// assert_eq!(true, set.each_reverse(|&x| { vec.push(x); true })); + /// assert_eq!(vec, vec![5, 4, 3, 2, 1]); + /// + /// // Stop when we reach 3 + /// let mut vec = Vec::new(); + /// assert_eq!(false, set.each_reverse(|&x| { vec.push(x); x != 3 })); + /// assert_eq!(vec, vec![5, 4, 3]); + /// ``` #[inline] pub fn each_reverse(&self, f: |&uint| -> bool) -> bool { self.map.each_reverse(|k, _| f(k)) } - /// Get an iterator over the values in the set + /// Get an iterator over the values in the set, in sorted order. + /// + /// # Example + /// + /// ``` + /// use std::collections::TrieSet; + /// + /// let mut set = TrieSet::new(); + /// set.insert(3); + /// set.insert(2); + /// set.insert(1); + /// set.insert(2); + /// + /// // Print 1, 2, 3 + /// for x in set.iter() { + /// println!("{}", x); + /// } + /// ``` #[inline] pub fn iter<'a>(&'a self) -> SetItems<'a> { SetItems{iter: self.map.iter()} @@ -388,12 +541,34 @@ impl TrieSet { /// Get an iterator pointing to the first value that is not less than `val`. /// If all values in the set are less than `val` an empty iterator is returned. + /// + /// # Example + /// + /// ``` + /// use std::collections::TrieSet; + /// + /// let set: TrieSet = [2, 4, 6, 8].iter().map(|&x| x).collect(); + /// assert_eq!(set.lower_bound(4).next(), Some(4)); + /// assert_eq!(set.lower_bound(5).next(), Some(6)); + /// assert_eq!(set.lower_bound(10).next(), None); + /// ``` pub fn lower_bound<'a>(&'a self, val: uint) -> SetItems<'a> { SetItems{iter: self.map.lower_bound(val)} } /// Get an iterator pointing to the first value that key is greater than `val`. - /// If all values in the set are not greater than `val` an empty iterator is returned. + /// If all values in the set are less than or equal to `val` an empty iterator is returned. + /// + /// # Example + /// + /// ``` + /// use std::collections::TrieSet; + /// + /// let set: TrieSet = [2, 4, 6, 8].iter().map(|&x| x).collect(); + /// assert_eq!(set.upper_bound(4).next(), Some(6)); + /// assert_eq!(set.upper_bound(5).next(), Some(6)); + /// assert_eq!(set.upper_bound(10).next(), None); + /// ``` pub fn upper_bound<'a>(&'a self, val: uint) -> SetItems<'a> { SetItems{iter: self.map.upper_bound(val)} } @@ -526,7 +701,7 @@ fn remove(count: &mut uint, child: &mut Child, key: uint, return ret; } -/// Forward iterator over a map +/// Forward iterator over a map. pub struct Entries<'a, T> { stack: [slice::Items<'a, Child>, .. NUM_CHUNKS], length: uint, @@ -660,7 +835,7 @@ macro_rules! iterator_impl { iterator_impl! { Entries, iter = iter, mutability = } iterator_impl! { MutEntries, iter = mut_iter, mutability = mut } -/// Forward iterator over a set +/// Forward iterator over a set. pub struct SetItems<'a> { iter: Entries<'a, ()> } From 3685945ec13ef463178787f1ea87a1a08152cd54 Mon Sep 17 00:00:00 2001 From: Jonas Hietala Date: Thu, 24 Jul 2014 14:30:03 +0200 Subject: [PATCH 20/23] Main examples for TrieSet and TrieMap. --- src/libcollections/trie.rs | 69 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 67 insertions(+), 2 deletions(-) diff --git a/src/libcollections/trie.rs b/src/libcollections/trie.rs index fd0e0971b15..5c17dd91225 100644 --- a/src/libcollections/trie.rs +++ b/src/libcollections/trie.rs @@ -36,7 +36,44 @@ enum Child { Nothing } -/// A map as a radix trie. +/// A map implemented as a radix trie. +/// +/// # Example +/// +/// ``` +/// use std::collections::TrieMap; +/// +/// let mut map = TrieMap::new(); +/// map.insert(27, "Olaf"); +/// map.insert(1, "Edgar"); +/// map.insert(13, "Ruth"); +/// map.insert(1, "Martin"); +/// +/// assert_eq!(map.len(), 3); +/// assert_eq!(map.find(&1), Some(&"Martin")); +/// +/// if !map.contains_key(&90) { +/// println!("Nobody is keyed 90"); +/// } +/// +/// // Update a key +/// match map.find_mut(&1) { +/// Some(value) => *value = "Olga", +/// None => (), +/// } +/// +/// map.remove(&13); +/// assert_eq!(map.len(), 2); +/// +/// // Print the key value pairs, ordered by key. +/// for (key, value) in map.iter() { +/// // Prints `1: Olga` then `27: Olaf` +/// println!("{}: {}", key, value); +/// } +/// +/// map.clear(); +/// assert!(map.is_empty()); +/// ``` pub struct TrieMap { root: TrieNode, length: uint @@ -421,7 +458,35 @@ impl> Hash for TrieMap { } } -/// A set as a radix trie. +/// A set implemented as a radix trie. +/// +/// # Example +/// +/// ``` +/// use std::collections::TrieSet; +/// +/// let mut set = TrieSet::new(); +/// set.insert(6); +/// set.insert(28); +/// set.insert(6); +/// +/// assert_eq!(set.len(), 2); +/// +/// if !set.contains(&3) { +/// println!("3 is not in the set"); +/// } +/// +/// // Print contents in order +/// for x in set.iter() { +/// println!("{}", x); +/// } +/// +/// set.remove(&6); +/// assert_eq!(set.len(), 1); +/// +/// set.clear(); +/// assert!(set.is_empty()); +/// ``` #[deriving(Hash, PartialEq, Eq)] pub struct TrieSet { map: TrieMap<()> From d93e53e70e450e770b6b00bfc6b6498c4513b8e7 Mon Sep 17 00:00:00 2001 From: Jonas Hietala Date: Thu, 24 Jul 2014 15:22:24 +0200 Subject: [PATCH 21/23] Format documentation for SmallIntMap. --- src/libcollections/smallintmap.rs | 32 +++++++++++++++---------------- 1 file changed, 15 insertions(+), 17 deletions(-) diff --git a/src/libcollections/smallintmap.rs b/src/libcollections/smallintmap.rs index eb97215c721..7c102e35b25 100644 --- a/src/libcollections/smallintmap.rs +++ b/src/libcollections/smallintmap.rs @@ -8,10 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -/*! - * A simple map based on a vector for small integer keys. Space requirements - * are O(highest integer key). - */ +//! A simple map based on a vector for small integer keys. Space requirements +//! are O(highest integer key). #![allow(missing_doc)] @@ -32,12 +30,12 @@ pub struct SmallIntMap { } impl Collection for SmallIntMap { - /// Return the number of elements in the map + /// Return the number of elements in the map. fn len(&self) -> uint { self.v.iter().filter(|elt| elt.is_some()).count() } - /// Return true if there are no elements in the map + /// Return `true` if there are no elements in the map. fn is_empty(&self) -> bool { self.v.iter().all(|elt| elt.is_none()) } @@ -49,7 +47,7 @@ impl Mutable for SmallIntMap { } impl Map for SmallIntMap { - /// Return a reference to the value corresponding to the key + /// Return a reference to the value corresponding to the key. fn find<'a>(&'a self, key: &uint) -> Option<&'a V> { if *key < self.v.len() { match *self.v.get(*key) { @@ -63,7 +61,7 @@ impl Map for SmallIntMap { } impl MutableMap for SmallIntMap { - /// Return a mutable reference to the value corresponding to the key + /// Return a mutable reference to the value corresponding to the key. fn find_mut<'a>(&'a mut self, key: &uint) -> Option<&'a mut V> { if *key < self.v.len() { match *self.v.get_mut(*key) { @@ -76,7 +74,7 @@ impl MutableMap for SmallIntMap { } /// Insert a key-value pair into the map. An existing value for a - /// key is replaced by the new value. Return true if the key did + /// key is replaced by the new value. Return `true` if the key did /// not already exist in the map. fn insert(&mut self, key: uint, value: V) -> bool { let exists = self.contains_key(&key); @@ -88,14 +86,14 @@ impl MutableMap for SmallIntMap { !exists } - /// Remove a key-value pair from the map. Return true if the key - /// was present in the map, otherwise false. + /// Remove a key-value pair from the map. Return `true` if the key + /// was present in the map, otherwise `false`. fn remove(&mut self, key: &uint) -> bool { self.pop(key).is_some() } /// Insert a key-value pair from the map. If the key already had a value - /// present in the map, that value is returned. Otherwise None is returned. + /// present in the map, that value is returned. Otherwise `None` is returned. fn swap(&mut self, key: uint, value: V) -> Option { match self.find_mut(&key) { Some(loc) => { return Some(replace(loc, value)); } @@ -121,10 +119,10 @@ impl Default for SmallIntMap { } impl SmallIntMap { - /// Create an empty SmallIntMap + /// Create an empty SmallIntMap. pub fn new() -> SmallIntMap { SmallIntMap{v: vec!()} } - /// Create an empty SmallIntMap with capacity `capacity` + /// Create an empty SmallIntMap with capacity `capacity`. pub fn with_capacity(capacity: uint) -> SmallIntMap { SmallIntMap { v: Vec::with_capacity(capacity) } } @@ -134,7 +132,7 @@ impl SmallIntMap { } /// An iterator visiting all key-value pairs in ascending order by the keys. - /// Iterator element type is (uint, &'r V) + /// Iterator element type is `(uint, &'r V)`. pub fn iter<'r>(&'r self) -> Entries<'r, V> { Entries { front: 0, @@ -145,7 +143,7 @@ impl SmallIntMap { /// An iterator visiting all key-value pairs in ascending order by the keys, /// with mutable references to the values - /// Iterator element type is (uint, &'r mut V) + /// Iterator element type is `(uint, &'r mut V)`. pub fn mut_iter<'r>(&'r mut self) -> MutEntries<'r, V> { MutEntries { front: 0, @@ -154,7 +152,7 @@ impl SmallIntMap { } } - /// Empties the hash map, moving all values into the specified closure + /// Empties the hash map, moving all values into the specified closure. pub fn move_iter(&mut self) -> FilterMap<(uint, Option), (uint, V), Enumerate>>> From dff14069c966ad4e4c453a84a42579a846d4863b Mon Sep 17 00:00:00 2001 From: Jonas Hietala Date: Thu, 24 Jul 2014 15:46:55 +0200 Subject: [PATCH 22/23] Document SmallIntMap with examples. --- src/libcollections/smallintmap.rs | 121 +++++++++++++++++++++++++++++- 1 file changed, 119 insertions(+), 2 deletions(-) diff --git a/src/libcollections/smallintmap.rs b/src/libcollections/smallintmap.rs index 7c102e35b25..3bc2dbe5cbb 100644 --- a/src/libcollections/smallintmap.rs +++ b/src/libcollections/smallintmap.rs @@ -24,7 +24,39 @@ use {Collection, Mutable, Map, MutableMap, MutableSeq}; use {vec, slice}; use vec::Vec; -#[allow(missing_doc)] +/// A map optimized for small integer keys. +/// +/// # Example +/// +/// ``` +/// use std::collections::SmallIntMap; +/// +/// let mut months = SmallIntMap::new(); +/// months.insert(1, "Jan"); +/// months.insert(2, "Feb"); +/// months.insert(3, "Mar"); +/// +/// if !months.contains_key(&12) { +/// println!("The end is near!"); +/// } +/// +/// assert_eq!(months.find(&1), Some(&"Jan")); +/// +/// match months.find_mut(&3) { +/// Some(value) => *value = "Venus", +/// None => (), +/// } +/// +/// assert_eq!(months.find(&3), Some(&"Venus")); +/// +/// // Print out all months +/// for (key, value) in months.iter() { +/// println!("month {} is {}", key, value); +/// } +/// +/// months.clear(); +/// assert!(months.is_empty()); +/// ``` pub struct SmallIntMap { v: Vec>, } @@ -120,19 +152,66 @@ impl Default for SmallIntMap { impl SmallIntMap { /// Create an empty SmallIntMap. + /// + /// # Example + /// + /// ``` + /// use std::collections::SmallIntMap; + /// let mut map: SmallIntMap<&str> = SmallIntMap::new(); + /// ``` pub fn new() -> SmallIntMap { SmallIntMap{v: vec!()} } - /// Create an empty SmallIntMap with capacity `capacity`. + /// Create an empty SmallIntMap with space for at least `capacity` elements + /// before resizing. + /// + /// # Example + /// + /// ``` + /// use std::collections::SmallIntMap; + /// let mut map: SmallIntMap<&str> = SmallIntMap::with_capacity(10); + /// ``` pub fn with_capacity(capacity: uint) -> SmallIntMap { SmallIntMap { v: Vec::with_capacity(capacity) } } + /// Retrieves a value for the given key. + /// See [`find`](../trait.Map.html#tymethod.find) for a non-failing alternative. + /// + /// # Failure + /// + /// Fails if the key is not present. + /// + /// # Example + /// + /// ``` + /// use std::collections::SmallIntMap; + /// + /// let mut map = SmallIntMap::new(); + /// map.insert(1, "a"); + /// assert_eq!(map.get(&1), &"a"); + /// ``` pub fn get<'a>(&'a self, key: &uint) -> &'a V { self.find(key).expect("key not present") } /// An iterator visiting all key-value pairs in ascending order by the keys. /// Iterator element type is `(uint, &'r V)`. + /// + /// # Example + /// + /// ``` + /// use std::collections::SmallIntMap; + /// + /// let mut map = SmallIntMap::new(); + /// map.insert(1, "a"); + /// map.insert(3, "c"); + /// map.insert(2, "b"); + /// + /// // Print `1: a` then `2: b` then `3: c` + /// for (key, value) in map.iter() { + /// println!("{}: {}", key, value); + /// } + /// ``` pub fn iter<'r>(&'r self) -> Entries<'r, V> { Entries { front: 0, @@ -144,6 +223,25 @@ impl SmallIntMap { /// An iterator visiting all key-value pairs in ascending order by the keys, /// with mutable references to the values /// Iterator element type is `(uint, &'r mut V)`. + /// + /// # Example + /// + /// ``` + /// use std::collections::SmallIntMap; + /// + /// let mut map = SmallIntMap::new(); + /// map.insert(1, "a"); + /// map.insert(2, "b"); + /// map.insert(3, "c"); + /// + /// for (key, value) in map.mut_iter() { + /// *value = "x"; + /// } + /// + /// for (key, value) in map.iter() { + /// assert_eq!(value, &"x"); + /// } + /// ``` pub fn mut_iter<'r>(&'r mut self) -> MutEntries<'r, V> { MutEntries { front: 0, @@ -153,6 +251,22 @@ impl SmallIntMap { } /// Empties the hash map, moving all values into the specified closure. + /// + /// # Example + /// + /// ``` + /// use std::collections::SmallIntMap; + /// + /// let mut map = SmallIntMap::new(); + /// map.insert(1, "a"); + /// map.insert(3, "c"); + /// map.insert(2, "b"); + /// + /// // Not possible with .iter() + /// let vec: Vec<(uint, &str)> = map.move_iter().collect(); + /// + /// assert_eq!(vec, vec![(1, "a"), (2, "b"), (3, "c")]); + /// ``` pub fn move_iter(&mut self) -> FilterMap<(uint, Option), (uint, V), Enumerate>>> @@ -247,6 +361,7 @@ macro_rules! double_ended_iterator { } } +/// Forward iterator over a map. pub struct Entries<'a, T> { front: uint, back: uint, @@ -256,6 +371,8 @@ pub struct Entries<'a, T> { iterator!(impl Entries -> (uint, &'a T), get_ref) double_ended_iterator!(impl Entries -> (uint, &'a T), get_ref) +/// Forward iterator over the key-value pairs of a map, with the +/// values being mutable. pub struct MutEntries<'a, T> { front: uint, back: uint, From 1031ad8f709839a4d34045c6b116704e639f5cbe Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 24 Jul 2014 08:48:38 -0700 Subject: [PATCH 23/23] Test fixes from the rollup Closes #15807 (Deprecate some unsafe functions in `str::raw` and remove `OwnedStr` trait) Closes #15859 (Implement `Show` for `CString` and fix warning compiling tests for libcollections) Closes #15911 (Updated LLVM for iOS) Closes #15925 (libsyntax: Remove `~self` and `mut ~self` from the language.) Closes #15930 (Add examples for Checked[Add|Sub|Mul|Div]) Closes #15933 (rustdoc: make table of contents optional) Closes #15937 (librustc: Make bare functions implement the `FnMut` trait.) Closes #15938 (librustc: Check structure constructors against their types.) Closes #15939 (rustdoc: Add a --crate-name option) Closes #15942 (Document trie collections) Closes #15943 (Document SmallIntMap) --- src/libnative/io/addrinfo.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/libnative/io/addrinfo.rs b/src/libnative/io/addrinfo.rs index 343fe05ed42..7a07b622127 100644 --- a/src/libnative/io/addrinfo.rs +++ b/src/libnative/io/addrinfo.rs @@ -27,7 +27,9 @@ impl GetAddrInfoRequest { assert!(host.is_some() || servname.is_some()); let c_host = host.map(|x| x.to_c_str()); + 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 = c_serv.as_ref().map(|x| x.as_ptr()).unwrap_or(null()); let hint = hint.map(|hint| { libc::addrinfo { @@ -49,9 +51,7 @@ impl GetAddrInfoRequest { // Make the call let s = unsafe { - let ch = if c_host.is_none() { null() } else { c_host.unwrap().as_ptr() }; - let cs = if c_serv.is_none() { null() } else { c_serv.unwrap().as_ptr() }; - getaddrinfo(ch, cs, hint_ptr, &mut res) + getaddrinfo(c_host, c_serv, hint_ptr, &mut res) }; // Error?