/// Translate this directive into an equivalent Rust formatting directive.
///
/// Returns `Err` in cases where the `printf` directive does not have an exact Rust
/// equivalent, rather than guessing.
Translate this directive into an equivalent Rust formatting directive.
Returns `Err` in cases where the `printf` directive does not have an exact Rust
equivalent, rather than guessing.
Translate this directive into an equivalent Rust formatting directive . Returns ` Err ` in cases where the ` printf ` directive does not have an exact Rust equivalent rather than guessing .
pub fn translate(&self) -> Result<String, Option<String>> {
            use std::fmt::Write;
            let (c_alt, c_zero, c_left, c_plus) = {
                let mut c_alt = false;
                let mut c_zero = false;
                let mut c_left = false;
                let mut c_plus = false;
                for c in self.flags.chars() {
                    match c {
                        '#' => c_alt = true,
                        '0' => c_zero = true,
                        '-' => c_left = true,
                        '+' => c_plus = true,
                        _ => {
                            return Err(Some(format!(
                                "the flag `{}` is unknown or unsupported",
                                c
                            )));
                        }
                    }
                }
                (c_alt, c_zero, c_left, c_plus)
            };
            // Has a special form in Rust for numbers.
            let fill = c_zero.then_some("0");
            let align = c_left.then_some("<");
            // Rust doesn't have an equivalent to the `' '` flag.
            let sign = c_plus.then_some("+");
            // Not *quite* the same, depending on the type...
            let alt = c_alt;
            let width = match self.width {
                Some(Num::Next) => {
                    // NOTE: Rust doesn't support this.
                    return Err(Some(
                        "you have to use a positional or named parameter for the width".to_string(),
                    ));
                }
                w @ Some(Num::Arg(_)) => w,
                w @ Some(Num::Num(_)) => w,
                None => None,
            };
            let precision = self.precision;
            // NOTE: although length *can* have an effect, we can't duplicate the effect in Rust, so
            // we just ignore it.
            let (type_, use_zero_fill, is_int) = match self.type_ {
                "d" | "i" | "u" => (None, true, true),
                "f" | "F" => (None, false, false),
                "s" | "c" => (None, false, false),
                "e" | "E" => (Some(self.type_), true, false),
                "x" | "X" | "o" => (Some(self.type_), true, true),
                "p" => (Some(self.type_), false, true),
                "g" => (Some("e"), true, false),
                "G" => (Some("E"), true, false),
                _ => {
                    return Err(Some(format!(
                        "the conversion specifier `{}` is unknown or unsupported",
                        self.type_
                    )));
                }
            };
            let (fill, width, precision) = match (is_int, width, precision) {
                (true, Some(_), Some(_)) => {
                    // Rust can't duplicate this insanity.
                    return Err(Some(
                        "width and precision cannot both be specified for integer conversions"
                            .to_string(),
                    ));
                }
                (true, None, Some(p)) => (Some("0"), Some(p), None),
                (true, w, None) => (fill, w, None),
                (false, w, p) => (fill, w, p),
            };
            let align = match (self.type_, width.is_some(), align.is_some()) {
                ("s", true, false) => Some(">"),
                _ => align,
            };
            let (fill, zero_fill) = match (fill, use_zero_fill) {
                (Some("0"), true) => (None, true),
                (fill, _) => (fill, false),
            };
            let alt = match type_ {
                Some("x" | "X") => alt,
                _ => false,
            };
            let has_options = fill.is_some()
                || align.is_some()
                || sign.is_some()
                || alt
                || zero_fill
                || width.is_some()
                || precision.is_some()
                || type_.is_some();
            // Initialise with a rough guess.
            let cap = self.span.len() + if has_options { 2 } else { 0 };
            let mut s = String::with_capacity(cap);
            s.push('{');
            if let Some(arg) = self.parameter {
                match write!(
                    s,
                    "{}",
                    match arg.checked_sub(1) {
                        Some(a) => a,
                        None => return Err(None),
                    }
                ) {
                    Err(_) => return Err(None),
                    _ => {}
                }
            }
            if has_options {
                s.push(':');
                let align = if let Some(fill) = fill {
                    s.push_str(fill);
                    align.or(Some(">"))
                } else {
                    align
                };
                if let Some(align) = align {
                    s.push_str(align);
                }
                if let Some(sign) = sign {
                    s.push_str(sign);
                }
                if alt {
                    s.push('#');
                }
                if zero_fill {
                    s.push('0');
                }
                if let Some(width) = width {
                    match width.translate(&mut s) {
                        Err(_) => return Err(None),
                        _ => {}
                    }
                }
                if let Some(precision) = precision {
                    s.push('.');
                    match precision.translate(&mut s) {
                        Err(_) => return Err(None),
                        _ => {}
                    }
                }
                if let Some(type_) = type_ {
                    s.push_str(type_);
                }
            }
            s.push('}');
            Ok(s)
        }
