Skip to content

Commit 6bc48b6

Browse files
committed
auto merge of #9192 : Kimundi/rust/master, r=huonw
A SendStr is a string that can hold either a ~str or a &'static str. This can be useful as an optimization when an allocation is sometimes needed but the common case is statically known. Possible use cases include Maps with both static and owned keys, or propagating error messages across task boundaries. SendStr implements most basic traits in a way that hides the fact that it is an enum; in particular things like order and equality are only determined by the content of the wrapped strings. This basically reimplements #7599 and has a use case for replacing an similar type in `std::rt::logging` ( Added in #9180).
2 parents 507a7f0 + 0635cb7 commit 6bc48b6

File tree

9 files changed

+431
-16
lines changed

9 files changed

+431
-16
lines changed

src/libstd/logging.rs

+4-3
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,8 @@
1313
use option::*;
1414
use os;
1515
use rt;
16-
use rt::logging::{Logger, StdErrLogger, OwnedString};
16+
use rt::logging::{Logger, StdErrLogger};
17+
use send_str::SendStrOwned;
1718

1819
/// Turns on logging to stdout globally
1920
pub fn console_on() {
@@ -56,12 +57,12 @@ fn newsched_log_str(msg: ~str) {
5657
match optional_task {
5758
Some(local) => {
5859
// Use the available logger
59-
(*local).logger.log(OwnedString(msg));
60+
(*local).logger.log(SendStrOwned(msg));
6061
}
6162
None => {
6263
// There is no logger anywhere, just write to stderr
6364
let mut logger = StdErrLogger;
64-
logger.log(OwnedString(msg));
65+
logger.log(SendStrOwned(msg));
6566
}
6667
}
6768
}

src/libstd/prelude.rs

+1
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ pub use path::PosixPath;
6666
pub use path::WindowsPath;
6767
pub use ptr::RawPtr;
6868
pub use ascii::{Ascii, AsciiCast, OwnedAsciiCast, AsciiStr, ToBytesConsume};
69+
pub use send_str::{SendStr, SendStrOwned, SendStrStatic, IntoSendStr};
6970
pub use str::{Str, StrVector, StrSlice, OwnedStr};
7071
pub use from_str::FromStr;
7172
pub use to_bytes::IterBytes;

src/libstd/rt/logging.rs

+5-10
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ use str::raw::from_c_str;
1717
use u32;
1818
use vec::ImmutableVector;
1919
use cast::transmute;
20+
use send_str::{SendStr, SendStrOwned, SendStrStatic};
2021

2122
struct LogDirective {
2223
name: Option<~str>,
@@ -168,32 +169,26 @@ fn update_log_settings(crate_map: *u8, settings: ~str) {
168169
}
169170
}
170171

171-
/// Represent a string with `Send` bound.
172-
pub enum SendableString {
173-
OwnedString(~str),
174-
StaticString(&'static str)
175-
}
176-
177172
pub trait Logger {
178-
fn log(&mut self, msg: SendableString);
173+
fn log(&mut self, msg: SendStr);
179174
}
180175

181176
pub struct StdErrLogger;
182177

183178
impl Logger for StdErrLogger {
184-
fn log(&mut self, msg: SendableString) {
179+
fn log(&mut self, msg: SendStr) {
185180
use io::{Writer, WriterUtil};
186181

187182
if !should_log_console() {
188183
return;
189184
}
190185

191186
let s: &str = match msg {
192-
OwnedString(ref s) => {
187+
SendStrOwned(ref s) => {
193188
let slc: &str = *s;
194189
slc
195190
},
196-
StaticString(s) => s,
191+
SendStrStatic(s) => s,
197192
};
198193

199194
// Truncate the string

src/libstd/send_str.rs

+248
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,248 @@
1+
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
//! `SendStr` definition and trait implementations
12+
13+
use clone::{Clone, DeepClone};
14+
use cmp::{Eq, TotalEq, Ord, TotalOrd, Equiv};
15+
use cmp::Ordering;
16+
use container::Container;
17+
use default::Default;
18+
use str::{Str, StrSlice};
19+
use to_str::ToStr;
20+
use to_bytes::{IterBytes, Cb};
21+
22+
/// A SendStr is a string that can hold either a ~str or a &'static str.
23+
/// This can be useful as an optimization when an allocation is sometimes
24+
/// needed but the common case is statically known.
25+
pub enum SendStr {
26+
SendStrOwned(~str),
27+
SendStrStatic(&'static str)
28+
}
29+
30+
impl SendStr {
31+
/// Returns `true` if this `SendStr` wraps an owned string
32+
#[inline]
33+
pub fn is_owned(&self) -> bool {
34+
match *self {
35+
SendStrOwned(_) => true,
36+
SendStrStatic(_) => false
37+
}
38+
}
39+
40+
/// Returns `true` if this `SendStr` wraps an static string
41+
#[inline]
42+
pub fn is_static(&self) -> bool {
43+
match *self {
44+
SendStrOwned(_) => false,
45+
SendStrStatic(_) => true
46+
}
47+
}
48+
}
49+
50+
/// Trait for moving into an `SendStr`
51+
pub trait IntoSendStr {
52+
/// Moves self into an `SendStr`
53+
fn into_send_str(self) -> SendStr;
54+
}
55+
56+
impl IntoSendStr for ~str {
57+
#[inline]
58+
fn into_send_str(self) -> SendStr { SendStrOwned(self) }
59+
}
60+
61+
impl IntoSendStr for &'static str {
62+
#[inline]
63+
fn into_send_str(self) -> SendStr { SendStrStatic(self) }
64+
}
65+
66+
/*
67+
Section: String trait impls.
68+
`SendStr` should behave like a normal string, so we don't derive.
69+
*/
70+
71+
impl ToStr for SendStr {
72+
#[inline]
73+
fn to_str(&self) -> ~str { self.as_slice().to_owned() }
74+
}
75+
76+
impl Eq for SendStr {
77+
#[inline]
78+
fn eq(&self, other: &SendStr) -> bool {
79+
self.as_slice().equals(&other.as_slice())
80+
}
81+
}
82+
83+
impl TotalEq for SendStr {
84+
#[inline]
85+
fn equals(&self, other: &SendStr) -> bool {
86+
self.as_slice().equals(&other.as_slice())
87+
}
88+
}
89+
90+
impl Ord for SendStr {
91+
#[inline]
92+
fn lt(&self, other: &SendStr) -> bool {
93+
self.as_slice().lt(&other.as_slice())
94+
}
95+
}
96+
97+
impl TotalOrd for SendStr {
98+
#[inline]
99+
fn cmp(&self, other: &SendStr) -> Ordering {
100+
self.as_slice().cmp(&other.as_slice())
101+
}
102+
}
103+
104+
impl<'self, S: Str> Equiv<S> for SendStr {
105+
#[inline]
106+
fn equiv(&self, other: &S) -> bool {
107+
self.as_slice().equals(&other.as_slice())
108+
}
109+
}
110+
111+
impl Str for SendStr {
112+
#[inline]
113+
fn as_slice<'r>(&'r self) -> &'r str {
114+
match *self {
115+
SendStrOwned(ref s) => s.as_slice(),
116+
// XXX: Borrowchecker doesn't recognize lifetime as static unless prompted
117+
// SendStrStatic(s) => s.as_slice()
118+
SendStrStatic(s) => {let tmp: &'static str = s; tmp}
119+
}
120+
}
121+
122+
#[inline]
123+
fn into_owned(self) -> ~str {
124+
match self {
125+
SendStrOwned(s) => s,
126+
SendStrStatic(s) => s.to_owned()
127+
}
128+
}
129+
}
130+
131+
impl Container for SendStr {
132+
#[inline]
133+
fn len(&self) -> uint { self.as_slice().len() }
134+
}
135+
136+
impl Clone for SendStr {
137+
#[inline]
138+
fn clone(&self) -> SendStr {
139+
match *self {
140+
SendStrOwned(ref s) => SendStrOwned(s.to_owned()),
141+
SendStrStatic(s) => SendStrStatic(s)
142+
}
143+
}
144+
}
145+
146+
impl DeepClone for SendStr {
147+
#[inline]
148+
fn deep_clone(&self) -> SendStr {
149+
match *self {
150+
SendStrOwned(ref s) => SendStrOwned(s.to_owned()),
151+
SendStrStatic(s) => SendStrStatic(s)
152+
}
153+
}
154+
}
155+
156+
impl Default for SendStr {
157+
#[inline]
158+
fn default() -> SendStr { SendStrStatic("") }
159+
}
160+
161+
impl IterBytes for SendStr {
162+
#[inline]
163+
fn iter_bytes(&self, lsb0: bool, f: Cb) -> bool {
164+
match *self {
165+
SendStrOwned(ref s) => s.iter_bytes(lsb0, f),
166+
SendStrStatic(s) => s.iter_bytes(lsb0, f)
167+
}
168+
}
169+
}
170+
171+
#[cfg(test)]
172+
mod tests {
173+
use clone::{Clone, DeepClone};
174+
use cmp::{TotalEq, Ord, TotalOrd, Equiv};
175+
use cmp::Equal;
176+
use container::Container;
177+
use default::Default;
178+
use send_str::{SendStrOwned, SendStrStatic};
179+
use str::Str;
180+
use to_str::ToStr;
181+
182+
#[test]
183+
fn test_send_str_traits() {
184+
let s = SendStrStatic("abcde");
185+
assert_eq!(s.len(), 5);
186+
assert_eq!(s.as_slice(), "abcde");
187+
assert_eq!(s.to_str(), ~"abcde");
188+
assert!(s.equiv(&@"abcde"));
189+
assert!(s.lt(&SendStrOwned(~"bcdef")));
190+
assert_eq!(SendStrStatic(""), Default::default());
191+
192+
let o = SendStrOwned(~"abcde");
193+
assert_eq!(o.len(), 5);
194+
assert_eq!(o.as_slice(), "abcde");
195+
assert_eq!(o.to_str(), ~"abcde");
196+
assert!(o.equiv(&@"abcde"));
197+
assert!(o.lt(&SendStrStatic("bcdef")));
198+
assert_eq!(SendStrOwned(~""), Default::default());
199+
200+
assert_eq!(s.cmp(&o), Equal);
201+
assert!(s.equals(&o));
202+
assert!(s.equiv(&o));
203+
204+
assert_eq!(o.cmp(&s), Equal);
205+
assert!(o.equals(&s));
206+
assert!(o.equiv(&s));
207+
}
208+
209+
#[test]
210+
fn test_send_str_methods() {
211+
let s = SendStrStatic("abcde");
212+
assert!(s.is_static());
213+
assert!(!s.is_owned());
214+
215+
let o = SendStrOwned(~"abcde");
216+
assert!(!o.is_static());
217+
assert!(o.is_owned());
218+
}
219+
220+
#[test]
221+
fn test_send_str_clone() {
222+
assert_eq!(SendStrOwned(~"abcde"), SendStrStatic("abcde").clone());
223+
assert_eq!(SendStrOwned(~"abcde"), SendStrStatic("abcde").deep_clone());
224+
225+
assert_eq!(SendStrOwned(~"abcde"), SendStrOwned(~"abcde").clone());
226+
assert_eq!(SendStrOwned(~"abcde"), SendStrOwned(~"abcde").deep_clone());
227+
228+
assert_eq!(SendStrStatic("abcde"), SendStrStatic("abcde").clone());
229+
assert_eq!(SendStrStatic("abcde"), SendStrStatic("abcde").deep_clone());
230+
231+
assert_eq!(SendStrStatic("abcde"), SendStrOwned(~"abcde").clone());
232+
assert_eq!(SendStrStatic("abcde"), SendStrOwned(~"abcde").deep_clone());
233+
}
234+
235+
#[test]
236+
fn test_send_str_into_owned() {
237+
assert_eq!(SendStrStatic("abcde").into_owned(), ~"abcde");
238+
assert_eq!(SendStrOwned(~"abcde").into_owned(), ~"abcde");
239+
}
240+
241+
#[test]
242+
fn test_into_send_str() {
243+
assert_eq!("abcde".into_send_str(), SendStrStatic("abcde"));
244+
assert_eq!((~"abcde").into_send_str(), SendStrStatic("abcde"));
245+
assert_eq!("abcde".into_send_str(), SendStrOwned(~"abcde"));
246+
assert_eq!((~"abcde").into_send_str(), SendStrOwned(~"abcde"));
247+
}
248+
}

src/libstd/std.rs

+1
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,7 @@ pub mod str;
121121

122122
#[path = "str/ascii.rs"]
123123
pub mod ascii;
124+
pub mod send_str;
124125

125126
pub mod ptr;
126127
pub mod owned;

0 commit comments

Comments
 (0)