11//! Runtime implementation of [`format!`].
22//!
3- //! See [`format()`] for details.
3+ //! See [`format`](format()) and [`write`](write()) for details.
44//!
55//! # Features
66//! By default only [`Display`] is supported, the rest of the
@@ -24,7 +24,7 @@ use std::error::Error as StdError;
2424use std:: fmt:: Pointer ;
2525#[ cfg( feature = "number" ) ]
2626use std:: fmt:: { Binary , LowerExp , LowerHex , Octal , UpperExp , UpperHex } ;
27- use std:: fmt:: { Debug , Display , Error as FmtError } ;
27+ use std:: fmt:: { Debug , Display , Error as FmtError , Write } ;
2828use std:: hash:: Hash ;
2929use std:: num:: ParseIntError ;
3030
@@ -494,21 +494,23 @@ impl<'a> FormatArgument<'a> {
494494 }
495495}
496496
497- /// Runtime version of [`format !`].
497+ /// Runtime version of [`write !`].
498498///
499- /// Takes a string and a context, containing [`Formattable `] values, returns a
500- /// string .
499+ /// Takes a mutable [`Write `] e.g `&mut String`, a format string and a context,
500+ /// containing [`Formattable`] values .
501501///
502502/// ```
503- /// use template::{format , Formattable};
503+ /// use template::{write , Formattable};
504504///
505- /// let formatted = format(
505+ /// let mut buf = String::new();
506+ /// write(
507+ /// &mut buf,
506508/// "{value:+05}", // could be dynamic
507509/// &[("value", Formattable::display(&12))].into_iter().collect(),
508510/// )
509511/// .unwrap();
510512///
511- /// assert_eq!(formatted , format!("{:+05}", 12));
513+ /// assert_eq!(buf , format!("{:+05}", 12));
512514/// ```
513515///
514516/// # Errors
@@ -518,16 +520,17 @@ impl<'a> FormatArgument<'a> {
518520/// failed.
519521///
520522/// For more details have a look at [`Error`] and [`FormatArgumentError`].
521- pub fn format < K : Borrow < str > + Eq + Hash > (
523+ pub fn write < K : Borrow < str > + Eq + Hash > (
524+ out : & mut impl Write ,
522525 mut format : & str ,
523526 context : & HashMap < K , Formattable > ,
524- ) -> Result < String > {
527+ ) -> Result {
525528 let format = & mut format;
526- let mut out = String :: with_capacity ( format. len ( ) ) ;
527529 let idx = & mut 0 ;
528530 while !format. is_empty ( ) {
529531 if format. starts_with ( "{{" ) || format. starts_with ( "}}" ) {
530- out. push_str ( & format[ ..1 ] ) ;
532+ out. write_str ( & format[ ..1 ] )
533+ . map_err ( |e| Error :: FmtError ( e, * idx) ) ?;
531534 step ( 2 , format, idx) ;
532535 continue ;
533536 }
@@ -548,7 +551,7 @@ pub fn format<K: Borrow<str> + Eq + Hash>(
548551 . get ( ident)
549552 . ok_or ( Error :: MissingValue ( ident. to_string ( ) , start) ) ?;
550553 format_value (
551- & mut out, value, width, precision, alignment, sign, hash, zero, trait_, * idx,
554+ out, value, width, precision, alignment, sign, hash, zero, trait_, * idx,
552555 ) ?;
553556 ensure ! (
554557 format. starts_with( '}' ) ,
@@ -561,8 +564,41 @@ pub fn format<K: Borrow<str> + Eq + Hash>(
561564 . chars ( )
562565 . next ( )
563566 . expect ( "should contain a char if not empty" ) ;
564- out. push ( next) ;
567+ out. write_char ( next) . map_err ( |e| Error :: FmtError ( e , * idx ) ) ? ;
565568 step ( next. len_utf8 ( ) , format, idx) ;
566569 }
570+ Ok ( ( ) )
571+ }
572+
573+ /// Runtime version of [`format!`].
574+ ///
575+ /// Takes a string and a context, containing [`Formattable`] values, returns a
576+ /// string.
577+ ///
578+ /// ```
579+ /// use template::{format, Formattable};
580+ ///
581+ /// let formatted = format(
582+ /// "{value:+05}", // could be dynamic
583+ /// &[("value", Formattable::display(&12))].into_iter().collect(),
584+ /// )
585+ /// .unwrap();
586+ ///
587+ /// assert_eq!(formatted, format!("{:+05}", 12));
588+ /// ```
589+ ///
590+ /// # Errors
591+ ///
592+ /// It will return an error if the specified format string has invalid syntax,
593+ /// the type doesn't implement the expected trait, or the formatting it self
594+ /// failed.
595+ ///
596+ /// For more details have a look at [`Error`] and [`FormatArgumentError`].
597+ pub fn format < K : Borrow < str > + Eq + Hash > (
598+ format : & str ,
599+ context : & HashMap < K , Formattable > ,
600+ ) -> Result < String > {
601+ let mut out = String :: with_capacity ( format. len ( ) ) ;
602+ write ( & mut out, format, context) ?;
567603 Ok ( out)
568604}
0 commit comments