pub fn translate ( & self ) -> Result < String , Option < String > > { use std :: fmt :: Write ; let ( c_alt , c_zero , c_left , c_plus ) = { let mut c_alt = false ; let mut c_zero = false ; let mut c_left = false ; let mut c_plus = false ; for c in self . flags . chars ( ) { match c { '#' => c_alt = true , '0' => c_zero = true , '-' => c_left = true , '+' => c_plus = true , _ => { return Err ( Some ( format ! ( " " c ) ) ) ; } } } ( c_alt , c_zero , c_left , c_plus ) } ; // Has a special form in Rust for numbers. let fill = c_zero . then_some ( " " ) ; let align = c_left . then_some ( " " ) ; // Rust doesn't have an equivalent to the `' '` flag. let sign = c_plus . then_some ( " " ) ; // Not *quite* the same, depending on the type... let alt = c_alt ; let width = match self . width { Some ( Num :: Next ) => { // NOTE: Rust doesn't support this. return Err ( Some ( " " . to_string ( ) , ) ) ; } w @ Some ( Num :: Arg ( _ ) ) => w , w @ Some ( Num :: Num ( _ ) ) => w , None => None , } ; let precision = self . precision ; // NOTE: although length *can* have an effect, we can't duplicate the effect in Rust, so // we just ignore it. let ( type_ , use_zero_fill , is_int ) = match self . type_ { " " | " " | " " => ( None , true , true ) , " " | " " => ( None , false , false ) , " " | " " => ( None , false , false ) , " " | " " => ( Some ( self . type_ ) , true , false ) , " " | " " | " " => ( Some ( self . type_ ) , true , true ) , " " => ( Some ( self . type_ ) , false , true ) , " " => ( Some ( " " ) , true , false ) , " " => ( Some ( " " ) , true , false ) , _ => { return Err ( Some ( format ! ( " " self type_ ) ) ) ; } } ; let ( fill , width , precision ) = match ( is_int , width , precision ) { ( true , Some ( _ ) , Some ( _ ) ) => { // Rust can't duplicate this insanity. return Err ( Some ( " " . to_string ( ) , ) ) ; } ( true , None , Some ( p ) ) => ( Some ( " " ) , Some ( p ) , None ) , ( true , w , None ) => ( fill , w , None ) , ( false , w , p ) => ( fill , w , p ) , } ; let align = match ( self . type_ , width . is_some ( ) , align . is_some ( ) ) { ( " " , true , false ) => Some ( " " ) , _ => align , } ; let ( fill , zero_fill ) = match ( fill , use_zero_fill ) { ( Some ( " " ) , true ) => ( None , true ) , ( fill , _ ) => ( fill , false ) , } ; let alt = match type_ { Some ( " " | " " ) => alt , _ => false , } ; let has_options = fill . is_some ( ) || align . is_some ( ) || sign . is_some ( ) || alt || zero_fill || width . is_some ( ) || precision . is_some ( ) || type_ . is_some ( ) ; // Initialise with a rough guess. let cap = self . span . len ( ) + if has_options { 2 } else { 0 } ; let mut s = String :: with_capacity ( cap ) ; s . push ( '{' ) ; if let Some ( arg ) = self . parameter { match write ! ( s " " match arg checked_sub ( 1 ) { Some ( a ) a None return Err ( None ) } ) { Err ( _ ) => return Err ( None ) , _ => { } } } if has_options { s . push ( ':' ) ; let align = if let Some ( fill ) = fill { s . push_str ( fill ) ; align . or ( Some ( " " ) ) } else { align } ; if let Some ( align ) = align { s . push_str ( align ) ; } if let Some ( sign ) = sign { s . push_str ( sign ) ; } if alt { s . push ( '#' ) ; } if zero_fill { s . push ( '0' ) ; } if let Some ( width ) = width { match width . translate ( & mut s ) { Err ( _ ) => return Err ( None ) , _ => { } } } if let Some ( precision ) = precision { s . push ( '.' ) ; match precision . translate ( & mut s ) { Err ( _ ) => return Err ( None ) , _ => { } } } if let Some ( type_ ) = type_ { s . push_str ( type_ ) ; } } s . push ( '}' ) ; Ok ( s ) }
Translate this directive into an equivalent Rust formatting directive.
Translate this directive into an equivalent Rust formatting directive .
&self