1111use prelude:: * ;
1212
1313use cast;
14- use int ;
14+ use char :: Char ;
1515use rt:: io:: Decorator ;
1616use rt:: io:: mem:: MemWriter ;
1717use rt:: io;
@@ -122,6 +122,11 @@ pub unsafe fn sprintf(fmt: &[rt::Piece], args: &[Argument]) -> ~str {
122122}
123123
124124impl < ' 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+
125130 fn run ( & mut self , piece : & rt:: Piece , cur : Option < & str > ) {
126131 let setcount = |slot : & mut Option < uint > , cnt : & parse:: Count | {
127132 match * cnt {
@@ -240,6 +245,118 @@ impl<'self> Formatter<'self> {
240245 }
241246 }
242247 }
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+ }
243360}
244361
245362/// This is a function which calls are emitted to by the compiler itself to
@@ -279,60 +396,53 @@ impl Bool for bool {
279396
280397impl < ' self > String for & ' self str {
281398 fn fmt ( s : & & ' self str , f : & mut Formatter ) {
282- // XXX: formatting args
283- f. buf . write ( s. as_bytes ( ) )
399+ f. pad ( * s) ;
284400 }
285401}
286402
287403impl Char for char {
288404 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) ;
294409 }
295410}
296411
297412impl Signed for int {
298413 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 ) ;
302416 }
303417 }
304418}
305419
306420impl Unsigned for uint {
307421 fn fmt ( c : & uint , f : & mut Formatter ) {
308- // XXX: formatting args
309422 do uint:: to_str_bytes ( * c, 10 ) |buf| {
310- f. buf . write ( buf) ;
423+ f. pad_integral ( buf, "" , true ) ;
311424 }
312425 }
313426}
314427
315428impl Octal for uint {
316429 fn fmt ( c : & uint , f : & mut Formatter ) {
317- // XXX: formatting args
318430 do uint:: to_str_bytes ( * c, 8 ) |buf| {
319- f. buf . write ( buf) ;
431+ f. pad_integral ( buf, "0o" , true ) ;
320432 }
321433 }
322434}
323435
324436impl LowerHex for uint {
325437 fn fmt ( c : & uint , f : & mut Formatter ) {
326- // XXX: formatting args
327438 do uint:: to_str_bytes ( * c, 16 ) |buf| {
328- f. buf . write ( buf) ;
439+ f. pad_integral ( buf, "0x" , true ) ;
329440 }
330441 }
331442}
332443
333444impl UpperHex for uint {
334445 fn fmt ( c : & uint , f : & mut Formatter ) {
335- // XXX: formatting args
336446 do uint:: to_str_bytes ( * c, 16 ) |buf| {
337447 let mut local = [ 0u8 , ..16 ] ;
338448 for ( l, & b) in local. mut_iter ( ) . zip ( buf. iter ( ) ) {
@@ -341,16 +451,29 @@ impl UpperHex for uint {
341451 _ => b,
342452 } ;
343453 }
344- f. buf . write ( local. slice_to ( buf. len ( ) ) ) ;
454+ f. pad_integral ( local. slice_to ( buf. len ( ) ) , "0x" , true ) ;
345455 }
346456 }
347457}
348458
349459impl < T > Poly for T {
350460 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+ }
354477 }
355478}
356479
0 commit comments