pub fn format_action_notification_string(format_string: &str, action_name: &str, notification: &Notification) -> String {
    let mut formatted: Vec<u8> = vec![];
    let bytes = format_string.as_bytes();
    let mut i = 0;
    while i < bytes.len() {
        let byte = bytes[i];
        // We need at least 2 chars to match a format string, so if we only have one, then let's
        // leave.
        if i == bytes.len()-1 {
            formatted.push(byte);
            i += 1;
            continue;
        }

        match byte {
            b'%' => {
                // This range is exclusive on the right hand side, so we go +2.
                match &format_string[i..i+2] {
                    // We need room for at least 2 brackets, so check for that.
                    "%t" => if i+4 < format_string.len() {
                        let (time_format, len) =
                            extract_time_format(&format_string[i+2..]).unwrap_or(("", 0));

                        formatted.extend_from_slice(
                            notification.time.format(time_format).to_string().as_bytes()
                        );

                        i += 2 + len;
                        continue;
                    }
                    "%s" => { formatted.extend_from_slice(notification.summary.as_bytes()); i += 2; continue },
                    "%b" => { formatted.extend_from_slice(notification.body.as_bytes()); i += 2; continue },
                    "%n" => { formatted.extend_from_slice(notification.app_name.as_bytes()); i += 2; continue },
                    "%a" => { formatted.extend_from_slice(action_name.as_bytes()); i += 2; continue },
                    "%i" => { formatted.extend_from_slice(notification.id.to_string().as_bytes()); i += 2; continue },
                    _ => (),
                }

                formatted.push(b'%');
            }

            _ => formatted.push(byte),
        }

        i += 1;
    }

    // We should be safe to use `from_utf8_unchecked` here, but let's be safe.
    String::from_utf8(formatted).expect("Error when formatting notification string.")
}
// str.replace() won't work for this because we'd have to do it twice: once for the summary and
// once for the body.  The first insertion could insert format strings which would mess up the
// second insertion.
// This solution is pretty fast (microseconds in release).
str.replace() won't work for this because we'd have to do it twice: once for the summary and
once for the body.  The first insertion could insert format strings which would mess up the
second insertion.
This solution is pretty fast (microseconds in release).
str . replace () won ' t work for this because we ' d have to do it twice : once for the summary and once for the body . The first insertion could insert format strings which would mess up the second insertion . This solution is pretty fast ( microseconds in release ) .
pub fn format_action_notification_string(format_string: &str, action_name: &str, notification: &Notification) -> String {
    let mut formatted: Vec<u8> = vec![];
    let bytes = format_string.as_bytes();
    let mut i = 0;
    while i < bytes.len() {
        let byte = bytes[i];
        // We need at least 2 chars to match a format string, so if we only have one, then let's
        // leave.
        if i == bytes.len()-1 {
            formatted.push(byte);
            i += 1;
            continue;
        }
        match byte {
            b'%' => {
                // This range is exclusive on the right hand side, so we go +2.
                match &format_string[i..i+2] {
                    // We need room for at least 2 brackets, so check for that.
                    "%t" => if i+4 < format_string.len() {
                        let (time_format, len) =
                            extract_time_format(&format_string[i+2..]).unwrap_or(("", 0));
                        formatted.extend_from_slice(
                            notification.time.format(time_format).to_string().as_bytes()
                        );
                        i += 2 + len;
                        continue;
                    }
                    "%s" => { formatted.extend_from_slice(notification.summary.as_bytes()); i += 2; continue },
                    "%b" => { formatted.extend_from_slice(notification.body.as_bytes()); i += 2; continue },
                    "%n" => { formatted.extend_from_slice(notification.app_name.as_bytes()); i += 2; continue },
                    "%a" => { formatted.extend_from_slice(action_name.as_bytes()); i += 2; continue },
                    "%i" => { formatted.extend_from_slice(notification.id.to_string().as_bytes()); i += 2; continue },
                    _ => (),
                }
                formatted.push(b'%');
            }
            _ => formatted.push(byte),
        }
        i += 1;
    }
    // We should be safe to use `from_utf8_unchecked` here, but let's be safe.
    String::from_utf8(formatted).expect("Error when formatting notification string.")
}
pub fn format_action_notification_string ( format_string : & str , action_name : & str , notification : & Notification ) -> String { let mut formatted : Vec < u8 > = vec ! [ ] ; let bytes = format_string . as_bytes ( ) ; let mut i = 0 ; while i < bytes . len ( ) { let byte = bytes [ i ] ; // We need at least 2 chars to match a format string, so if we only have one, then let's // leave. if i == bytes . len ( ) - 1 { formatted . push ( byte ) ; i += 1 ; continue ; } match byte { b'%' => { // This range is exclusive on the right hand side, so we go +2. match & format_string [ i .. i + 2 ] { // We need room for at least 2 brackets, so check for that. " " => if i + 4 < format_string . len ( ) { let ( time_format , len ) = extract_time_format ( & format_string [ i + 2 .. ] ) . unwrap_or ( ( " " , 0 ) ) ; formatted . extend_from_slice ( notification . time . format ( time_format ) . to_string ( ) . as_bytes ( ) ) ; i += 2 + len ; continue ; } " " => { formatted . extend_from_slice ( notification . summary . as_bytes ( ) ) ; i += 2 ; continue } , " " => { formatted . extend_from_slice ( notification . body . as_bytes ( ) ) ; i += 2 ; continue } , " " => { formatted . extend_from_slice ( notification . app_name . as_bytes ( ) ) ; i += 2 ; continue } , " " => { formatted . extend_from_slice ( action_name . as_bytes ( ) ) ; i += 2 ; continue } , " " => { formatted . extend_from_slice ( notification . id . to_string ( ) . as_bytes ( ) ) ; i += 2 ; continue } , _ => ( ) , } formatted . push ( b'%' ) ; } _ => formatted . push ( byte ) , } i += 1 ; } // We should be safe to use `from_utf8_unchecked` here, but let's be safe. String :: from_utf8 ( formatted ) . expect ( " " ) }
str.replace() won't work for this because we'd have to do it twice: once for the summary and
once for the body.
str . replace () won ' t work for this because we ' d have to do it twice : once for the summary and once for the body .
format_string
&str
action_name
&str
notification
&Notification
format_string
&str
action_name
&str
notification
&Notification