(index<- ) ./libstd/unstable/extfmt.rs
1 // Copyright 2012 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 //! Support for fmt! expressions.
12 //!
13 //! The syntax is close to that of Posix format strings:
14 //!
15 //! ~~~~~~
16 //! Format := '%' Parameter? Flag* Width? Precision? Type
17 //! Parameter := [0-9]+ '$'
18 //! Flag := [ 0#+-]
19 //! Width := Parameter | [0-9]+
20 //! Precision := '.' [0-9]+
21 //! Type := [bcdfiostuxX?]
22 //! ~~~~~~
23 //!
24 //! * Parameter is the 1-based argument to apply the format to. Currently not
25 //! implemented.
26 //! * Flag 0 causes leading zeros to be used for padding when converting
27 //! numbers.
28 //! * Flag # causes the conversion to be done in an *alternative* manner.
29 //! Currently not implemented.
30 //! * Flag + causes signed numbers to always be prepended with a sign
31 //! character.
32 //! * Flag - left justifies the result
33 //! * Width specifies the minimum field width of the result. By default
34 //! leading spaces are added.
35 //! * Precision specifies the minimum number of digits for integral types
36 //! and the minimum number
37 //! of decimal places for float.
38 //!
39 //! The types currently supported are:
40 //!
41 //! * b - bool
42 //! * c - char
43 //! * d - int
44 //! * f - float
45 //! * i - int (same as d)
46 //! * o - uint as octal
47 //! * t - uint as binary
48 //! * u - uint
49 //! * x - uint as lower-case hexadecimal
50 //! * X - uint as upper-case hexadecimal
51 //! * s - str (any flavor)
52 //! * ? - arbitrary type (does not use the to_str trait)
53
54 /*
55 Syntax Extension: fmt
56
57 Format a string
58
59 The 'fmt' extension is modeled on the posix printf system.
60
61 A posix conversion ostensibly looks like this
62
63 > %~[parameter]~[flags]~[width]~[.precision]~[length]type
64
65 Given the different numeric type bestiary we have, we omit the 'length'
66 parameter and support slightly different conversions for 'type'
67
68 > %~[parameter]~[flags]~[width]~[.precision]type
69
70 we also only support translating-to-rust a tiny subset of the possible
71 combinations at the moment.
72
73 Example:
74
75 debug!("hello, %s!", "world");
76
77 */
78
79 use prelude::*;
80
81 /*
82 * We have a 'ct' (compile-time) module that parses format strings into a
83 * sequence of conversions. From those conversions AST fragments are built
84 * that call into properly-typed functions in the 'rt' (run-time) module.
85 * Each of those run-time conversion functions accepts another conversion
86 * description that specifies how to format its output.
87 *
88 * The building of the AST is currently done in a module inside the compiler,
89 * but should migrate over here as the plugin interface is defined.
90 */
91
92 // Functions used by the fmt extension at compile time
93 #[doc(hidden)]
94 pub mod ct {
95 use char;
96 use container::Container;
97 use prelude::*;
98 use str;
99
100 #[deriving(Eq)]
101 pub enum Signedness { Signed, Unsigned, }
102
103 #[deriving(Eq)]
104 pub enum Caseness { CaseUpper, CaseLower, }
105
106 #[deriving(Eq)]
107 pub enum Ty {
108 TyBool,
109 TyStr,
110 TyChar,
111 TyInt(Signedness),
112 TyBits,
113 TyHex(Caseness),
114 TyOctal,
115 TyFloat,
116 TyPointer,
117 TyPoly,
118 }
119
120 #[deriving(Eq)]
121 pub enum Flag {
122 FlagLeftJustify,
123 FlagLeftZeroPad,
124 FlagSpaceForSign,
125 FlagSignAlways,
126 FlagAlternate,
127 }
128
129 #[deriving(Eq)]
130 pub enum Count {
131 CountIs(uint),
132 CountIsParam(uint),
133 CountIsNextParam,
134 CountImplied,
135 }
136
137 #[deriving(Eq)]
138 struct Parsed<T> {
139 val: T,
140 next: uint
141 }
142
143 impl<T> Parsed<T> {
144 pub fn new(val: T, next: uint) -> Parsed<T> {
145 Parsed {val: val, next: next}
146 }
147 }
148
149 // A formatted conversion from an expression to a string
150 #[deriving(Eq)]
151 pub struct Conv {
152 param: Option<uint>,
153 flags: ~[Flag],
154 width: Count,
155 precision: Count,
156 ty: Ty
157 }
158
159 // A fragment of the output sequence
160 #[deriving(Eq)]
161 pub enum Piece {
162 PieceString(~str),
163 PieceConv(Conv),
164 }
165
166 pub type ErrorFn<'self> = &'self fn(&str) -> !;
167
168 pub fn parse_fmt_string<'a>(s: &str, err: ErrorFn<'a>) -> ~[Piece] {
169 fn push_slice(ps: &mut ~[Piece], s: &str, from: uint, to: uint) {
170 if to > from {
171 ps.push(PieceString(s.slice(from, to).to_owned()));
172 }
173 }
174
175 let lim = s.len();
176 let mut h = 0;
177 let mut i = 0;
178 let mut pieces = ~[];
179
180 while i < lim {
181 if s[i] == '%' as u8 {
182 i += 1;
183
184 if i >= lim {
185 err("unterminated conversion at end of string");
186 } else if s[i] == '%' as u8 {
187 push_slice(&mut pieces, s, h, i);
188 i += 1;
189 } else {
190 push_slice(&mut pieces, s, h, i - 1);
191 let Parsed {
192 val,
193 next
194 } = parse_conversion(s, i, lim, |s| err(s));
195 pieces.push(val);
196 i = next;
197 }
198
199 h = i;
200 } else {
201 i += str::utf8_char_width(s[i]);
202 }
203 }
204
205 push_slice(&mut pieces, s, h, i);
206 pieces
207 }
208
209 pub fn peek_num(s: &str, i: uint, lim: uint) -> Option<Parsed<uint>> {
210 let mut i = i;
211 let mut accum = 0;
212 let mut found = false;
213
214 while i < lim {
215 match char::to_digit(s[i] as char, 10) {
216 Some(x) => {
217 found = true;
218 accum *= 10;
219 accum += x;
220 i += 1;
221 }
222 None => break
223 }
224 }
225
226 if found {
227 Some(Parsed::new(accum, i))
228 } else {
229 None
230 }
231 }
232
233 pub fn parse_conversion<'a>(s: &str, i: uint, lim: uint, err: ErrorFn<'a>)
234 -> Parsed<Piece> {
235 let param = parse_parameter(s, i, lim);
236 // avoid copying ~[Flag] by destructuring
237 let Parsed {val: flags_val, next: flags_next} = parse_flags(s,
238 param.next, lim);
239 let width = parse_count(s, flags_next, lim);
240 let prec = parse_precision(s, width.next, lim);
241 let ty = parse_type(s, prec.next, lim, err);
242
243 Parsed::new(PieceConv(Conv {
244 param: param.val,
245 flags: flags_val,
246 width: width.val,
247 precision: prec.val,
248 ty: ty.val}), ty.next)
249 }
250
251 pub fn parse_parameter(s: &str, i: uint, lim: uint) ->
252 Parsed<Option<uint>> {
253 if i >= lim { return Parsed::new(None, i); }
254
255 match peek_num(s, i, lim) {
256 Some(num) if num.next < lim && s[num.next] == '$' as u8 =>
257 Parsed::new(Some(num.val), num.next + 1),
258 _ => Parsed::new(None, i)
259 }
260 }
261
262 pub fn parse_flags(s: &str, i: uint, lim: uint) -> Parsed<~[Flag]> {
263 let mut i = i;
264 let mut flags = ~[];
265
266 while i < lim {
267 let f = match s[i] as char {
268 '-' => FlagLeftJustify,
269 '0' => FlagLeftZeroPad,
270 ' ' => FlagSpaceForSign,
271 '+' => FlagSignAlways,
272 '#' => FlagAlternate,
273 _ => break
274 };
275
276 flags.push(f);
277 i += 1;
278 }
279
280 Parsed::new(flags, i)
281 }
282
283 pub fn parse_count(s: &str, i: uint, lim: uint) -> Parsed<Count> {
284 if i >= lim {
285 Parsed::new(CountImplied, i)
286 } else if s[i] == '*' as u8 {
287 let param = parse_parameter(s, i + 1, lim);
288 let j = param.next;
289
290 match param.val {
291 None => Parsed::new(CountIsNextParam, j),
292 Some(n) => Parsed::new(CountIsParam(n), j)
293 }
294 } else {
295 match peek_num(s, i, lim) {
296 None => Parsed::new(CountImplied, i),
297 Some(num) => Parsed::new(CountIs(num.val), num.next)
298 }
299 }
300 }
301
302 pub fn parse_precision(s: &str, i: uint, lim: uint) -> Parsed<Count> {
303 if i < lim && s[i] == '.' as u8 {
304 let count = parse_count(s, i + 1, lim);
305
306 // If there were no digits specified, i.e. the precision
307 // was ".", then the precision is 0
308 match count.val {
309 CountImplied => Parsed::new(CountIs(0), count.next),
310 _ => count
311 }
312 } else {
313 Parsed::new(CountImplied, i)
314 }
315 }
316
317 pub fn parse_type<'a>(s: &str, i: uint, lim: uint, err: ErrorFn<'a>)
318 -> Parsed<Ty> {
319 if i >= lim { err("missing type in conversion"); }
320
321 // FIXME (#2249): Do we really want two signed types here?
322 // How important is it to be printf compatible?
323 let t = match s[i] as char {
324 'b' => TyBool,
325 's' => TyStr,
326 'c' => TyChar,
327 'd' | 'i' => TyInt(Signed),
328 'u' => TyInt(Unsigned),
329 'x' => TyHex(CaseLower),
330 'X' => TyHex(CaseUpper),
331 't' => TyBits,
332 'o' => TyOctal,
333 'f' => TyFloat,
334 'p' => TyPointer,
335 '?' => TyPoly,
336 _ => err(format!("unknown type in conversion: {}", s.char_at(i)))
337 };
338
339 Parsed::new(t, i + 1)
340 }
341
342 #[cfg(test)]
343 fn die(s: &str) -> ! { fail2!(s.to_owned()) }
344
345 #[test]
346 fn test_parse_count() {
347 fn test(s: &str, count: Count, next: uint) -> bool {
348 parse_count(s, 0, s.len()) == Parsed::new(count, next)
349 }
350
351 assert!(test("", CountImplied, 0));
352 assert!(test("*", CountIsNextParam, 1));
353 assert!(test("*1", CountIsNextParam, 1));
354 assert!(test("*1$", CountIsParam(1), 3));
355 assert!(test("123", CountIs(123), 3));
356 }
357
358 #[test]
359 fn test_parse_flags() {
360 fn pack(fs: &[Flag]) -> uint {
361 fs.iter().fold(0, |p, &f| p | (1 << f as uint))
362 }
363
364 fn test(s: &str, flags: &[Flag], next: uint) {
365 let f = parse_flags(s, 0, s.len());
366 assert_eq!(pack(f.val), pack(flags));
367 assert_eq!(f.next, next);
368 }
369
370 test("", [], 0);
371 test("!#-+ 0", [], 0);
372 test("#-+", [FlagAlternate, FlagLeftJustify, FlagSignAlways], 3);
373 test(" 0", [FlagSpaceForSign, FlagLeftZeroPad], 2);
374 }
375
376 #[test]
377 fn test_parse_fmt_string() {
378 assert!(parse_fmt_string("foo %s bar", die) == ~[
379 PieceString(~"foo "),
380 PieceConv(Conv {
381 param: None,
382 flags: ~[],
383 width: CountImplied,
384 precision: CountImplied,
385 ty: TyStr,
386 }),
387 PieceString(~" bar")]);
388
389 assert!(parse_fmt_string("%s", die) == ~[
390 PieceConv(Conv {
391 param: None,
392 flags: ~[],
393 width: CountImplied,
394 precision: CountImplied,
395 ty: TyStr,
396 })]);
397
398 assert!(parse_fmt_string("%%%%", die) == ~[
399 PieceString(~"%"), PieceString(~"%")]);
400 }
401
402 #[test]
403 fn test_parse_parameter() {
404 fn test(s: &str, param: Option<uint>, next: uint) -> bool {
405 parse_parameter(s, 0, s.len()) == Parsed::new(param, next)
406 }
407
408 assert!(test("", None, 0));
409 assert!(test("foo", None, 0));
410 assert!(test("123", None, 0));
411 assert!(test("123$", Some(123), 4));
412 }
413
414 #[test]
415 fn test_parse_precision() {
416 fn test(s: &str, count: Count, next: uint) -> bool {
417 parse_precision(s, 0, s.len()) == Parsed::new(count, next)
418 }
419
420 assert!(test("", CountImplied, 0));
421 assert!(test(".", CountIs(0), 1));
422 assert!(test(".*", CountIsNextParam, 2));
423 assert!(test(".*1", CountIsNextParam, 2));
424 assert!(test(".*1$", CountIsParam(1), 4));
425 assert!(test(".123", CountIs(123), 4));
426 }
427
428 #[test]
429 fn test_parse_type() {
430 fn test(s: &str, ty: Ty) -> bool {
431 parse_type(s, 0, s.len(), die) == Parsed::new(ty, 1)
432 }
433
434 assert!(test("b", TyBool));
435 assert!(test("c", TyChar));
436 assert!(test("d", TyInt(Signed)));
437 assert!(test("f", TyFloat));
438 assert!(test("i", TyInt(Signed)));
439 assert!(test("o", TyOctal));
440 assert!(test("s", TyStr));
441 assert!(test("t", TyBits));
442 assert!(test("x", TyHex(CaseLower)));
443 assert!(test("X", TyHex(CaseUpper)));
444 assert!(test("p", TyPointer));
445 assert!(test("?", TyPoly));
446 }
447
448 #[test]
449 #[should_fail]
450 fn test_parse_type_missing() {
451 parse_type("", 0, 0, die);
452 }
453
454 #[test]
455 #[should_fail]
456 fn test_parse_type_unknown() {
457 parse_type("!", 0, 1, die);
458 }
459
460 #[test]
461 fn test_peek_num() {
462 let s1 = "";
463 assert!(peek_num(s1, 0, s1.len()).is_none());
464
465 let s2 = "foo";
466 assert!(peek_num(s2, 0, s2.len()).is_none());
467
468 let s3 = "123";
469 assert_eq!(peek_num(s3, 0, s3.len()), Some(Parsed::new(123, 3)));
470
471 let s4 = "123foo";
472 assert_eq!(peek_num(s4, 0, s4.len()), Some(Parsed::new(123, 3)));
473 }
474 }
475
476 // Functions used by the fmt extension at runtime. For now there are a lot of
477 // decisions made a runtime. If it proves worthwhile then some of these
478 // conditions can be evaluated at compile-time. For now though it's cleaner to
479 // implement it this way, I think.
480 #[doc(hidden)]
481 #[allow(non_uppercase_statics)]
482 pub mod rt {
483 use f64;
484 use str;
485 use sys;
486 use num;
487 use vec;
488 use option::{Some, None, Option};
489
490 pub static flag_none : u32 = 0u32;
491 pub static flag_left_justify : u32 = 0b00000000000001u32;
492 pub static flag_left_zero_pad : u32 = 0b00000000000010u32;
493 pub static flag_space_for_sign : u32 = 0b00000000000100u32;
494 pub static flag_sign_always : u32 = 0b00000000001000u32;
495 pub static flag_alternate : u32 = 0b00000000010000u32;
496
497 pub enum Count { CountIs(uint), CountImplied, }
498
499 pub enum Ty { TyDefault, TyBits, TyHexUpper, TyHexLower, TyOctal, }
500
501 pub struct Conv {
502 flags: u32,
503 width: Count,
504 precision: Count,
505 ty: Ty,
506 }
507
508 pub fn conv_int(cv: Conv, i: int, buf: &mut ~str) {
509 let radix = 10;
510 let prec = get_int_precision(cv);
511 let s : ~str = uint_to_str_prec(num::abs(i) as uint, radix, prec);
512
513 let head = if i >= 0 {
514 if have_flag(cv.flags, flag_sign_always) {
515 Some('+')
516 } else if have_flag(cv.flags, flag_space_for_sign) {
517 Some(' ')
518 } else {
519 None
520 }
521 } else { Some('-') };
522 pad(cv, s, head, PadSigned, buf);
523 }
524 pub fn conv_uint(cv: Conv, u: uint, buf: &mut ~str) {
525 let prec = get_int_precision(cv);
526 let rs =
527 match cv.ty {
528 TyDefault => uint_to_str_prec(u, 10, prec),
529 TyHexLower => uint_to_str_prec(u, 16, prec),
530
531 // FIXME: #4318 Instead of to_ascii and to_str_ascii, could use
532 // to_ascii_move and to_str_move to not do a unnecessary copy.
533 TyHexUpper => {
534 let s = uint_to_str_prec(u, 16, prec);
535 s.to_ascii().to_upper().to_str_ascii()
536 }
537 TyBits => uint_to_str_prec(u, 2, prec),
538 TyOctal => uint_to_str_prec(u, 8, prec)
539 };
540 pad(cv, rs, None, PadUnsigned, buf);
541 }
542 pub fn conv_bool(cv: Conv, b: bool, buf: &mut ~str) {
543 let s = if b { "true" } else { "false" };
544 // run the boolean conversion through the string conversion logic,
545 // giving it the same rules for precision, etc.
546 conv_str(cv, s, buf);
547 }
548 pub fn conv_char(cv: Conv, c: char, buf: &mut ~str) {
549 pad(cv, "", Some(c), PadNozero, buf);
550 }
551 pub fn conv_str(cv: Conv, s: &str, buf: &mut ~str) {
552 // For strings, precision is the maximum characters
553 // displayed
554 let unpadded = match cv.precision {
555 CountImplied => s,
556 CountIs(max) => {
557 if (max as uint) < s.char_len() {
558 s.slice(0, max as uint)
559 } else {
560 s
561 }
562 }
563 };
564 pad(cv, unpadded, None, PadNozero, buf);
565 }
566 pub fn conv_float(cv: Conv, f: f64, buf: &mut ~str) {
567 let (to_str, digits) = match cv.precision {
568 CountIs(c) => (f64::to_str_exact, c as uint),
569 CountImplied => (f64::to_str_digits, 6u)
570 };
571 let s = to_str(f, digits);
572 let head = if 0.0 <= f {
573 if have_flag(cv.flags, flag_sign_always) {
574 Some('+')
575 } else if have_flag(cv.flags, flag_space_for_sign) {
576 Some(' ')
577 } else {
578 None
579 }
580 } else { None };
581 pad(cv, s, head, PadFloat, buf);
582 }
583 pub fn conv_pointer<T>(cv: Conv, ptr: *T, buf: &mut ~str) {
584 let s = ~"0x" + uint_to_str_prec(ptr as uint, 16, 1u);
585 pad(cv, s, None, PadNozero, buf);
586 }
587 pub fn conv_poly<T>(cv: Conv, v: &T, buf: &mut ~str) {
588 let s = sys::log_str(v);
589 conv_str(cv, s, buf);
590 }
591
592 // Convert a uint to string with a minimum number of digits. If precision
593 // is 0 and num is 0 then the result is the empty string. Could move this
594 // to uint: but it doesn't seem all that useful.
595 pub fn uint_to_str_prec(num: uint, radix: uint, prec: uint) -> ~str {
596 return if prec == 0u && num == 0u {
597 ~""
598 } else {
599 let s = num.to_str_radix(radix);
600 let len = s.char_len();
601 if len < prec {
602 let diff = prec - len;
603 let pad = str::from_chars(vec::from_elem(diff, '0'));
604 pad + s
605 } else { s }
606 };
607 }
608 pub fn get_int_precision(cv: Conv) -> uint {
609 return match cv.precision {
610 CountIs(c) => c as uint,
611 CountImplied => 1u
612 };
613 }
614
615 #[deriving(Eq)]
616 pub enum PadMode { PadSigned, PadUnsigned, PadNozero, PadFloat }
617
618 pub fn pad(cv: Conv, s: &str, head: Option<char>, mode: PadMode,
619 buf: &mut ~str) {
620 let headsize = match head { Some(_) => 1, _ => 0 };
621 let uwidth : uint = match cv.width {
622 CountImplied => {
623 for &c in head.iter() {
624 buf.push_char(c);
625 }
626 return buf.push_str(s);
627 }
628 CountIs(width) => { width as uint }
629 };
630 let strlen = s.char_len() + headsize;
631 if uwidth <= strlen {
632 for &c in head.iter() {
633 buf.push_char(c);
634 }
635 return buf.push_str(s);
636 }
637 let mut padchar = ' ';
638 let diff = uwidth - strlen;
639 if have_flag(cv.flags, flag_left_justify) {
640 for &c in head.iter() {
641 buf.push_char(c);
642 }
643 buf.push_str(s);
644 do diff.times {
645 buf.push_char(padchar);
646 }
647 return;
648 }
649 let (might_zero_pad, signed) = match mode {
650 PadNozero => (false, true),
651 PadSigned => (true, true),
652 PadFloat => (true, true),
653 PadUnsigned => (true, false)
654 };
655 fn have_precision(cv: Conv) -> bool {
656 return match cv.precision { CountImplied => false, _ => true };
657 }
658 let zero_padding = {
659 if might_zero_pad && have_flag(cv.flags, flag_left_zero_pad) &&
660 (!have_precision(cv) || mode == PadFloat) {
661 padchar = '0';
662 true
663 } else {
664 false
665 }
666 };
667 let padstr = str::from_chars(vec::from_elem(diff, padchar));
668 // This is completely heinous. If we have a signed value then
669 // potentially rip apart the intermediate result and insert some
670 // zeros. It may make sense to convert zero padding to a precision
671 // instead.
672
673 if signed && zero_padding {
674 for &head in head.iter() {
675 if head == '+' || head == '-' || head == ' ' {
676 buf.push_char(head);
677 buf.push_str(padstr);
678 buf.push_str(s);
679 return;
680 }
681 }
682 }
683 buf.push_str(padstr);
684 for &c in head.iter() {
685 buf.push_char(c);
686 }
687 buf.push_str(s);
688 }
689 #[inline]
690 pub fn have_flag(flags: u32, f: u32) -> bool {
691 flags & f != 0
692 }
693 }
694
695 // Bulk of the tests are in src/test/run-pass/syntax-extension-fmt.rs
696 #[cfg(test)]
697 mod test {
698 #[test]
699 fn fmt_slice() {
700 let s = "abc";
701 let _s = format!("{}", s);
702 }
703 }
libstd/unstable/extfmt.rs:166:4-166:4 -ty- definition:
pub type ErrorFn<'self> = &'self fn(&str) -> !;
references:-233: pub fn parse_conversion<'a>(s: &str, i: uint, lim: uint, err: ErrorFn<'a>)
317: pub fn parse_type<'a>(s: &str, i: uint, lim: uint, err: ErrorFn<'a>)
168: pub fn parse_fmt_string<'a>(s: &str, err: ErrorFn<'a>) -> ~[Piece] {
libstd/unstable/extfmt.rs:121:4-121:4 -enum- definition:
pub enum Flag {
FlagLeftJustify,
references:-120: #[deriving(Eq)]
120: #[deriving(Eq)]
120: #[deriving(Eq)]
153: flags: ~[Flag],
262: pub fn parse_flags(s: &str, i: uint, lim: uint) -> Parsed<~[Flag]> {
libstd/unstable/extfmt.rs:169:8-169:8 -fn- definition:
fn push_slice(ps: &mut ~[Piece], s: &str, from: uint, to: uint) {
if to > from {
references:-190: push_slice(&mut pieces, s, h, i - 1);
205: push_slice(&mut pieces, s, h, i);
187: push_slice(&mut pieces, s, h, i);
libstd/unstable/extfmt.rs:209:4-209:4 -fn- definition:
pub fn peek_num(s: &str, i: uint, lim: uint) -> Option<Parsed<uint>> {
let mut i = i;
references:-295: match peek_num(s, i, lim) {
255: match peek_num(s, i, lim) {
libstd/unstable/extfmt.rs:302:4-302:4 -fn- definition:
pub fn parse_precision(s: &str, i: uint, lim: uint) -> Parsed<Count> {
if i < lim && s[i] == '.' as u8 {
references:-240: let prec = parse_precision(s, width.next, lim);
libstd/unstable/extfmt.rs:262:4-262:4 -fn- definition:
pub fn parse_flags(s: &str, i: uint, lim: uint) -> Parsed<~[Flag]> {
let mut i = i;
references:-237: let Parsed {val: flags_val, next: flags_next} = parse_flags(s,
libstd/unstable/extfmt.rs:616:4-616:4 -enum- definition:
pub enum PadMode { PadSigned, PadUnsigned, PadNozero, PadFloat }
references:-615: #[deriving(Eq)]
615: #[deriving(Eq)]
615: #[deriving(Eq)]
618: pub fn pad(cv: Conv, s: &str, head: Option<char>, mode: PadMode,
libstd/unstable/extfmt.rs:161:4-161:4 -enum- definition:
pub enum Piece {
PieceString(~str),
references:-169: fn push_slice(ps: &mut ~[Piece], s: &str, from: uint, to: uint) {
168: pub fn parse_fmt_string<'a>(s: &str, err: ErrorFn<'a>) -> ~[Piece] {
234: -> Parsed<Piece> {
160: #[deriving(Eq)]
160: #[deriving(Eq)]
160: #[deriving(Eq)]
libstd/unstable/extfmt.rs:151:4-151:4 -struct- definition:
pub struct Conv {
param: Option<uint>,
references:-150: #[deriving(Eq)]
150: #[deriving(Eq)]
243: Parsed::new(PieceConv(Conv {
150: #[deriving(Eq)]
150: #[deriving(Eq)]
163: PieceConv(Conv),
150: #[deriving(Eq)]
150: #[deriving(Eq)]
150: #[deriving(Eq)]
libstd/unstable/extfmt.rs:690:4-690:4 -fn- definition:
pub fn have_flag(flags: u32, f: u32) -> bool {
flags & f != 0
references:-516: } else if have_flag(cv.flags, flag_space_for_sign) {
514: if have_flag(cv.flags, flag_sign_always) {
659: if might_zero_pad && have_flag(cv.flags, flag_left_zero_pad) &&
639: if have_flag(cv.flags, flag_left_justify) {
575: } else if have_flag(cv.flags, flag_space_for_sign) {
573: if have_flag(cv.flags, flag_sign_always) {
libstd/unstable/extfmt.rs:618:4-618:4 -fn- definition:
pub fn pad(cv: Conv, s: &str, head: Option<char>, mode: PadMode,
buf: &mut ~str) {
references:-540: pad(cv, rs, None, PadUnsigned, buf);
564: pad(cv, unpadded, None, PadNozero, buf);
581: pad(cv, s, head, PadFloat, buf);
522: pad(cv, s, head, PadSigned, buf);
549: pad(cv, "", Some(c), PadNozero, buf);
585: pad(cv, s, None, PadNozero, buf);
libstd/unstable/extfmt.rs:317:4-317:4 -fn- definition:
pub fn parse_type<'a>(s: &str, i: uint, lim: uint, err: ErrorFn<'a>)
-> Parsed<Ty> {
references:-241: let ty = parse_type(s, prec.next, lim, err);
libstd/unstable/extfmt.rs:233:4-233:4 -fn- definition:
pub fn parse_conversion<'a>(s: &str, i: uint, lim: uint, err: ErrorFn<'a>)
-> Parsed<Piece> {
references:-194: } = parse_conversion(s, i, lim, |s| err(s));
libstd/unstable/extfmt.rs:655:8-655:8 -fn- definition:
fn have_precision(cv: Conv) -> bool {
return match cv.precision { CountImplied => false, _ => true };
references:-660: (!have_precision(cv) || mode == PadFloat) {
libstd/unstable/extfmt.rs:551:4-551:4 -fn- definition:
pub fn conv_str(cv: Conv, s: &str, buf: &mut ~str) {
// For strings, precision is the maximum characters
references:-546: conv_str(cv, s, buf);
589: conv_str(cv, s, buf);
libstd/unstable/extfmt.rs:104:4-104:4 -enum- definition:
pub enum Caseness { CaseUpper, CaseLower, }
references:-103: #[deriving(Eq)]
113: TyHex(Caseness),
103: #[deriving(Eq)]
103: #[deriving(Eq)]
libstd/unstable/extfmt.rs:138:4-138:4 -struct- definition:
struct Parsed<T> {
val: T,
references:-137: #[deriving(Eq)]
144: pub fn new(val: T, next: uint) -> Parsed<T> {
137: #[deriving(Eq)]
143: impl<T> Parsed<T> {
318: -> Parsed<Ty> {
137: #[deriving(Eq)]
252: Parsed<Option<uint>> {
137: #[deriving(Eq)]
145: Parsed {val: val, next: next}
237: let Parsed {val: flags_val, next: flags_next} = parse_flags(s,
302: pub fn parse_precision(s: &str, i: uint, lim: uint) -> Parsed<Count> {
137: #[deriving(Eq)]
262: pub fn parse_flags(s: &str, i: uint, lim: uint) -> Parsed<~[Flag]> {
234: -> Parsed<Piece> {
209: pub fn peek_num(s: &str, i: uint, lim: uint) -> Option<Parsed<uint>> {
137: #[deriving(Eq)]
283: pub fn parse_count(s: &str, i: uint, lim: uint) -> Parsed<Count> {
137: #[deriving(Eq)]
191: let Parsed {
libstd/unstable/extfmt.rs:251:4-251:4 -fn- definition:
pub fn parse_parameter(s: &str, i: uint, lim: uint) ->
Parsed<Option<uint>> {
references:-235: let param = parse_parameter(s, i, lim);
287: let param = parse_parameter(s, i + 1, lim);
libstd/unstable/extfmt.rs:501:4-501:4 -struct- definition:
pub struct Conv {
flags: u32,
references:-583: pub fn conv_pointer<T>(cv: Conv, ptr: *T, buf: &mut ~str) {
524: pub fn conv_uint(cv: Conv, u: uint, buf: &mut ~str) {
542: pub fn conv_bool(cv: Conv, b: bool, buf: &mut ~str) {
551: pub fn conv_str(cv: Conv, s: &str, buf: &mut ~str) {
508: pub fn conv_int(cv: Conv, i: int, buf: &mut ~str) {
655: fn have_precision(cv: Conv) -> bool {
618: pub fn pad(cv: Conv, s: &str, head: Option<char>, mode: PadMode,
587: pub fn conv_poly<T>(cv: Conv, v: &T, buf: &mut ~str) {
566: pub fn conv_float(cv: Conv, f: f64, buf: &mut ~str) {
548: pub fn conv_char(cv: Conv, c: char, buf: &mut ~str) {
608: pub fn get_int_precision(cv: Conv) -> uint {
libstd/unstable/extfmt.rs:130:4-130:4 -enum- definition:
pub enum Count {
CountIs(uint),
references:-129: #[deriving(Eq)]
129: #[deriving(Eq)]
302: pub fn parse_precision(s: &str, i: uint, lim: uint) -> Parsed<Count> {
129: #[deriving(Eq)]
154: width: Count,
155: precision: Count,
283: pub fn parse_count(s: &str, i: uint, lim: uint) -> Parsed<Count> {
libstd/unstable/extfmt.rs:499:4-499:4 -enum- definition:
pub enum Ty { TyDefault, TyBits, TyHexUpper, TyHexLower, TyOctal, }
references:-505: ty: Ty,
libstd/unstable/extfmt.rs:608:4-608:4 -fn- definition:
pub fn get_int_precision(cv: Conv) -> uint {
return match cv.precision {
references:-510: let prec = get_int_precision(cv);
525: let prec = get_int_precision(cv);
libstd/unstable/extfmt.rs:497:4-497:4 -enum- definition:
pub enum Count { CountIs(uint), CountImplied, }
references:-504: precision: Count,
503: width: Count,
libstd/unstable/extfmt.rs:101:4-101:4 -enum- definition:
pub enum Signedness { Signed, Unsigned, }
references:-111: TyInt(Signedness),
100: #[deriving(Eq)]
100: #[deriving(Eq)]
100: #[deriving(Eq)]
libstd/unstable/extfmt.rs:107:4-107:4 -enum- definition:
pub enum Ty {
TyBool,
references:-156: ty: Ty
106: #[deriving(Eq)]
106: #[deriving(Eq)]
106: #[deriving(Eq)]
318: -> Parsed<Ty> {
libstd/unstable/extfmt.rs:283:4-283:4 -fn- definition:
pub fn parse_count(s: &str, i: uint, lim: uint) -> Parsed<Count> {
if i >= lim {
references:-239: let width = parse_count(s, flags_next, lim);
304: let count = parse_count(s, i + 1, lim);
libstd/unstable/extfmt.rs:595:4-595:4 -fn- definition:
pub fn uint_to_str_prec(num: uint, radix: uint, prec: uint) -> ~str {
return if prec == 0u && num == 0u {
references:-511: let s : ~str = uint_to_str_prec(num::abs(i) as uint, radix, prec);
584: let s = ~"0x" + uint_to_str_prec(ptr as uint, 16, 1u);
537: TyBits => uint_to_str_prec(u, 2, prec),
528: TyDefault => uint_to_str_prec(u, 10, prec),
538: TyOctal => uint_to_str_prec(u, 8, prec)
529: TyHexLower => uint_to_str_prec(u, 16, prec),
534: let s = uint_to_str_prec(u, 16, prec);