Skip to content

Commit 5ea1472

Browse files
committed
---
yaml --- r: 130797 b: refs/heads/master c: 370f8df h: refs/heads/master i: 130795: bed1c1b v: v3
1 parent 1f4c4ac commit 5ea1472

File tree

10 files changed

+329
-77
lines changed

10 files changed

+329
-77
lines changed

[refs]

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
---
2-
refs/heads/master: c8e5068ec93ff7af550bcd0276f10c1321e4b337
2+
refs/heads/master: 370f8df2aed338664d9b73ec44ce271daad99148
33
refs/heads/snap-stage1: e33de59e47c5076a89eadeb38f4934f58a3618a6
44
refs/heads/snap-stage3: 6faa4f33a42de32579e02a8d030db920d360e2b5
55
refs/heads/try: a2473a89da106f7dd3be86e9d52fe23f43d5bfa5

trunk/src/doc/guide-strings.md

Lines changed: 86 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -92,9 +92,33 @@ fn foo(s: String) {
9292
```
9393

9494
If you have good reason. It's not polite to hold on to ownership you don't
95-
need, and it can make your lifetimes more complex. Furthermore, you can pass
96-
either kind of string into `foo` by using `.as_slice()` on any `String` you
97-
need to pass in, so the `&str` version is more flexible.
95+
need, and it can make your lifetimes more complex.
96+
97+
## Generic functions
98+
99+
To write a function that's generic over types of strings, use [the `Str`
100+
trait](http://doc.rust-lang.org/std/str/trait.Str.html):
101+
102+
```{rust}
103+
fn some_string_length<T: Str>(x: T) -> uint {
104+
x.as_slice().len()
105+
}
106+
107+
fn main() {
108+
let s = "Hello, world";
109+
110+
println!("{}", some_string_length(s));
111+
112+
let s = "Hello, world".to_string();
113+
114+
println!("{}", some_string_length(s));
115+
}
116+
```
117+
118+
Both of these lines will print `12`.
119+
120+
The only method that the `Str` trait has is `as_slice()`, which gives you
121+
access to a `&str` value from the underlying string.
98122

99123
## Comparisons
100124

@@ -121,6 +145,65 @@ fn compare(string: String) {
121145
Converting a `String` to a `&str` is cheap, but converting the `&str` to a
122146
`String` involves an allocation.
123147

148+
## Indexing strings
149+
150+
You may be tempted to try to access a certain character of a `String`, like
151+
this:
152+
153+
```{rust,ignore}
154+
let s = "hello".to_string();
155+
156+
println!("{}", s[0]);
157+
```
158+
159+
This does not compile. This is on purpose. In the world of UTF-8, direct
160+
indexing is basically never what you want to do. The reason is that each
161+
character can be a variable number of bytes. This means that you have to iterate
162+
through the characters anyway, which is a O(n) operation.
163+
164+
To iterate over a string, use the `graphemes()` method on `&str`:
165+
166+
```{rust}
167+
let s = "αἰθήρ";
168+
169+
for l in s.graphemes(true) {
170+
println!("{}", l);
171+
}
172+
```
173+
174+
Note that `l` has the type `&str` here, since a single grapheme can consist of
175+
multiple codepoints, so a `char` wouldn't be appropriate.
176+
177+
This will print out each character in turn, as you'd expect: first "α", then
178+
"ἰ", etc. You can see that this is different than just the individual bytes.
179+
Here's a version that prints out each byte:
180+
181+
```{rust}
182+
let s = "αἰθήρ";
183+
184+
for l in s.bytes() {
185+
println!("{}", l);
186+
}
187+
```
188+
189+
This will print:
190+
191+
```{notrust,ignore}
192+
206
193+
177
194+
225
195+
188
196+
176
197+
206
198+
184
199+
206
200+
174
201+
207
202+
129
203+
```
204+
205+
Many more bytes than graphemes!
206+
124207
# Other Documentation
125208

126209
* [the `&str` API documentation](/std/str/index.html)

trunk/src/libcore/fmt/mod.rs

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,33 @@ impl<'a> Arguments<'a> {
113113
/// Arguments structure. The compiler inserts an `unsafe` block to call this,
114114
/// which is valid because the compiler performs all necessary validation to
115115
/// ensure that the resulting call to format/write would be safe.
116+
#[cfg(not(stage0))]
117+
#[doc(hidden)] #[inline]
118+
pub unsafe fn new<'a>(pieces: &'static [&'static str],
119+
args: &'a [Argument<'a>]) -> Arguments<'a> {
120+
Arguments {
121+
pieces: mem::transmute(pieces),
122+
fmt: None,
123+
args: args
124+
}
125+
}
126+
127+
/// This function is used to specify nonstandard formatting parameters.
128+
/// The `pieces` array must be at least as long as `fmt` to construct
129+
/// a valid Arguments structure.
130+
#[cfg(not(stage0))]
131+
#[doc(hidden)] #[inline]
132+
pub unsafe fn with_placeholders<'a>(pieces: &'static [&'static str],
133+
fmt: &'static [rt::Argument<'static>],
134+
args: &'a [Argument<'a>]) -> Arguments<'a> {
135+
Arguments {
136+
pieces: mem::transmute(pieces),
137+
fmt: Some(mem::transmute(fmt)),
138+
args: args
139+
}
140+
}
141+
142+
#[cfg(stage0)]
116143
#[doc(hidden)] #[inline]
117144
pub unsafe fn new<'a>(fmt: &'static [rt::Piece<'static>],
118145
args: &'a [Argument<'a>]) -> Arguments<'a> {
@@ -129,6 +156,20 @@ impl<'a> Arguments<'a> {
129156
/// and pass it to a function or closure, passed as the first argument. The
130157
/// macro validates the format string at compile-time so usage of the `write`
131158
/// and `format` functions can be safely performed.
159+
#[cfg(not(stage0))]
160+
pub struct Arguments<'a> {
161+
// Format string pieces to print.
162+
pieces: &'a [&'a str],
163+
164+
// Placeholder specs, or `None` if all specs are default (as in "{}{}").
165+
fmt: Option<&'a [rt::Argument<'a>]>,
166+
167+
// Dynamic arguments for interpolation, to be interleaved with string
168+
// pieces. (Every argument is preceded by a string piece.)
169+
args: &'a [Argument<'a>],
170+
}
171+
172+
#[cfg(stage0)] #[doc(hidden)]
132173
pub struct Arguments<'a> {
133174
fmt: &'a [rt::Piece<'a>],
134175
args: &'a [Argument<'a>],
@@ -255,6 +296,18 @@ uniform_fn_call_workaround! {
255296
secret_upper_exp, UpperExp;
256297
}
257298

299+
#[cfg(not(stage0))]
300+
static DEFAULT_ARGUMENT: rt::Argument<'static> = rt::Argument {
301+
position: rt::ArgumentNext,
302+
format: rt::FormatSpec {
303+
fill: ' ',
304+
align: rt::AlignUnknown,
305+
flags: 0,
306+
precision: rt::CountImplied,
307+
width: rt::CountImplied,
308+
}
309+
};
310+
258311
/// The `write` function takes an output stream, a precompiled format string,
259312
/// and a list of arguments. The arguments will be formatted according to the
260313
/// specified format string into the output stream provided.
@@ -263,6 +316,51 @@ uniform_fn_call_workaround! {
263316
///
264317
/// * output - the buffer to write output to
265318
/// * args - the precompiled arguments generated by `format_args!`
319+
#[cfg(not(stage0))]
320+
pub fn write(output: &mut FormatWriter, args: &Arguments) -> Result {
321+
let mut formatter = Formatter {
322+
flags: 0,
323+
width: None,
324+
precision: None,
325+
buf: output,
326+
align: rt::AlignUnknown,
327+
fill: ' ',
328+
args: args.args,
329+
curarg: args.args.iter(),
330+
};
331+
332+
let mut pieces = args.pieces.iter();
333+
334+
match args.fmt {
335+
None => {
336+
// We can use default formatting parameters for all arguments.
337+
for _ in range(0, args.args.len()) {
338+
try!(formatter.buf.write(pieces.next().unwrap().as_bytes()));
339+
try!(formatter.run(&DEFAULT_ARGUMENT));
340+
}
341+
}
342+
Some(fmt) => {
343+
// Every spec has a corresponding argument that is preceded by
344+
// a string piece.
345+
for (arg, piece) in fmt.iter().zip(pieces.by_ref()) {
346+
try!(formatter.buf.write(piece.as_bytes()));
347+
try!(formatter.run(arg));
348+
}
349+
}
350+
}
351+
352+
// There can be only one trailing string piece left.
353+
match pieces.next() {
354+
Some(piece) => {
355+
try!(formatter.buf.write(piece.as_bytes()));
356+
}
357+
None => {}
358+
}
359+
360+
Ok(())
361+
}
362+
363+
#[cfg(stage0)] #[doc(hidden)]
266364
pub fn write(output: &mut FormatWriter, args: &Arguments) -> Result {
267365
let mut formatter = Formatter {
268366
flags: 0,
@@ -285,7 +383,26 @@ impl<'a> Formatter<'a> {
285383
// First up is the collection of functions used to execute a format string
286384
// at runtime. This consumes all of the compile-time statics generated by
287385
// the format! syntax extension.
386+
#[cfg(not(stage0))]
387+
fn run(&mut self, arg: &rt::Argument) -> Result {
388+
// Fill in the format parameters into the formatter
389+
self.fill = arg.format.fill;
390+
self.align = arg.format.align;
391+
self.flags = arg.format.flags;
392+
self.width = self.getcount(&arg.format.width);
393+
self.precision = self.getcount(&arg.format.precision);
394+
395+
// Extract the correct argument
396+
let value = match arg.position {
397+
rt::ArgumentNext => { *self.curarg.next().unwrap() }
398+
rt::ArgumentIs(i) => self.args[i],
399+
};
400+
401+
// Then actually do some printing
402+
(value.formatter)(value.value, self)
403+
}
288404

405+
#[cfg(stage0)] #[doc(hidden)]
289406
fn run(&mut self, piece: &rt::Piece) -> Result {
290407
match *piece {
291408
rt::String(s) => self.buf.write(s.as_bytes()),

trunk/src/libcore/fmt/rt.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
//! These definitions are similar to their `ct` equivalents, but differ in that
1515
//! these can be statically allocated and are slightly optimized for the runtime
1616
17-
17+
#[cfg(stage0)]
1818
#[doc(hidden)]
1919
pub enum Piece<'a> {
2020
String(&'a str),

trunk/src/libcoretest/fmt/mod.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,10 @@
99
// except according to those terms.
1010

1111
mod num;
12+
13+
#[test]
14+
fn test_format_flags() {
15+
// No residual flags left by pointer formatting
16+
let p = "".as_ptr();
17+
assert_eq!(format!("{:p} {:x}", p, 16u), format!("{:p} 10", p));
18+
}

trunk/src/librustc/lib.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,8 @@ extern crate flate;
4242
extern crate getopts;
4343
extern crate graphviz;
4444
extern crate libc;
45-
extern crate "rustc_llvm" as llvm;
46-
extern crate "rustc_back" as rustc_back;
45+
extern crate rustc_llvm;
46+
extern crate rustc_back;
4747
extern crate serialize;
4848
extern crate rbml;
4949
extern crate time;
@@ -53,6 +53,8 @@ extern crate time;
5353
#[cfg(test)]
5454
extern crate test;
5555

56+
pub use rustc_llvm as llvm;
57+
5658
mod diagnostics;
5759

5860
pub mod back {

0 commit comments

Comments
 (0)