11
11
use prelude:: * ;
12
12
13
13
use cast;
14
- use int ;
14
+ use char :: Char ;
15
15
use rt:: io:: Decorator ;
16
16
use rt:: io:: mem:: MemWriter ;
17
17
use rt:: io;
@@ -122,6 +122,11 @@ pub unsafe fn sprintf(fmt: &[rt::Piece], args: &[Argument]) -> ~str {
122
122
}
123
123
124
124
impl < ' self > Formatter < ' self > {
125
+
126
+ // First up is the collection of functions used to execute a format string
127
+ // at runtime. This consumes all of the compile-time statics generated by
128
+ // the ifmt! syntax extension.
129
+
125
130
fn run ( & mut self , piece : & rt:: Piece , cur : Option < & str > ) {
126
131
let setcount = |slot : & mut Option < uint > , cnt : & parse:: Count | {
127
132
match * cnt {
@@ -240,6 +245,118 @@ impl<'self> Formatter<'self> {
240
245
}
241
246
}
242
247
}
248
+
249
+ // Helper methods used for padding and processing formatting arguments that
250
+ // all formatting traits can use.
251
+
252
+ /// TODO: dox
253
+ pub fn pad_integral ( & mut self , s : & [ u8 ] , alternate_prefix : & str ,
254
+ positive : bool ) {
255
+ use fmt:: parse:: { FlagAlternate , FlagSignPlus } ;
256
+
257
+ let mut actual_len = s. len ( ) ;
258
+ if self . flags & 1 << ( FlagAlternate as uint ) != 0 {
259
+ actual_len += alternate_prefix. len ( ) ;
260
+ }
261
+ if self . flags & 1 << ( FlagSignPlus as uint ) != 0 {
262
+ actual_len += 1 ;
263
+ }
264
+ if !positive {
265
+ actual_len += 1 ;
266
+ }
267
+
268
+ let emit = |this : & mut Formatter | {
269
+ if this. flags & 1 << ( FlagSignPlus as uint ) != 0 && positive {
270
+ this. buf . write ( [ '+' as u8 ] ) ;
271
+ } else if !positive {
272
+ this. buf . write ( [ '-' as u8 ] ) ;
273
+ }
274
+ if this. flags & 1 << ( FlagAlternate as uint ) != 0 {
275
+ this. buf . write ( alternate_prefix. as_bytes ( ) ) ;
276
+ }
277
+ this. buf . write ( s) ;
278
+ } ;
279
+
280
+ match self . width {
281
+ None => { emit ( self ) }
282
+ Some ( min) if actual_len >= min => { emit ( self ) }
283
+ Some ( min) => {
284
+ do self . with_padding ( min - actual_len) |me| {
285
+ emit ( me) ;
286
+ }
287
+ }
288
+ }
289
+ }
290
+
291
+ /// This function takes a string slice and emits it to the internal buffer
292
+ /// after applying the relevant formatting flags specified. The flags
293
+ /// recognized for generic strings are:
294
+ ///
295
+ /// * width - the minimum width of what to emit
296
+ /// * fill/alignleft - what to emit and where to emit it if the string
297
+ /// provided needs to be padded
298
+ /// * precision - the maximum length to emit, the string is truncated if it
299
+ /// is longer than this length
300
+ ///
301
+ /// Notably this function ignored the `flag` parameters
302
+ pub fn pad ( & mut self , s : & str ) {
303
+ // Make sure there's a fast path up front
304
+ if self . width . is_none ( ) && self . precision . is_none ( ) {
305
+ self . buf . write ( s. as_bytes ( ) ) ;
306
+ return
307
+ }
308
+ // The `precision` field can be interpreted as a `max-width` for the
309
+ // string being formatted
310
+ match self . precision {
311
+ Some ( max) => {
312
+ // If there's a maximum width and our string is longer than
313
+ // that, then we must always have truncation. This is the only
314
+ // case where the maximum length will matter.
315
+ let char_len = s. char_len ( ) ;
316
+ if char_len >= max {
317
+ let nchars = uint:: min ( max, char_len) ;
318
+ self . buf . write ( s. slice_chars ( 0 , nchars) . as_bytes ( ) ) ;
319
+ return
320
+ }
321
+ }
322
+ None => { }
323
+ }
324
+
325
+ // The `width` field is more of a `min-width` parameter at this point.
326
+ match self . width {
327
+ // If we're under the maximum length, and there's no minimum length
328
+ // requirements, then we can just emit the string
329
+ None => { self . buf . write ( s. as_bytes ( ) ) }
330
+
331
+ // If we're under the maximum width, check if we're over the minimum
332
+ // width, if so it's as easy as just emitting the string.
333
+ Some ( width) if s. char_len ( ) >= width => {
334
+ self . buf . write ( s. as_bytes ( ) )
335
+ }
336
+
337
+ // If we're under both the maximum and the minimum width, then fill
338
+ // up the minimum width with the specified string + some alignment.
339
+ Some ( width) => {
340
+ do self . with_padding ( width - s. len ( ) ) |me| {
341
+ me. buf . write ( s. as_bytes ( ) ) ;
342
+ }
343
+ }
344
+ }
345
+ }
346
+
347
+ fn with_padding ( & mut self , padding : uint , f : & fn ( & mut Formatter ) ) {
348
+ if self . alignleft {
349
+ f ( self ) ;
350
+ }
351
+ let mut fill = [ 0u8 , ..4 ] ;
352
+ let len = self . fill . encode_utf8 ( fill) ;
353
+ for _ in range ( 0 , padding) {
354
+ self . buf . write ( fill. slice_to ( len) ) ;
355
+ }
356
+ if !self . alignleft {
357
+ f ( self ) ;
358
+ }
359
+ }
243
360
}
244
361
245
362
/// This is a function which calls are emitted to by the compiler itself to
@@ -279,60 +396,53 @@ impl Bool for bool {
279
396
280
397
impl < ' self > String for & ' self str {
281
398
fn fmt ( s : & & ' self str , f : & mut Formatter ) {
282
- // XXX: formatting args
283
- f. buf . write ( s. as_bytes ( ) )
399
+ f. pad ( * s) ;
284
400
}
285
401
}
286
402
287
403
impl Char for char {
288
404
fn fmt ( c : & char , f : & mut Formatter ) {
289
- // XXX: formatting args
290
- // XXX: shouldn't require an allocation
291
- let mut s = ~"";
292
- s. push_char ( * c) ;
293
- f. buf . write ( s. as_bytes ( ) ) ;
405
+ let mut utf8 = [ 0u8 , ..4 ] ;
406
+ let amt = c. encode_utf8 ( utf8) ;
407
+ let s: & str = unsafe { cast:: transmute ( utf8. slice_to ( amt) ) } ;
408
+ String :: fmt ( & s, f) ;
294
409
}
295
410
}
296
411
297
412
impl Signed for int {
298
413
fn fmt ( c : & int , f : & mut Formatter ) {
299
- // XXX: formatting args
300
- do int:: to_str_bytes ( * c, 10 ) |buf| {
301
- f. buf . write ( buf) ;
414
+ do uint:: to_str_bytes ( c. abs ( ) as uint , 10 ) |buf| {
415
+ f. pad_integral ( buf, "" , * c >= 0 ) ;
302
416
}
303
417
}
304
418
}
305
419
306
420
impl Unsigned for uint {
307
421
fn fmt ( c : & uint , f : & mut Formatter ) {
308
- // XXX: formatting args
309
422
do uint:: to_str_bytes ( * c, 10 ) |buf| {
310
- f. buf . write ( buf) ;
423
+ f. pad_integral ( buf, "" , true ) ;
311
424
}
312
425
}
313
426
}
314
427
315
428
impl Octal for uint {
316
429
fn fmt ( c : & uint , f : & mut Formatter ) {
317
- // XXX: formatting args
318
430
do uint:: to_str_bytes ( * c, 8 ) |buf| {
319
- f. buf . write ( buf) ;
431
+ f. pad_integral ( buf, "0o" , true ) ;
320
432
}
321
433
}
322
434
}
323
435
324
436
impl LowerHex for uint {
325
437
fn fmt ( c : & uint , f : & mut Formatter ) {
326
- // XXX: formatting args
327
438
do uint:: to_str_bytes ( * c, 16 ) |buf| {
328
- f. buf . write ( buf) ;
439
+ f. pad_integral ( buf, "0x" , true ) ;
329
440
}
330
441
}
331
442
}
332
443
333
444
impl UpperHex for uint {
334
445
fn fmt ( c : & uint , f : & mut Formatter ) {
335
- // XXX: formatting args
336
446
do uint:: to_str_bytes ( * c, 16 ) |buf| {
337
447
let mut local = [ 0u8 , ..16 ] ;
338
448
for ( l, & b) in local. mut_iter ( ) . zip ( buf. iter ( ) ) {
@@ -341,16 +451,29 @@ impl UpperHex for uint {
341
451
_ => b,
342
452
} ;
343
453
}
344
- f. buf . write ( local. slice_to ( buf. len ( ) ) ) ;
454
+ f. pad_integral ( local. slice_to ( buf. len ( ) ) , "0x" , true ) ;
345
455
}
346
456
}
347
457
}
348
458
349
459
impl < T > Poly for T {
350
460
fn fmt ( t : & T , f : & mut Formatter ) {
351
- // XXX: formatting args
352
- let s = sys:: log_str ( t) ;
353
- f. buf . write ( s. as_bytes ( ) ) ;
461
+ match ( f. width , f. precision ) {
462
+ ( None , None ) => {
463
+ // XXX: sys::log_str should have a variant which takes a stream
464
+ // and we should directly call that (avoids unnecessary
465
+ // allocations)
466
+ let s = sys:: log_str ( t) ;
467
+ f. buf . write ( s. as_bytes ( ) ) ;
468
+ }
469
+
470
+ // If we have a specified width for formatting, then we have to make
471
+ // this allocation of a new string
472
+ _ => {
473
+ let s = sys:: log_str ( t) ;
474
+ f. pad ( s) ;
475
+ }
476
+ }
354
477
}
355
478
}
356
479
0 commit comments