<commit_before>//! Tidy check to ensure below in UI test directories:
//! - the number of entries in each directory must be less than `ENTRY_LIMIT`
//! - there are no stray `.stderr` files

use std::fs;
use std::path::Path;

const ENTRY_LIMIT: usize = 1000;
// FIXME: The following limits should be reduced eventually.
const ROOT_ENTRY_LIMIT: usize = 1102;
const ISSUES_ENTRY_LIMIT: usize = 2310;
const PARSER_LIMIT: usize = 1004;

fn check_entries(path: &Path, bad: &mut bool) {
    let dirs = walkdir::WalkDir::new(&path.join("test/ui"))
        .into_iter()
        .filter_entry(|e| e.file_type().is_dir());
    for dir in dirs {
        if let Ok(dir) = dir {
            let dir_path = dir.path();

            // Use special values for these dirs.
            let is_root = path.join("test/ui") == dir_path;
            let is_issues_dir = path.join("test/ui/issues") == dir_path;
            let is_parser = path.join("test/ui/parser") == dir_path;
            let limit = if is_root {
                ROOT_ENTRY_LIMIT
            } else if is_issues_dir {
                ISSUES_ENTRY_LIMIT
            } else if is_parser {
                PARSER_LIMIT
            } else {
                ENTRY_LIMIT
            };

            let count = std::fs::read_dir(dir_path).unwrap().count();
            if count > limit {
                tidy_error!(
                    bad,
                    "following path contains more than {} entries, \
                    you should move the test to some relevant subdirectory (current: {}): {}",
                    limit,
                    count,
                    dir_path.display()
                );
            }
        }
    }
}

pub fn check(path: &Path, bad: &mut bool) {
    check_entries(&path, bad);
    for path in &[&path.join("test/ui"), &path.join("test/ui-fulldeps")] {
        super::walk_no_read(path, &mut |_| false, &mut |entry| {
            let file_path = entry.path();
            if let Some(ext) = file_path.extension() {
                if ext == "stderr" || ext == "stdout" {
                    // Test output filenames have one of the formats:
                    // ```
                    // $testname.stderr
                    // $testname.$mode.stderr
                    // $testname.$revision.stderr
                    // $testname.$revision.$mode.stderr
                    // ```
                    //
                    // For now, just make sure that there is a corresponding
                    // `$testname.rs` file.
                    //
                    // NB: We do not use file_stem() as some file names have multiple `.`s and we
                    // must strip all of them.
                    let testname =
                        file_path.file_name().unwrap().to_str().unwrap().split_once('.').unwrap().0;
                    if !file_path.with_file_name(testname).with_extension("rs").exists() {
                        tidy_error!(bad, "Stray file with UI testing output: {:?}", file_path);
                    }

                    if let Ok(metadata) = fs::metadata(file_path) {
                        if metadata.len() == 0 {
                            tidy_error!(bad, "Empty file with UI testing output: {:?}", file_path);
                        }
                    }
                }
            }
        });
    }
}
<commit_msg>Increase tidy limit for parser by 1<commit_after>//! Tidy check to ensure below in UI test directories:
//! - the number of entries in each directory must be less than `ENTRY_LIMIT`
//! - there are no stray `.stderr` files

use std::fs;
use std::path::Path;

const ENTRY_LIMIT: usize = 1000;
// FIXME: The following limits should be reduced eventually.
const ROOT_ENTRY_LIMIT: usize = 1102;
const ISSUES_ENTRY_LIMIT: usize = 2310;
const PARSER_LIMIT: usize = 1005;

fn check_entries(path: &Path, bad: &mut bool) {
    let dirs = walkdir::WalkDir::new(&path.join("test/ui"))
        .into_iter()
        .filter_entry(|e| e.file_type().is_dir());
    for dir in dirs {
        if let Ok(dir) = dir {
            let dir_path = dir.path();

            // Use special values for these dirs.
            let is_root = path.join("test/ui") == dir_path;
            let is_issues_dir = path.join("test/ui/issues") == dir_path;
            let is_parser = path.join("test/ui/parser") == dir_path;
            let limit = if is_root {
                ROOT_ENTRY_LIMIT
            } else if is_issues_dir {
                ISSUES_ENTRY_LIMIT
            } else if is_parser {
                PARSER_LIMIT
            } else {
                ENTRY_LIMIT
            };

            let count = std::fs::read_dir(dir_path).unwrap().count();
            if count > limit {
                tidy_error!(
                    bad,
                    "following path contains more than {} entries, \
                    you should move the test to some relevant subdirectory (current: {}): {}",
                    limit,
                    count,
                    dir_path.display()
                );
            }
        }
    }
}

pub fn check(path: &Path, bad: &mut bool) {
    check_entries(&path, bad);
    for path in &[&path.join("test/ui"), &path.join("test/ui-fulldeps")] {
        super::walk_no_read(path, &mut |_| false, &mut |entry| {
            let file_path = entry.path();
            if let Some(ext) = file_path.extension() {
                if ext == "stderr" || ext == "stdout" {
                    // Test output filenames have one of the formats:
                    // ```
                    // $testname.stderr
                    // $testname.$mode.stderr
                    // $testname.$revision.stderr
                    // $testname.$revision.$mode.stderr
                    // ```
                    //
                    // For now, just make sure that there is a corresponding
                    // `$testname.rs` file.
                    //
                    // NB: We do not use file_stem() as some file names have multiple `.`s and we
                    // must strip all of them.
                    let testname =
                        file_path.file_name().unwrap().to_str().unwrap().split_once('.').unwrap().0;
                    if !file_path.with_file_name(testname).with_extension("rs").exists() {
                        tidy_error!(bad, "Stray file with UI testing output: {:?}", file_path);
                    }

                    if let Ok(metadata) = fs::metadata(file_path) {
                        if metadata.len() == 0 {
                            tidy_error!(bad, "Empty file with UI testing output: {:?}", file_path);
                        }
                    }
                }
            }
        });
    }
}
<|endoftext|>


<commit_before>//! SMTP commands

use std::fmt::{self, Display, Formatter};

use crate::{
    address::Address,
    transport::smtp::{
        authentication::{Credentials, Mechanism},
        error::{self, Error},
        extension::{ClientId, MailParameter, RcptParameter},
        response::Response,
    },
};

/// EHLO command
#[derive(PartialEq, Eq, Clone, Debug)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct Ehlo {
    client_id: ClientId,
}

impl Display for Ehlo {
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
        write!(f, "EHLO {}\r\n", self.client_id)
    }
}

impl Ehlo {
    /// Creates a EHLO command
    pub fn new(client_id: ClientId) -> Ehlo {
        Ehlo { client_id }
    }
}

/// STARTTLS command
#[derive(PartialEq, Eq, Clone, Debug, Copy)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct Starttls;

impl Display for Starttls {
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
        f.write_str("STARTTLS\r\n")
    }
}

/// MAIL command
#[derive(PartialEq, Eq, Clone, Debug)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct Mail {
    sender: Option<Address>,
    parameters: Vec<MailParameter>,
}

impl Display for Mail {
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
        write!(
            f,
            "MAIL FROM:<{}>",
            self.sender.as_ref().map_or("", |s| s.as_ref())
        )?;
        for parameter in &self.parameters {
            write!(f, " {}", parameter)?;
        }
        f.write_str("\r\n")
    }
}

impl Mail {
    /// Creates a MAIL command
    pub fn new(sender: Option<Address>, parameters: Vec<MailParameter>) -> Mail {
        Mail { sender, parameters }
    }
}

/// RCPT command
#[derive(PartialEq, Eq, Clone, Debug)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct Rcpt {
    recipient: Address,
    parameters: Vec<RcptParameter>,
}

impl Display for Rcpt {
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
        write!(f, "RCPT TO:<{}>", self.recipient)?;
        for parameter in &self.parameters {
            write!(f, " {}", parameter)?;
        }
        f.write_str("\r\n")
    }
}

impl Rcpt {
    /// Creates an RCPT command
    pub fn new(recipient: Address, parameters: Vec<RcptParameter>) -> Rcpt {
        Rcpt {
            recipient,
            parameters,
        }
    }
}

/// DATA command
#[derive(PartialEq, Eq, Clone, Debug, Copy)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct Data;

impl Display for Data {
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
        f.write_str("DATA\r\n")
    }
}

/// QUIT command
#[derive(PartialEq, Eq, Clone, Debug, Copy)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct Quit;

impl Display for Quit {
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
        f.write_str("QUIT\r\n")
    }
}

/// NOOP command
#[derive(PartialEq, Eq, Clone, Debug, Copy)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct Noop;

impl Display for Noop {
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
        f.write_str("NOOP\r\n")
    }
}

/// HELP command
#[derive(PartialEq, Eq, Clone, Debug)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct Help {
    argument: Option<String>,
}

impl Display for Help {
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
        f.write_str("HELP")?;
        if let Some(argument) = &self.argument {
            write!(f, " {}", argument)?;
        }
        f.write_str("\r\n")
    }
}

impl Help {
    /// Creates an HELP command
    pub fn new(argument: Option<String>) -> Help {
        Help { argument }
    }
}

/// VRFY command
#[derive(PartialEq, Eq, Clone, Debug)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct Vrfy {
    argument: String,
}

impl Display for Vrfy {
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
        write!(f, "VRFY {}\r\n", self.argument)
    }
}

impl Vrfy {
    /// Creates a VRFY command
    pub fn new(argument: String) -> Vrfy {
        Vrfy { argument }
    }
}

/// EXPN command
#[derive(PartialEq, Eq, Clone, Debug)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct Expn {
    argument: String,
}

impl Display for Expn {
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
        write!(f, "EXPN {}\r\n", self.argument)
    }
}

impl Expn {
    /// Creates an EXPN command
    pub fn new(argument: String) -> Expn {
        Expn { argument }
    }
}

/// RSET command
#[derive(PartialEq, Eq, Clone, Debug, Copy)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct Rset;

impl Display for Rset {
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
        f.write_str("RSET\r\n")
    }
}

/// AUTH command
#[derive(PartialEq, Eq, Clone, Debug)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct Auth {
    mechanism: Mechanism,
    credentials: Credentials,
    challenge: Option<String>,
    response: Option<String>,
}

impl Display for Auth {
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
        let encoded_response = self.response.as_ref().map(base64::encode);

        if self.mechanism.supports_initial_response() {
            write!(f, "AUTH {} {}", self.mechanism, encoded_response.unwrap())?;
        } else {
            match encoded_response {
                Some(response) => f.write_str(&response)?,
                None => write!(f, "AUTH {}", self.mechanism)?,
            }
        }
        f.write_str("\r\n")
    }
}

impl Auth {
    /// Creates an AUTH command (from a challenge if provided)
    pub fn new(
        mechanism: Mechanism,
        credentials: Credentials,
        challenge: Option<String>,
    ) -> Result<Auth, Error> {
        let response = if mechanism.supports_initial_response() || challenge.is_some() {
            Some(mechanism.response(&credentials, challenge.as_deref())?)
        } else {
            None
        };
        Ok(Auth {
            mechanism,
            credentials,
            challenge,
            response,
        })
    }

    /// Creates an AUTH command from a response that needs to be a
    /// valid challenge (with 334 response code)
    pub fn new_from_response(
        mechanism: Mechanism,
        credentials: Credentials,
        response: &Response,
    ) -> Result<Auth, Error> {
        if !response.has_code(334) {
            return Err(error::response("Expecting a challenge"));
        }

        let encoded_challenge = response
            .first_word()
            .ok_or_else(|| error::response("Could not read auth challenge"))?;
        #[cfg(feature = "tracing")]
        tracing::debug!("auth encoded challenge: {}", encoded_challenge);

        let decoded_base64 = base64::decode(&encoded_challenge).map_err(error::response)?;
        let decoded_challenge = String::from_utf8(decoded_base64).map_err(error::response)?;
        #[cfg(feature = "tracing")]
        tracing::debug!("auth decoded challenge: {}", decoded_challenge);

        let response = Some(mechanism.response(&credentials, Some(decoded_challenge.as_ref()))?);

        Ok(Auth {
            mechanism,
            credentials,
            challenge: Some(decoded_challenge),
            response,
        })
    }
}

#[cfg(test)]
mod test {
    use std::str::FromStr;

    use super::*;
    use crate::transport::smtp::extension::MailBodyParameter;

    #[test]
    fn test_display() {
        let id = ClientId::Domain("localhost".to_string());
        let email = Address::from_str("test@example.com").unwrap();
        let mail_parameter = MailParameter::Other {
            keyword: "TEST".to_string(),
            value: Some("value".to_string()),
        };
        let rcpt_parameter = RcptParameter::Other {
            keyword: "TEST".to_string(),
            value: Some("value".to_string()),
        };
        assert_eq!(format!("{}", Ehlo::new(id)), "EHLO localhost\r\n");
        assert_eq!(
            format!("{}", Mail::new(Some(email.clone()), vec![])),
            "MAIL FROM:<test@example.com>\r\n"
        );
        assert_eq!(format!("{}", Mail::new(None, vec![])), "MAIL FROM:<>\r\n");
        assert_eq!(
            format!(
                "{}",
                Mail::new(Some(email.clone()), vec![MailParameter::Size(42)])
            ),
            "MAIL FROM:<test@example.com> SIZE=42\r\n"
        );
        assert_eq!(
            format!(
                "{}",
                Mail::new(
                    Some(email.clone()),
                    vec![
                        MailParameter::Size(42),
                        MailParameter::Body(MailBodyParameter::EightBitMime),
                        mail_parameter,
                    ],
                )
            ),
            "MAIL FROM:<test@example.com> SIZE=42 BODY=8BITMIME TEST=value\r\n"
        );
        assert_eq!(
            format!("{}", Rcpt::new(email.clone(), vec![])),
            "RCPT TO:<test@example.com>\r\n"
        );
        assert_eq!(
            format!("{}", Rcpt::new(email, vec![rcpt_parameter])),
            "RCPT TO:<test@example.com> TEST=value\r\n"
        );
        assert_eq!(format!("{}", Quit), "QUIT\r\n");
        assert_eq!(format!("{}", Data), "DATA\r\n");
        assert_eq!(format!("{}", Noop), "NOOP\r\n");
        assert_eq!(format!("{}", Help::new(None)), "HELP\r\n");
        assert_eq!(
            format!("{}", Help::new(Some("test".to_string()))),
            "HELP test\r\n"
        );
        assert_eq!(
            format!("{}", Vrfy::new("test".to_string())),
            "VRFY test\r\n"
        );
        assert_eq!(
            format!("{}", Expn::new("test".to_string())),
            "EXPN test\r\n"
        );
        assert_eq!(format!("{}", Rset), "RSET\r\n");
        let credentials = Credentials::new("user".to_string(), "password".to_string());
        assert_eq!(
            format!(
                "{}",
                Auth::new(Mechanism::Plain, credentials.clone(), None).unwrap()
            ),
            "AUTH PLAIN AHVzZXIAcGFzc3dvcmQ=\r\n"
        );
        assert_eq!(
            format!(
                "{}",
                Auth::new(Mechanism::Login, credentials, None).unwrap()
            ),
            "AUTH LOGIN\r\n"
        );
    }
}
<commit_msg>clippy: fix latest warning (#818)<commit_after>//! SMTP commands

use std::fmt::{self, Display, Formatter};

use crate::{
    address::Address,
    transport::smtp::{
        authentication::{Credentials, Mechanism},
        error::{self, Error},
        extension::{ClientId, MailParameter, RcptParameter},
        response::Response,
    },
};

/// EHLO command
#[derive(PartialEq, Eq, Clone, Debug)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct Ehlo {
    client_id: ClientId,
}

impl Display for Ehlo {
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
        write!(f, "EHLO {}\r\n", self.client_id)
    }
}

impl Ehlo {
    /// Creates a EHLO command
    pub fn new(client_id: ClientId) -> Ehlo {
        Ehlo { client_id }
    }
}

/// STARTTLS command
#[derive(PartialEq, Eq, Clone, Debug, Copy)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct Starttls;

impl Display for Starttls {
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
        f.write_str("STARTTLS\r\n")
    }
}

/// MAIL command
#[derive(PartialEq, Eq, Clone, Debug)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct Mail {
    sender: Option<Address>,
    parameters: Vec<MailParameter>,
}

impl Display for Mail {
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
        write!(
            f,
            "MAIL FROM:<{}>",
            self.sender.as_ref().map_or("", |s| s.as_ref())
        )?;
        for parameter in &self.parameters {
            write!(f, " {}", parameter)?;
        }
        f.write_str("\r\n")
    }
}

impl Mail {
    /// Creates a MAIL command
    pub fn new(sender: Option<Address>, parameters: Vec<MailParameter>) -> Mail {
        Mail { sender, parameters }
    }
}

/// RCPT command
#[derive(PartialEq, Eq, Clone, Debug)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct Rcpt {
    recipient: Address,
    parameters: Vec<RcptParameter>,
}

impl Display for Rcpt {
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
        write!(f, "RCPT TO:<{}>", self.recipient)?;
        for parameter in &self.parameters {
            write!(f, " {}", parameter)?;
        }
        f.write_str("\r\n")
    }
}

impl Rcpt {
    /// Creates an RCPT command
    pub fn new(recipient: Address, parameters: Vec<RcptParameter>) -> Rcpt {
        Rcpt {
            recipient,
            parameters,
        }
    }
}

/// DATA command
#[derive(PartialEq, Eq, Clone, Debug, Copy)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct Data;

impl Display for Data {
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
        f.write_str("DATA\r\n")
    }
}

/// QUIT command
#[derive(PartialEq, Eq, Clone, Debug, Copy)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct Quit;

impl Display for Quit {
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
        f.write_str("QUIT\r\n")
    }
}

/// NOOP command
#[derive(PartialEq, Eq, Clone, Debug, Copy)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct Noop;

impl Display for Noop {
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
        f.write_str("NOOP\r\n")
    }
}

/// HELP command
#[derive(PartialEq, Eq, Clone, Debug)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct Help {
    argument: Option<String>,
}

impl Display for Help {
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
        f.write_str("HELP")?;
        if let Some(argument) = &self.argument {
            write!(f, " {}", argument)?;
        }
        f.write_str("\r\n")
    }
}

impl Help {
    /// Creates an HELP command
    pub fn new(argument: Option<String>) -> Help {
        Help { argument }
    }
}

/// VRFY command
#[derive(PartialEq, Eq, Clone, Debug)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct Vrfy {
    argument: String,
}

impl Display for Vrfy {
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
        write!(f, "VRFY {}\r\n", self.argument)
    }
}

impl Vrfy {
    /// Creates a VRFY command
    pub fn new(argument: String) -> Vrfy {
        Vrfy { argument }
    }
}

/// EXPN command
#[derive(PartialEq, Eq, Clone, Debug)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct Expn {
    argument: String,
}

impl Display for Expn {
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
        write!(f, "EXPN {}\r\n", self.argument)
    }
}

impl Expn {
    /// Creates an EXPN command
    pub fn new(argument: String) -> Expn {
        Expn { argument }
    }
}

/// RSET command
#[derive(PartialEq, Eq, Clone, Debug, Copy)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct Rset;

impl Display for Rset {
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
        f.write_str("RSET\r\n")
    }
}

/// AUTH command
#[derive(PartialEq, Eq, Clone, Debug)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct Auth {
    mechanism: Mechanism,
    credentials: Credentials,
    challenge: Option<String>,
    response: Option<String>,
}

impl Display for Auth {
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
        let encoded_response = self.response.as_ref().map(base64::encode);

        if self.mechanism.supports_initial_response() {
            write!(f, "AUTH {} {}", self.mechanism, encoded_response.unwrap())?;
        } else {
            match encoded_response {
                Some(response) => f.write_str(&response)?,
                None => write!(f, "AUTH {}", self.mechanism)?,
            }
        }
        f.write_str("\r\n")
    }
}

impl Auth {
    /// Creates an AUTH command (from a challenge if provided)
    pub fn new(
        mechanism: Mechanism,
        credentials: Credentials,
        challenge: Option<String>,
    ) -> Result<Auth, Error> {
        let response = if mechanism.supports_initial_response() || challenge.is_some() {
            Some(mechanism.response(&credentials, challenge.as_deref())?)
        } else {
            None
        };
        Ok(Auth {
            mechanism,
            credentials,
            challenge,
            response,
        })
    }

    /// Creates an AUTH command from a response that needs to be a
    /// valid challenge (with 334 response code)
    pub fn new_from_response(
        mechanism: Mechanism,
        credentials: Credentials,
        response: &Response,
    ) -> Result<Auth, Error> {
        if !response.has_code(334) {
            return Err(error::response("Expecting a challenge"));
        }

        let encoded_challenge = response
            .first_word()
            .ok_or_else(|| error::response("Could not read auth challenge"))?;
        #[cfg(feature = "tracing")]
        tracing::debug!("auth encoded challenge: {}", encoded_challenge);

        let decoded_base64 = base64::decode(encoded_challenge).map_err(error::response)?;
        let decoded_challenge = String::from_utf8(decoded_base64).map_err(error::response)?;
        #[cfg(feature = "tracing")]
        tracing::debug!("auth decoded challenge: {}", decoded_challenge);

        let response = Some(mechanism.response(&credentials, Some(decoded_challenge.as_ref()))?);

        Ok(Auth {
            mechanism,
            credentials,
            challenge: Some(decoded_challenge),
            response,
        })
    }
}

#[cfg(test)]
mod test {
    use std::str::FromStr;

    use super::*;
    use crate::transport::smtp::extension::MailBodyParameter;

    #[test]
    fn test_display() {
        let id = ClientId::Domain("localhost".to_string());
        let email = Address::from_str("test@example.com").unwrap();
        let mail_parameter = MailParameter::Other {
            keyword: "TEST".to_string(),
            value: Some("value".to_string()),
        };
        let rcpt_parameter = RcptParameter::Other {
            keyword: "TEST".to_string(),
            value: Some("value".to_string()),
        };
        assert_eq!(format!("{}", Ehlo::new(id)), "EHLO localhost\r\n");
        assert_eq!(
            format!("{}", Mail::new(Some(email.clone()), vec![])),
            "MAIL FROM:<test@example.com>\r\n"
        );
        assert_eq!(format!("{}", Mail::new(None, vec![])), "MAIL FROM:<>\r\n");
        assert_eq!(
            format!(
                "{}",
                Mail::new(Some(email.clone()), vec![MailParameter::Size(42)])
            ),
            "MAIL FROM:<test@example.com> SIZE=42\r\n"
        );
        assert_eq!(
            format!(
                "{}",
                Mail::new(
                    Some(email.clone()),
                    vec![
                        MailParameter::Size(42),
                        MailParameter::Body(MailBodyParameter::EightBitMime),
                        mail_parameter,
                    ],
                )
            ),
            "MAIL FROM:<test@example.com> SIZE=42 BODY=8BITMIME TEST=value\r\n"
        );
        assert_eq!(
            format!("{}", Rcpt::new(email.clone(), vec![])),
            "RCPT TO:<test@example.com>\r\n"
        );
        assert_eq!(
            format!("{}", Rcpt::new(email, vec![rcpt_parameter])),
            "RCPT TO:<test@example.com> TEST=value\r\n"
        );
        assert_eq!(format!("{}", Quit), "QUIT\r\n");
        assert_eq!(format!("{}", Data), "DATA\r\n");
        assert_eq!(format!("{}", Noop), "NOOP\r\n");
        assert_eq!(format!("{}", Help::new(None)), "HELP\r\n");
        assert_eq!(
            format!("{}", Help::new(Some("test".to_string()))),
            "HELP test\r\n"
        );
        assert_eq!(
            format!("{}", Vrfy::new("test".to_string())),
            "VRFY test\r\n"
        );
        assert_eq!(
            format!("{}", Expn::new("test".to_string())),
            "EXPN test\r\n"
        );
        assert_eq!(format!("{}", Rset), "RSET\r\n");
        let credentials = Credentials::new("user".to_string(), "password".to_string());
        assert_eq!(
            format!(
                "{}",
                Auth::new(Mechanism::Plain, credentials.clone(), None).unwrap()
            ),
            "AUTH PLAIN AHVzZXIAcGFzc3dvcmQ=\r\n"
        );
        assert_eq!(
            format!(
                "{}",
                Auth::new(Mechanism::Login, credentials, None).unwrap()
            ),
            "AUTH LOGIN\r\n"
        );
    }
}
<|endoftext|>


<commit_before>//! Extensions to existing types used in the zwreec compiler
//!
//! Currently this contains only extensions to the Iterator trait yielding new Iterator types
//! that wrap certain functionality, that is used to filter/construct/lookahead all objects
//! passed and iterated upon in the compiler, making it possible to have most of the compiler
//! chain to be lazy_evaluated and even multi-threaded.

use std::iter::Peekable;
use std::sync::mpsc;
use std::thread;

/// An iterator that performs a lookahead of 1, utilizing the existing Peakable Iterator
/// Can be stacked to perform an even greater lookahead
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
#[derive(Clone)]
pub struct Peeking<I, A> where
    A: Clone,
    I: Iterator<Item=A>,
{
    iter: Peekable<I>,
}

impl<I, A> Iterator for Peeking<I, A> where
    A: Clone,
    I: Iterator<Item=A>
{
    type Item = (A, Option<A>);

    #[inline]
    fn next(&mut self) -> Option<(A, Option<A>)> {
        match self.iter.next() {
            Some(item) => Some((item,
                match self.iter.peek() {
                    Some(ref item) => Some((*item).clone()),
                    None => None,
                }
            )),
            None => None,
        }
    }

    #[inline]
    fn size_hint(&self) -> (usize, Option<usize>) {
        self.iter.size_hint()
    }
}

/// An extension for sized Iterators that specifies a function that returns a Peeking Iterator
pub trait PeekingExt {

    /// Consumes this Iterator and returns a Peeking Iterator
    fn peeking(self) -> Peeking<Self, Self::Item>
        where Self: Sized+Iterator,
              Self::Item: Clone;
}

impl<A: Clone, I: Sized+Iterator<Item=A>> PeekingExt for I {
    fn peeking(self) -> Peeking<Self, A>
        where Self: Sized+Iterator
    {
         Peeking { iter: self.peekable() }
    }
}

/// An iterator to maintain state while iterating another iterator and allows filtering
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
#[derive(Clone)]
pub struct FilteringScan<I, St, F> {
    iter: I,
    f: F,
    state: St,
}

impl<B, I, St, F> Iterator for FilteringScan<I, St, F> where
    I: Iterator,
    F: FnMut(&mut St, I::Item) -> Option<B>,
{
    type Item = B;

    #[inline]
    fn next(&mut self) -> Option<B> {
        loop {
            match self.iter.next() {
                Some(next) => match (self.f)(&mut self.state, next) {
                    Some(result) => return Some(result),
                    None => continue,
                },
                None => return None,
            }
        }
    }

    #[inline]
    fn size_hint(&self) -> (usize, Option<usize>) {
        let (_, upper) = self.iter.size_hint();
        (0, upper) // can't know a lower bound, due to the scan function
    }
}

/// An extension to sized Iterators that specifies a function that returns a FilteringScan Iterator
pub trait FilteringScanExt {

    /// Consumes this Iterator and returns a FilteringScan Iterator
    fn scan_filter<St, B, F>(self, initial_state: St, f: F) -> FilteringScan<Self, St, F>
        where Self: Sized+Iterator, F: FnMut(&mut St, Self::Item) -> Option<B>;
}

impl<I: Sized+Iterator> FilteringScanExt for I {
    fn scan_filter<St, B, F>(self, initial_state: St, f: F) -> FilteringScan<Self, St, F>
        where Self: Sized+Iterator, F: FnMut(&mut St, I::Item) -> Option<B>,
    {
        FilteringScan{iter: self, f: f, state: initial_state}
    }
}

/// The result of a parsing operation
#[derive(Clone)]
pub enum ParseResult {
    /// Continue parsing
    Continue,

    /// Halt parsing because an error occured
    Halt,

    /// End parsing because the last Token was processed
    End,
}

/// An iterator to maintain state while iterating another iterator and allows more complex parsing
// (allowing holding the current iterator value, continue if its goes empty and filter the output)
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
#[derive(Clone)]
pub struct Parser<I, A, St, F> where
    A: Clone,
    I: Iterator<Item=A>,
{
    iter: I,
    f: F,
    state: St,

    iter_state: ParseResult,
    current_elem: Option<A>,
}

impl<B, I, St, F, A> Iterator for Parser<I, A, St, F> where
    A: Clone,
    I: Iterator<Item=A>,
    F: FnMut(&mut St, Option<I::Item>) -> (ParseResult, Option<B>),
{
    type Item = B;

    #[inline]
    fn next(&mut self) -> Option<B> {
        loop {
            match self.iter_state {
                ParseResult::Continue => self.current_elem = self.iter.next(),
                ParseResult::Halt => {},
                ParseResult::End => return None,
            };

            let (new_state, result) = (self.f) (&mut self.state, self.current_elem.clone());

            self.iter_state = new_state;

            match result {
                Some(result) => return Some(result),
                None => continue,
            }
        }
    }

    #[inline]
    fn size_hint(&self) -> (usize, Option<usize>) {
        (0, None) // can't know a lower or upper bound, due to the parse function
    }
}

/// An extension to sized Iterators that specifies a function that returns a Parser Iterator
pub trait ParserExt {

    /// Consumes this Iterator and returns a FilteringScan Iterator
    fn parsing<St, B, F>(self, initial_state: St, f: F) -> Parser<Self, Self::Item, St, F>
        where Self: Sized+Iterator, Self::Item: Clone, F: Fn(&mut St, Option<Self::Item>) -> (ParseResult, Option<B>);
}

impl<A:Clone, I: Sized+Iterator<Item=A>>ParserExt for I {
    fn parsing<St, B, F>(self, initial_state: St, f: F) -> Parser<Self, A, St, F>
        where F: FnMut(&mut St, Option<A>) -> (ParseResult, Option<B>),
    {
        Parser{iter: self, f: f, state: initial_state, iter_state: ParseResult::Continue, current_elem: None}
    }
}

/// An iterator to maintain state while iterating another iterator and allows to hold the currently active
/// object to modify it (/construct it), until the next element is created
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
#[derive(Clone)]
pub struct Constructor<I, St, B, F>
    where
    I: Iterator,
    B: Clone,
    F: FnMut(&mut St, &mut Option<B>, I::Item) -> Option<B> {
        iter: I,
        state: St,
        f: F,
        current_elem: Option<B>,
}

impl<I, St, B, F> Iterator for Constructor<I, St, B, F> where
    I: Iterator,
    B: Clone,
    F: FnMut(&mut St, &mut Option<B>, I::Item) -> Option<B>,
{
    type Item = B;

    #[inline]
    fn next(&mut self) -> Option<B> {
        while let Some(elem) =  self.iter.next() {
            match (self.f)(&mut self.state, &mut self.current_elem, elem) {
                Some(elem) => {
                    let return_val = self.current_elem.clone();
                    self.current_elem = Some(elem);
                    match return_val {
                        Some(value) => return Some(value),
                        None => continue,
                    }
                },
                None => continue,
            }
        }

        let result = self.current_elem.clone();
        self.current_elem = None;
        result
    }

    #[inline]
    fn size_hint(&self) -> (usize, Option<usize>) {
        let (_, upper) = self.iter.size_hint();
        (0, upper) // can't know a lower bound, due to the waiting function
    }
}

/// An extension to sized Iterators that specifies a function that returns a Constructor Iterator
pub trait ConstructorExt {

    /// Consumes this Iterator and returns a Constructor Iterator
    fn construct_state<St, B, F>(self, state: St, f: F) -> Constructor<Self, St, B, F>
        where Self: Sized+Iterator, B: Clone, F: Fn(&mut St, &mut Option<B>, Self::Item) -> Option<B>;
}

impl<I: Sized+Iterator>ConstructorExt for I {
    fn construct_state<St, B, F>(self, state: St, f: F) -> Constructor<Self, St, B, F>
        where Self: Sized+Iterator, B: Clone, F: Fn(&mut St, &mut Option<B>, I::Item) -> Option<B>,
    {
        Constructor{iter: self, state: state, f: f, current_elem: None}
    }
}

/// An Iterator that performs all iteration in a seperate therad and caches them
pub struct Cached<A: Send> {
    rx: mpsc::Receiver<A>
}

impl<A: Send> Iterator for Cached<A> {
    type Item = A;

    fn next(&mut self) -> Option<A> { self.rx.recv().ok() }
}

/// A function to create a cached Iterator by passing the old Iterator by closure.
/// If the underlying iterator does not support Send you can construct it in the closure
pub fn cached<A: Send + 'static, I: Sized + Iterator<Item=A>, F: FnOnce() -> I + Send + 'static>(constructor: F) -> (Cached<A>, thread::JoinHandle<()>)
{
    let (tx, rx) = mpsc::channel();
    let handle = thread::spawn(move || {
        for item in constructor() {
            let _ = tx.send(item);
        }
    });
    (Cached { rx: rx }, handle)
}

// ================================
// Test functions
#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn peeking_test() {
        let test = vec!["first", "second", "third"];
        let mut index = 0;
        for (elem, peek) in test.into_iter().peeking() {
            match elem {
                "first" => {
                    assert_eq!(peek, Some("second"));
                    index += 1;
                },
                "second" => {
                    assert_eq!(peek, Some("third"));
                    index += 1;
                },
                "third" => {
                    assert_eq!(peek, None);
                    index += 1;
                },
                _ => assert!(false),
            }
        }
        assert_eq!(index, 3);
    }

    #[test]
    fn filtering_scan_test() {
        let test = vec![1, 3, 1, 3];
        let index = 0;
        let mut sum = 0;
        for elem in test.into_iter().scan_filter(index, |index, x| {
            *index += 1;
            if (*index % 2) == 1 {
                Some(x)
            } else {
                None
            }
        }) {
            sum += elem;
        }
        assert_eq!(sum, 2);
    }

    #[test]
    fn parsing_test() {

        struct ParseState {
            one_halt_test: u32,
            two_counter: u32,
            one_more_test: bool,
        }

        let mut result = vec![];

        let test = vec![1, 2, 2, 3];
        for elem in test.into_iter().parsing(
            ParseState {
                one_halt_test: 3,
                two_counter: 1,
                one_more_test: true,
            },
            |state, elem| {
                match elem {
                    Some(1) => {
                        state.one_halt_test -= 1;
                        if state.one_halt_test == 0 {
                            (ParseResult::Continue, Some(1))
                        } else {
                            (ParseResult::Halt, None)
                        }
                    },
                    Some(2) => {
                        state.two_counter += 1;
                        (ParseResult::Continue, Some(state.two_counter))
                    },
                    Some(3) => {
                        (ParseResult::Continue, Some(4))
                    },
                    Some(_) => { panic!("found a bug in rust") },
                    None => {
                        if state.one_more_test {
                            state.one_more_test = false;
                            (ParseResult::Continue, Some(5))
                        } else {
                            (ParseResult::End, None)
                        }
                    }
                }
            }
        ) {
            result.push(elem);
        }

        assert_eq!(result, vec![1, 2, 3, 4, 5]);
    }

    #[test]
    fn construct_test() {
        use std::cell::Cell;

        let test: Vec<u8> = vec![3, 3, 3, 2, 4, 5, 2];

        let result : Vec<u8> = test.into_iter().construct_state(0, |ref mut _state, ref mut value, i| {
            if value.is_none() {
                return Some(Cell::new(i)); //first value
            }

            let old_val = value.as_ref().unwrap().get();
            value.as_ref().unwrap().set(old_val + i);

            if value.as_ref().unwrap().get() >= 5 {
                Some(Cell::new(0)) //new value
            } else {
                None //continue constucting
            }
        }).map(|x| { x.get() % 5 }).collect();

        assert_eq!(result, vec![1, 0, 4, 2]);
    }
}
<commit_msg>Update extensions.rs<commit_after>//! Extensions to existing types used in the zwreec compiler
//!
//! Currently this contains only extensions to the Iterator trait yielding new Iterator types
//! that wrap certain functionality, that is used to filter/construct/lookahead all objects
//! passed and iterated upon in the compiler, making it possible to have most of the compiler
//! chain to be lazy_evaluated and even multi-threaded.

use std::iter::Peekable;
use std::sync::mpsc;
use std::thread;

/// An iterator that performs a lookahead of 1, utilizing the existing Peakable Iterator
/// Can be stacked to perform an even greater lookahead
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
#[derive(Clone)]
pub struct Peeking<I, A> where
    A: Clone,
    I: Iterator<Item=A>,
{
    iter: Peekable<I>,
}

impl<I, A> Iterator for Peeking<I, A> where
    A: Clone,
    I: Iterator<Item=A>
{
    type Item = (A, Option<A>);

    #[inline]
    fn next(&mut self) -> Option<(A, Option<A>)> {
        match self.iter.next() {
            Some(item) => Some((item,
                match self.iter.peek() {
                    Some(ref item) => Some((*item).clone()),
                    None => None,
                }
            )),
            None => None,
        }
    }

    #[inline]
    fn size_hint(&self) -> (usize, Option<usize>) {
        self.iter.size_hint()
    }
}

/// An extension for sized Iterators that specifies a function that returns a Peeking Iterator
pub trait PeekingExt {

    /// Consumes this Iterator and returns a Peeking Iterator
    fn peeking(self) -> Peeking<Self, Self::Item>
        where Self: Sized+Iterator,
              Self::Item: Clone;
}

impl<A: Clone, I: Sized+Iterator<Item=A>> PeekingExt for I {
    fn peeking(self) -> Peeking<Self, A>
        where Self: Sized+Iterator
    {
         Peeking { iter: self.peekable() }
    }
}

/// An iterator to maintain state while iterating another iterator and allows filtering
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
#[derive(Clone)]
pub struct FilteringScan<I, St, F> {
    iter: I,
    f: F,
    state: St,
}

impl<B, I, St, F> Iterator for FilteringScan<I, St, F> where
    I: Iterator,
    F: FnMut(&mut St, I::Item) -> Option<B>,
{
    type Item = B;

    #[inline]
    fn next(&mut self) -> Option<B> {
        loop {
            match self.iter.next() {
                Some(next) => match (self.f)(&mut self.state, next) {
                    Some(result) => return Some(result),
                    None => continue,
                },
                None => return None,
            }
        }
    }

    #[inline]
    fn size_hint(&self) -> (usize, Option<usize>) {
        let (_, upper) = self.iter.size_hint();
        (0, upper) // can't know a lower bound, due to the scan function
    }
}

/// An extension to sized Iterators that specifies a function that returns a FilteringScan Iterator
pub trait FilteringScanExt {

    /// Consumes this Iterator and returns a FilteringScan Iterator
    fn scan_filter<St, B, F>(self, initial_state: St, f: F) -> FilteringScan<Self, St, F>
        where Self: Sized+Iterator, F: FnMut(&mut St, Self::Item) -> Option<B>;
}

impl<I: Sized+Iterator> FilteringScanExt for I {
    fn scan_filter<St, B, F>(self, initial_state: St, f: F) -> FilteringScan<Self, St, F>
        where Self: Sized+Iterator, F: FnMut(&mut St, I::Item) -> Option<B>,
    {
        FilteringScan{iter: self, f: f, state: initial_state}
    }
}

/// The result of a parsing operation
#[derive(Clone)]
pub enum ParseResult {
    /// Continue with the next underlying Iterator Element (or None, if it is empty)
    Continue,

    /// Do not advance the underlying Iterator, but continue processing
    Halt,

    /// Finish the Iterator (let it return None)
    End,
}

/// An iterator to maintain state while iterating another iterator and allows more complex parsing
// (allowing holding the current iterator value, continue if its goes empty and filter the output)
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
#[derive(Clone)]
pub struct Parser<I, A, St, F> where
    A: Clone,
    I: Iterator<Item=A>,
{
    iter: I,
    f: F,
    state: St,

    iter_state: ParseResult,
    current_elem: Option<A>,
}

impl<B, I, St, F, A> Iterator for Parser<I, A, St, F> where
    A: Clone,
    I: Iterator<Item=A>,
    F: FnMut(&mut St, Option<I::Item>) -> (ParseResult, Option<B>),
{
    type Item = B;

    #[inline]
    fn next(&mut self) -> Option<B> {
        loop {
            match self.iter_state {
                ParseResult::Continue => self.current_elem = self.iter.next(),
                ParseResult::Halt => {},
                ParseResult::End => return None,
            };

            let (new_state, result) = (self.f) (&mut self.state, self.current_elem.clone());

            self.iter_state = new_state;

            match result {
                Some(result) => return Some(result),
                None => continue,
            }
        }
    }

    #[inline]
    fn size_hint(&self) -> (usize, Option<usize>) {
        (0, None) // can't know a lower or upper bound, due to the parse function
    }
}

/// An extension to sized Iterators that specifies a function that returns a Parser Iterator
pub trait ParserExt {

    /// Consumes this Iterator and returns a FilteringScan Iterator
    fn parsing<St, B, F>(self, initial_state: St, f: F) -> Parser<Self, Self::Item, St, F>
        where Self: Sized+Iterator, Self::Item: Clone, F: Fn(&mut St, Option<Self::Item>) -> (ParseResult, Option<B>);
}

impl<A:Clone, I: Sized+Iterator<Item=A>>ParserExt for I {
    fn parsing<St, B, F>(self, initial_state: St, f: F) -> Parser<Self, A, St, F>
        where F: FnMut(&mut St, Option<A>) -> (ParseResult, Option<B>),
    {
        Parser{iter: self, f: f, state: initial_state, iter_state: ParseResult::Continue, current_elem: None}
    }
}

/// An iterator to maintain state while iterating another iterator and allows to hold the currently active
/// object to modify it (/construct it), until the next element is created
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
#[derive(Clone)]
pub struct Constructor<I, St, B, F>
    where
    I: Iterator,
    B: Clone,
    F: FnMut(&mut St, &mut Option<B>, I::Item) -> Option<B> {
        iter: I,
        state: St,
        f: F,
        current_elem: Option<B>,
}

impl<I, St, B, F> Iterator for Constructor<I, St, B, F> where
    I: Iterator,
    B: Clone,
    F: FnMut(&mut St, &mut Option<B>, I::Item) -> Option<B>,
{
    type Item = B;

    #[inline]
    fn next(&mut self) -> Option<B> {
        while let Some(elem) =  self.iter.next() {
            match (self.f)(&mut self.state, &mut self.current_elem, elem) {
                Some(elem) => {
                    let return_val = self.current_elem.clone();
                    self.current_elem = Some(elem);
                    match return_val {
                        Some(value) => return Some(value),
                        None => continue,
                    }
                },
                None => continue,
            }
        }

        let result = self.current_elem.clone();
        self.current_elem = None;
        result
    }

    #[inline]
    fn size_hint(&self) -> (usize, Option<usize>) {
        let (_, upper) = self.iter.size_hint();
        (0, upper) // can't know a lower bound, due to the waiting function
    }
}

/// An extension to sized Iterators that specifies a function that returns a Constructor Iterator
pub trait ConstructorExt {

    /// Consumes this Iterator and returns a Constructor Iterator
    fn construct_state<St, B, F>(self, state: St, f: F) -> Constructor<Self, St, B, F>
        where Self: Sized+Iterator, B: Clone, F: Fn(&mut St, &mut Option<B>, Self::Item) -> Option<B>;
}

impl<I: Sized+Iterator>ConstructorExt for I {
    fn construct_state<St, B, F>(self, state: St, f: F) -> Constructor<Self, St, B, F>
        where Self: Sized+Iterator, B: Clone, F: Fn(&mut St, &mut Option<B>, I::Item) -> Option<B>,
    {
        Constructor{iter: self, state: state, f: f, current_elem: None}
    }
}

/// An Iterator that performs all iteration in a seperate therad and caches them
pub struct Cached<A: Send> {
    rx: mpsc::Receiver<A>
}

impl<A: Send> Iterator for Cached<A> {
    type Item = A;

    fn next(&mut self) -> Option<A> { self.rx.recv().ok() }
}

/// A function to create a cached Iterator by passing the old Iterator by closure.
/// If the underlying iterator does not support Send you can construct it in the closure
pub fn cached<A: Send + 'static, I: Sized + Iterator<Item=A>, F: FnOnce() -> I + Send + 'static>(constructor: F) -> (Cached<A>, thread::JoinHandle<()>)
{
    let (tx, rx) = mpsc::channel();
    let handle = thread::spawn(move || {
        for item in constructor() {
            let _ = tx.send(item);
        }
    });
    (Cached { rx: rx }, handle)
}

// ================================
// Test functions
#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn peeking_test() {
        let test = vec!["first", "second", "third"];
        let mut index = 0;
        for (elem, peek) in test.into_iter().peeking() {
            match elem {
                "first" => {
                    assert_eq!(peek, Some("second"));
                    index += 1;
                },
                "second" => {
                    assert_eq!(peek, Some("third"));
                    index += 1;
                },
                "third" => {
                    assert_eq!(peek, None);
                    index += 1;
                },
                _ => assert!(false),
            }
        }
        assert_eq!(index, 3);
    }

    #[test]
    fn filtering_scan_test() {
        let test = vec![1, 3, 1, 3];
        let index = 0;
        let mut sum = 0;
        for elem in test.into_iter().scan_filter(index, |index, x| {
            *index += 1;
            if (*index % 2) == 1 {
                Some(x)
            } else {
                None
            }
        }) {
            sum += elem;
        }
        assert_eq!(sum, 2);
    }

    #[test]
    fn parsing_test() {

        struct ParseState {
            one_halt_test: u32,
            two_counter: u32,
            one_more_test: bool,
        }

        let mut result = vec![];

        let test = vec![1, 2, 2, 3];
        for elem in test.into_iter().parsing(
            ParseState {
                one_halt_test: 3,
                two_counter: 1,
                one_more_test: true,
            },
            |state, elem| {
                match elem {
                    Some(1) => {
                        state.one_halt_test -= 1;
                        if state.one_halt_test == 0 {
                            (ParseResult::Continue, Some(1))
                        } else {
                            (ParseResult::Halt, None)
                        }
                    },
                    Some(2) => {
                        state.two_counter += 1;
                        (ParseResult::Continue, Some(state.two_counter))
                    },
                    Some(3) => {
                        (ParseResult::Continue, Some(4))
                    },
                    Some(_) => { panic!("found a bug in rust") },
                    None => {
                        if state.one_more_test {
                            state.one_more_test = false;
                            (ParseResult::Continue, Some(5))
                        } else {
                            (ParseResult::End, None)
                        }
                    }
                }
            }
        ) {
            result.push(elem);
        }

        assert_eq!(result, vec![1, 2, 3, 4, 5]);
    }

    #[test]
    fn construct_test() {
        use std::cell::Cell;

        let test: Vec<u8> = vec![3, 3, 3, 2, 4, 5, 2];

        let result : Vec<u8> = test.into_iter().construct_state(0, |ref mut _state, ref mut value, i| {
            if value.is_none() {
                return Some(Cell::new(i)); //first value
            }

            let old_val = value.as_ref().unwrap().get();
            value.as_ref().unwrap().set(old_val + i);

            if value.as_ref().unwrap().get() >= 5 {
                Some(Cell::new(0)) //new value
            } else {
                None //continue constucting
            }
        }).map(|x| { x.get() % 5 }).collect();

        assert_eq!(result, vec![1, 0, 4, 2]);
    }
}
<|endoftext|>


<commit_before>use inflector::Inflector;

use botocore::{Member, Operation, Service, Shape, ShapeType};
use super::{generate_field_name, mutate_type_name};

pub fn generate_struct_attributes(deserialized: bool) -> String {
    let mut derived = vec!["Default"];

    if deserialized {
        derived.push("Debug, Clone")
    }

    format!("#[derive({})]", derived.join(","))
}

pub fn generate_deserializer(name: &str, shape: &Shape, service: &Service) -> String {
    format!("struct {name}Deserializer;
            impl {name}Deserializer {{
                #[allow(unused_variables)]
                fn deserialize<'a, T: Peek + Next>(tag_name: &str, stack: &mut T)
                -> Result<{name}, XmlParseError> {{
                    {deserializer_body}
                }}
            }}",
            name = name,
            deserializer_body = generate_deserializer_body(name, shape, service))
}

pub fn generate_response_parser(service: &Service, operation: &Operation, mutable_result: bool) -> String {
    if operation.output.is_none() {
        return "let result = ();".to_string();
    }

    let shape_name = &operation.output.as_ref().unwrap().shape;
    let result_wrapper = &operation.output.as_ref().unwrap().result_wrapper;
    let output_shape = &service.shapes[shape_name];

    // if the 'payload' field on the output shape is a blob or string, it indicates that
    // the entire payload is set as one of the struct members, and not parsed
    match output_shape.payload {
        None => xml_body_parser(shape_name, result_wrapper, mutable_result),
        Some(ref payload_member) => {
            let payload_shape = &service.shapes[payload_member];
            match payload_shape.shape_type {
                payload_type if payload_type == ShapeType::Blob ||
                                payload_type == ShapeType::String => {
                    payload_body_parser(payload_type, shape_name, payload_member)
                }
                _ => xml_body_parser(shape_name, result_wrapper, mutable_result),
            }
        }
    }
}

fn payload_body_parser(payload_type: ShapeType,
                       output_shape: &str,
                       payload_member: &str)
                       -> String {
    let response_body = match payload_type {
        ShapeType::Blob => "Some(response.body.as_bytes().to_vec())",
        _ => "Some(response.body.to_owned())",
    };

    format!("
        let mut result = {output_shape}::default();
        result.{payload_member} = {response_body};
        ",
            output_shape = output_shape,
            payload_member = payload_member.to_snake_case(),
            response_body = response_body)
}

fn xml_body_parser(output_shape: &str, result_wrapper: &Option<String>, mutable_result: bool) -> String {
    let let_result = if mutable_result {
        "let mut result;"
    } else {
        "let result;"
    };

    let deserialize = match result_wrapper {
        &Some(ref tag_name) => {
            format!("try!(start_element(&actual_tag_name, &mut stack));
                     result = try!({output_shape}Deserializer::deserialize(\"{tag_name}\", &mut stack));
                     skip_tree(&mut stack);
                     try!(end_element(&actual_tag_name, &mut stack));",
                     output_shape = output_shape,
                     tag_name = tag_name)
        },
        &None => {
            format!("result = try!({output_shape}Deserializer::deserialize(&actual_tag_name, &mut stack));",
                     output_shape = output_shape)
        }
    };

    format!("
        {let_result}

        if response.body.is_empty() {{
            result = {output_shape}::default();
        }} else {{
            let reader = EventReader::new_with_config(
                response.body.as_bytes(),
                ParserConfig::new().trim_whitespace(true)
            );
            let mut stack = XmlResponse::new(reader.into_iter().peekable());
            let _start_document = stack.next();
            let actual_tag_name = try!(peek_at_name(&mut stack));
            {deserialize}
        }}",
            let_result = let_result,
            output_shape = output_shape,
            deserialize = deserialize)
}

fn generate_deserializer_body(name: &str, shape: &Shape, service: &Service) -> String {
    match shape.shape_type {
        ShapeType::List => generate_list_deserializer(shape),
        ShapeType::Map => generate_map_deserializer(shape),
        ShapeType::Structure => generate_struct_deserializer(name, service, shape),
        _ => generate_primitive_deserializer(shape),
    }
}

fn generate_list_deserializer(shape: &Shape) -> String {
    // flattened lists are just the list elements repeated without
    // an enclosing <FooList></FooList> tag
    if let Some(true) = shape.flattened {
        return generate_flat_list_deserializer(shape);
    }

    let location_name = shape.member
        .as_ref()
        .and_then(|m| m.location_name.to_owned())
        .unwrap_or_else(|| "member".to_owned());

    format!("
        let mut obj = vec![];
        try!(start_element(tag_name, stack));

        loop {{
            let next_event = match stack.peek() {{
                Some(&Ok(XmlEvent::EndElement {{ .. }})) => DeserializerNext::Close,
                Some(&Ok(XmlEvent::StartElement {{ ref name, .. }})) => DeserializerNext::Element(name.local_name.to_owned()),
                _ => DeserializerNext::Skip,
            }};

            match next_event {{
                DeserializerNext::Element(name) => {{
                    if name == \"{location_name}\" {{
                        obj.push(try!({member_name}Deserializer::deserialize(\"{location_name}\", stack)));
                    }} else {{
                        skip_tree(stack);
                    }}
                }},
                DeserializerNext::Close => {{
                    try!(end_element(tag_name, stack));
                    break;
                }}
                DeserializerNext::Skip => {{ stack.next(); }},
            }}
        }}

        Ok(obj)
        ",
            location_name = location_name,
            member_name = mutate_type_name(&shape.member_type()[..]))
}

fn generate_flat_list_deserializer(shape: &Shape) -> String {
    format!("
        let mut obj = vec![];

        loop {{

            let consume_next_tag = match stack.peek() {{
                Some(&Ok(XmlEvent::StartElement {{ ref name, .. }})) => name.local_name == tag_name,
                _ => false
            }};

            if consume_next_tag {{
                obj.push(try!({member_name}Deserializer::deserialize(tag_name, stack)));
            }} else {{
                break
            }}

        }}

        Ok(obj)
        ",
            member_name = mutate_type_name(shape.member_type()))
}

fn generate_map_deserializer(shape: &Shape) -> String {
    let key = shape.key.as_ref().unwrap();
    let value = shape.value.as_ref().unwrap();

    let entry_location = shape.location_name.as_ref()
                                            .map(String::as_ref)
                                            .unwrap_or_else(|| "entry");

    format!(
        "
        try!(start_element(tag_name, stack));
        let mut obj = ::std::collections::HashMap::new();

        while try!(peek_at_name(stack)) == \"{entry_location}\" {{
            try!(start_element(\"{entry_location}\", stack));
            let key = try!({key_type_name}Deserializer::deserialize(\"{key_tag_name}\", stack));
            let value = try!({value_type_name}Deserializer::deserialize(\"{value_tag_name}\", stack));
            obj.insert(key, value);
            try!(end_element(\"{entry_location}\", stack));
        }}

        try!(end_element(tag_name, stack));
        Ok(obj)
        ",
        key_tag_name = key.tag_name(),
        key_type_name = key.shape,
        value_tag_name = value.tag_name(),
        value_type_name = value.shape,
        entry_location = entry_location
    )
}

fn generate_primitive_deserializer(shape: &Shape) -> String {
    let statement = match shape.shape_type {
        ShapeType::String | ShapeType::Timestamp => "try!(characters(stack))",
        ShapeType::Integer => "i32::from_str(try!(characters(stack)).as_ref()).unwrap()",
        ShapeType::Long => "i64::from_str(try!(characters(stack)).as_ref()).unwrap()",
        ShapeType::Double => "f64::from_str(try!(characters(stack)).as_ref()).unwrap()",
        ShapeType::Float => "f32::from_str(try!(characters(stack)).as_ref()).unwrap()",
        ShapeType::Blob => "try!(characters(stack)).into_bytes()",
        ShapeType::Boolean => "bool::from_str(try!(characters(stack)).as_ref()).unwrap()",
        _ => panic!("Unknown primitive shape type"),
    };

    format!(
        "try!(start_element(tag_name, stack));
        let obj = {statement};
        try!(end_element(tag_name, stack));

        Ok(obj)
        ",
        statement = statement,
    )
}

fn generate_struct_deserializer(name: &str, service: &Service, shape: &Shape) -> String {
    let mut needs_xml_deserializer = false;

    // don't generate an xml deserializer if we don't need to
    for (_, member) in shape.members.as_ref().unwrap().iter() {
        match member.location.as_ref().map(String::as_ref) {
            Some("header") | Some("headers") => {}
            _ => needs_xml_deserializer = true,
        }
    }

    if !needs_xml_deserializer || shape.members.as_ref().unwrap().is_empty() {
        return format!(
            "try!(start_element(tag_name, stack));

            stack.next();

            let obj = {name}::default();

            try!(end_element(tag_name, stack));
            stack.next();

            Ok(obj)
            ",
            name = name,
        );
    }

    format!(
        "try!(start_element(tag_name, stack));

        let mut obj = {name}::default();

        loop {{
            let next_event = match stack.peek() {{
                Some(&Ok(XmlEvent::EndElement {{ ref name, .. }})) => DeserializerNext::Close,
                Some(&Ok(XmlEvent::StartElement {{ ref name, .. }})) => DeserializerNext::Element(name.local_name.to_owned()),
                _ => DeserializerNext::Skip,
            }};

            match next_event {{
                DeserializerNext::Element(name) => {{
                    match &name[..] {{
                        {struct_field_deserializers}
                        _ => skip_tree(stack),
                    }}
                }},
                DeserializerNext::Close => break,
                DeserializerNext::Skip => {{ stack.next(); }},
            }}
        }}

        try!(end_element(tag_name, stack));

        Ok(obj)
        ",
        name = name,
        struct_field_deserializers = generate_struct_field_deserializers(service, shape),
    )
}

fn generate_struct_field_deserializers(service: &Service, shape: &Shape) -> String {
    shape.members
        .as_ref()
        .unwrap()
        .iter()
        .filter_map(|(member_name, member)| {
            // look up member.shape in all_shapes.  use that shape.member.location_name
            let mut location_name = member.location_name.as_ref().unwrap_or(member_name);

            // skip deprecated and non-XML fields
            if member.deprecated() ||
               member.location == Some("header".to_owned()) ||
               member.location == Some("headers".to_owned()) {
                return None;
            }

            let member_shape = &service.shapes[&member.shape];

            // flattened lists have no surrounding tag, so match on the list member's tag
            if member_shape.shape_type == ShapeType::List && member_shape.flattened == Some(true) {
                let list_member = member_shape.member.as_ref().expect("list member undefined");
                if let Some(ref list_member_location) = list_member.location_name {
                    location_name = list_member_location;
                }
            }

            let parse_expression = generate_struct_field_parse_expression(shape,
                                                                          member_name,
                                                                          member,
                                                                          location_name);
            Some(format!(
            "\"{location_name}\" => {{
                obj.{field_name} = {parse_expression};
            }}",
            field_name = generate_field_name(member_name),
            parse_expression = parse_expression,
            location_name = location_name,
        ))

        })
        .collect::<Vec<String>>()
        .join("\n")
}

fn generate_struct_field_parse_expression(shape: &Shape,
                                          member_name: &str,
                                          member: &Member,
                                          location_name: &String)
                                          -> String {
    let expression = format!(
        "try!({name}Deserializer::deserialize(\"{location_name}\", stack))",
        name = member.shape,
        location_name = location_name,
    );

    if shape.required(member_name) {
        expression
    } else {
        format!("Some({})", expression)
    }
}
<commit_msg>handle flattened maps properly.  all integration tests passing again<commit_after>use inflector::Inflector;

use botocore::{Member, Operation, Service, Shape, ShapeType};
use super::{generate_field_name, mutate_type_name};

pub fn generate_struct_attributes(deserialized: bool) -> String {
    let mut derived = vec!["Default"];

    if deserialized {
        derived.push("Debug, Clone")
    }

    format!("#[derive({})]", derived.join(","))
}

pub fn generate_deserializer(name: &str, shape: &Shape, service: &Service) -> String {
    format!("struct {name}Deserializer;
            impl {name}Deserializer {{
                #[allow(unused_variables)]
                fn deserialize<'a, T: Peek + Next>(tag_name: &str, stack: &mut T)
                -> Result<{name}, XmlParseError> {{
                    {deserializer_body}
                }}
            }}",
            name = name,
            deserializer_body = generate_deserializer_body(name, shape, service))
}

pub fn generate_response_parser(service: &Service, operation: &Operation, mutable_result: bool) -> String {
    if operation.output.is_none() {
        return "let result = ();".to_string();
    }

    let shape_name = &operation.output.as_ref().unwrap().shape;
    let result_wrapper = &operation.output.as_ref().unwrap().result_wrapper;
    let output_shape = &service.shapes[shape_name];

    // if the 'payload' field on the output shape is a blob or string, it indicates that
    // the entire payload is set as one of the struct members, and not parsed
    match output_shape.payload {
        None => xml_body_parser(shape_name, result_wrapper, mutable_result),
        Some(ref payload_member) => {
            let payload_shape = &service.shapes[payload_member];
            match payload_shape.shape_type {
                payload_type if payload_type == ShapeType::Blob ||
                                payload_type == ShapeType::String => {
                    payload_body_parser(payload_type, shape_name, payload_member)
                }
                _ => xml_body_parser(shape_name, result_wrapper, mutable_result),
            }
        }
    }
}

fn payload_body_parser(payload_type: ShapeType,
                       output_shape: &str,
                       payload_member: &str)
                       -> String {
    let response_body = match payload_type {
        ShapeType::Blob => "Some(response.body.as_bytes().to_vec())",
        _ => "Some(response.body.to_owned())",
    };

    format!("
        let mut result = {output_shape}::default();
        result.{payload_member} = {response_body};
        ",
            output_shape = output_shape,
            payload_member = payload_member.to_snake_case(),
            response_body = response_body)
}

fn xml_body_parser(output_shape: &str, result_wrapper: &Option<String>, mutable_result: bool) -> String {
    let let_result = if mutable_result {
        "let mut result;"
    } else {
        "let result;"
    };

    let deserialize = match result_wrapper {
        &Some(ref tag_name) => {
            format!("try!(start_element(&actual_tag_name, &mut stack));
                     result = try!({output_shape}Deserializer::deserialize(\"{tag_name}\", &mut stack));
                     skip_tree(&mut stack);
                     try!(end_element(&actual_tag_name, &mut stack));",
                     output_shape = output_shape,
                     tag_name = tag_name)
        },
        &None => {
            format!("result = try!({output_shape}Deserializer::deserialize(&actual_tag_name, &mut stack));",
                     output_shape = output_shape)
        }
    };

    format!("
        {let_result}

        if response.body.is_empty() {{
            result = {output_shape}::default();
        }} else {{
            let reader = EventReader::new_with_config(
                response.body.as_bytes(),
                ParserConfig::new().trim_whitespace(true)
            );
            let mut stack = XmlResponse::new(reader.into_iter().peekable());
            let _start_document = stack.next();
            let actual_tag_name = try!(peek_at_name(&mut stack));
            {deserialize}
        }}",
            let_result = let_result,
            output_shape = output_shape,
            deserialize = deserialize)
}

fn generate_deserializer_body(name: &str, shape: &Shape, service: &Service) -> String {
    match shape.shape_type {
        ShapeType::List => generate_list_deserializer(shape),
        ShapeType::Map => generate_map_deserializer(shape),
        ShapeType::Structure => generate_struct_deserializer(name, service, shape),
        _ => generate_primitive_deserializer(shape),
    }
}

fn generate_list_deserializer(shape: &Shape) -> String {
    // flattened lists are just the list elements repeated without
    // an enclosing <FooList></FooList> tag
    if let Some(true) = shape.flattened {
        return generate_flat_list_deserializer(shape);
    }

    let location_name = shape.member
        .as_ref()
        .and_then(|m| m.location_name.to_owned())
        .unwrap_or_else(|| "member".to_owned());

    format!("
        let mut obj = vec![];
        try!(start_element(tag_name, stack));

        loop {{
            let next_event = match stack.peek() {{
                Some(&Ok(XmlEvent::EndElement {{ .. }})) => DeserializerNext::Close,
                Some(&Ok(XmlEvent::StartElement {{ ref name, .. }})) => DeserializerNext::Element(name.local_name.to_owned()),
                _ => DeserializerNext::Skip,
            }};

            match next_event {{
                DeserializerNext::Element(name) => {{
                    if name == \"{location_name}\" {{
                        obj.push(try!({member_name}Deserializer::deserialize(\"{location_name}\", stack)));
                    }} else {{
                        skip_tree(stack);
                    }}
                }},
                DeserializerNext::Close => {{
                    try!(end_element(tag_name, stack));
                    break;
                }}
                DeserializerNext::Skip => {{ stack.next(); }},
            }}
        }}

        Ok(obj)
        ",
            location_name = location_name,
            member_name = mutate_type_name(&shape.member_type()[..]))
}

fn generate_flat_list_deserializer(shape: &Shape) -> String {
    format!("
        let mut obj = vec![];

        loop {{

            let consume_next_tag = match stack.peek() {{
                Some(&Ok(XmlEvent::StartElement {{ ref name, .. }})) => name.local_name == tag_name,
                _ => false
            }};

            if consume_next_tag {{
                obj.push(try!({member_name}Deserializer::deserialize(tag_name, stack)));
            }} else {{
                break
            }}

        }}

        Ok(obj)
        ",
            member_name = mutate_type_name(shape.member_type()))
}

fn generate_map_deserializer(shape: &Shape) -> String {
    let key = shape.key.as_ref().unwrap();
    let value = shape.value.as_ref().unwrap();

    let entry_location = shape.location_name.as_ref()
                                            .map(String::as_ref)
                                            .unwrap_or_else(|| "entry");

    // the core of the map parser is the same whether or not it's flattened
    let entries_parser = format!(
        "
        let mut obj = ::std::collections::HashMap::new();

        while try!(peek_at_name(stack)) == \"{entry_location}\" {{
            try!(start_element(\"{entry_location}\", stack));
            let key = try!({key_type_name}Deserializer::deserialize(\"{key_tag_name}\", stack));
            let value = try!({value_type_name}Deserializer::deserialize(\"{value_tag_name}\", stack));
            obj.insert(key, value);
            try!(end_element(\"{entry_location}\", stack));
        }}
        ",
        key_tag_name = key.tag_name(),
        key_type_name = key.shape,
        value_tag_name = value.tag_name(),
        value_type_name = value.shape,
        entry_location = entry_location
    );

    // if the map is flattened, just return the entries parser
    // otherwise parse a start and end tag around the whole map
    match shape.flattened {
        Some(true) => format!("{entries_parser}
                               Ok(obj)",
                              entries_parser = entries_parser),
        _ => format!("try!(start_element(tag_name, stack));
                    {entries_parser}
                    try!(end_element(tag_name, stack));
                    Ok(obj)
                    ",
                    entries_parser = entries_parser)
    }
}

fn generate_primitive_deserializer(shape: &Shape) -> String {
    let statement = match shape.shape_type {
        ShapeType::String | ShapeType::Timestamp => "try!(characters(stack))",
        ShapeType::Integer => "i32::from_str(try!(characters(stack)).as_ref()).unwrap()",
        ShapeType::Long => "i64::from_str(try!(characters(stack)).as_ref()).unwrap()",
        ShapeType::Double => "f64::from_str(try!(characters(stack)).as_ref()).unwrap()",
        ShapeType::Float => "f32::from_str(try!(characters(stack)).as_ref()).unwrap()",
        ShapeType::Blob => "try!(characters(stack)).into_bytes()",
        ShapeType::Boolean => "bool::from_str(try!(characters(stack)).as_ref()).unwrap()",
        _ => panic!("Unknown primitive shape type"),
    };

    format!(
        "try!(start_element(tag_name, stack));
        let obj = {statement};
        try!(end_element(tag_name, stack));

        Ok(obj)
        ",
        statement = statement,
    )
}

fn generate_struct_deserializer(name: &str, service: &Service, shape: &Shape) -> String {
    let mut needs_xml_deserializer = false;

    // don't generate an xml deserializer if we don't need to
    for (_, member) in shape.members.as_ref().unwrap().iter() {
        match member.location.as_ref().map(String::as_ref) {
            Some("header") | Some("headers") => {}
            _ => needs_xml_deserializer = true,
        }
    }

    if !needs_xml_deserializer || shape.members.as_ref().unwrap().is_empty() {
        return format!(
            "try!(start_element(tag_name, stack));

            stack.next();

            let obj = {name}::default();

            try!(end_element(tag_name, stack));
            stack.next();

            Ok(obj)
            ",
            name = name,
        );
    }

    format!(
        "try!(start_element(tag_name, stack));

        let mut obj = {name}::default();

        loop {{
            let next_event = match stack.peek() {{
                Some(&Ok(XmlEvent::EndElement {{ ref name, .. }})) => DeserializerNext::Close,
                Some(&Ok(XmlEvent::StartElement {{ ref name, .. }})) => DeserializerNext::Element(name.local_name.to_owned()),
                _ => DeserializerNext::Skip,
            }};

            match next_event {{
                DeserializerNext::Element(name) => {{
                    match &name[..] {{
                        {struct_field_deserializers}
                        _ => skip_tree(stack),
                    }}
                }},
                DeserializerNext::Close => break,
                DeserializerNext::Skip => {{ stack.next(); }},
            }}
        }}

        try!(end_element(tag_name, stack));

        Ok(obj)
        ",
        name = name,
        struct_field_deserializers = generate_struct_field_deserializers(service, shape),
    )
}

fn generate_struct_field_deserializers(service: &Service, shape: &Shape) -> String {
    shape.members
        .as_ref()
        .unwrap()
        .iter()
        .filter_map(|(member_name, member)| {
            // look up member.shape in all_shapes.  use that shape.member.location_name
            let mut location_name = member.location_name.as_ref().unwrap_or(member_name);

            // skip deprecated and non-XML fields
            if member.deprecated() ||
               member.location == Some("header".to_owned()) ||
               member.location == Some("headers".to_owned()) {
                return None;
            }

            let member_shape = &service.shapes[&member.shape];

            // flattened lists have no surrounding tag, so match on the list member's tag
            if member_shape.shape_type == ShapeType::List && member_shape.flattened == Some(true) {
                let list_member = member_shape.member.as_ref().expect("list member undefined");
                if let Some(ref list_member_location) = list_member.location_name {
                    location_name = list_member_location;
                }
            }

            let parse_expression = generate_struct_field_parse_expression(shape,
                                                                          member_name,
                                                                          member,
                                                                          location_name);
            Some(format!(
            "\"{location_name}\" => {{
                obj.{field_name} = {parse_expression};
            }}",
            field_name = generate_field_name(member_name),
            parse_expression = parse_expression,
            location_name = location_name,
        ))

        })
        .collect::<Vec<String>>()
        .join("\n")
}

fn generate_struct_field_parse_expression(shape: &Shape,
                                          member_name: &str,
                                          member: &Member,
                                          location_name: &String)
                                          -> String {
    let expression = format!(
        "try!({name}Deserializer::deserialize(\"{location_name}\", stack))",
        name = member.shape,
        location_name = location_name,
    );

    if shape.required(member_name) {
        expression
    } else {
        format!("Some({})", expression)
    }
}
<|endoftext|>


<commit_before>// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use rustc::mir::repr::*;
use rustc::middle::ty;
use std::io::{self, Write};
use syntax::ast::NodeId;

const INDENT: &'static str = "    ";

/// Write out a human-readable textual representation for the given MIR.
pub fn write_mir_pretty<'a, 't, W, I>(tcx: &ty::TyCtxt<'t>, iter: I, w: &mut W) -> io::Result<()>
where W: Write, I: Iterator<Item=(&'a NodeId, &'a Mir<'a>)> {
    for (&nodeid, mir) in iter {
        write_mir_intro(tcx, nodeid, mir, w)?;
        // Nodes
        for block in mir.all_basic_blocks() {
            write_basic_block(block, mir, w)?;
        }
        writeln!(w, "}}")?
    }
    Ok(())
}

/// Write out a human-readable textual representation for the given basic block.
fn write_basic_block<W: Write>(block: BasicBlock, mir: &Mir, w: &mut W) -> io::Result<()> {
    let data = mir.basic_block_data(block);

    // Basic block label at the top.
    writeln!(w, "\n{}{:?}: {{", INDENT, block)?;

    // List of statements in the middle.
    for statement in &data.statements {
        writeln!(w, "{0}{0}{1:?};", INDENT, statement)?;
    }

    // Terminator at the bottom.
    writeln!(w, "{0}{0}{1:?};", INDENT, data.terminator())?;

    writeln!(w, "{}}}", INDENT)
}

/// Write out a human-readable textual representation of the MIR's `fn` type and the types of its
/// local variables (both user-defined bindings and compiler temporaries).
fn write_mir_intro<W: Write>(tcx: &ty::TyCtxt, nid: NodeId, mir: &Mir, w: &mut W)
-> io::Result<()> {

    write!(w, "fn {}(", tcx.map.path_to_string(nid))?;

    // fn argument types.
    for (i, arg) in mir.arg_decls.iter().enumerate() {
        if i > 0 {
            write!(w, ", ")?;
        }
        write!(w, "{:?}: {}", Lvalue::Arg(i as u32), arg.ty)?;
    }

    write!(w, ") -> ")?;

    // fn return type.
    match mir.return_ty {
        ty::FnOutput::FnConverging(ty) => write!(w, "{}", ty)?,
        ty::FnOutput::FnDiverging => write!(w, "!")?,
    }

    writeln!(w, " {{")?;

    // User variable types (including the user's name in a comment).
    for (i, var) in mir.var_decls.iter().enumerate() {
        write!(w, "{}let ", INDENT)?;
        if var.mutability == Mutability::Mut {
            write!(w, "mut ")?;
        }
        writeln!(w, "{:?}: {}; // {}", Lvalue::Var(i as u32), var.ty, var.name)?;
    }

    // Compiler-introduced temporary types.
    for (i, temp) in mir.temp_decls.iter().enumerate() {
        writeln!(w, "{}let mut {:?}: {};", INDENT, Lvalue::Temp(i as u32), temp.ty)?;
    }

    Ok(())
}
<commit_msg>reformat mir text pretty printer<commit_after>// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use rustc::mir::repr::*;
use rustc::middle::ty;
use std::io::{self, Write};
use syntax::ast::NodeId;

const INDENT: &'static str = "    ";

/// Write out a human-readable textual representation for the given MIR.
pub fn write_mir_pretty<'a, 'tcx, I>(tcx: &ty::TyCtxt<'tcx>,
                                     iter: I,
                                     w: &mut Write)
                                     -> io::Result<()>
    where I: Iterator<Item=(&'a NodeId, &'a Mir<'tcx>)>, 'tcx: 'a
{
    for (&node_id, mir) in iter {
        write_mir_fn(tcx, node_id, mir, w)?;
    }
    Ok(())
}

pub fn write_mir_fn<'tcx>(tcx: &ty::TyCtxt<'tcx>,
                          node_id: NodeId,
                          mir: &Mir<'tcx>,
                          w: &mut Write)
                          -> io::Result<()> {
    write_mir_intro(tcx, node_id, mir, w)?;
    for block in mir.all_basic_blocks() {
        write_basic_block(block, mir, w)?;
    }
    writeln!(w, "}}")?;
    Ok(())
}

/// Write out a human-readable textual representation for the given basic block.
fn write_basic_block(block: BasicBlock, mir: &Mir, w: &mut Write) -> io::Result<()> {
    let data = mir.basic_block_data(block);

    // Basic block label at the top.
    writeln!(w, "\n{}{:?}: {{", INDENT, block)?;

    // List of statements in the middle.
    for statement in &data.statements {
        writeln!(w, "{0}{0}{1:?};", INDENT, statement)?;
    }

    // Terminator at the bottom.
    writeln!(w, "{0}{0}{1:?};", INDENT, data.terminator())?;

    writeln!(w, "{}}}", INDENT)
}

/// Write out a human-readable textual representation of the MIR's `fn` type and the types of its
/// local variables (both user-defined bindings and compiler temporaries).
fn write_mir_intro(tcx: &ty::TyCtxt, nid: NodeId, mir: &Mir, w: &mut Write)
                   -> io::Result<()> {
    write!(w, "fn {}(", tcx.map.path_to_string(nid))?;

    // fn argument types.
    for (i, arg) in mir.arg_decls.iter().enumerate() {
        if i > 0 {
            write!(w, ", ")?;
        }
        write!(w, "{:?}: {}", Lvalue::Arg(i as u32), arg.ty)?;
    }

    write!(w, ") -> ")?;

    // fn return type.
    match mir.return_ty {
        ty::FnOutput::FnConverging(ty) => write!(w, "{}", ty)?,
        ty::FnOutput::FnDiverging => write!(w, "!")?,
    }

    writeln!(w, " {{")?;

    // User variable types (including the user's name in a comment).
    for (i, var) in mir.var_decls.iter().enumerate() {
        write!(w, "{}let ", INDENT)?;
        if var.mutability == Mutability::Mut {
            write!(w, "mut ")?;
        }
        writeln!(w, "{:?}: {}; // {}", Lvalue::Var(i as u32), var.ty, var.name)?;
    }

    // Compiler-introduced temporary types.
    for (i, temp) in mir.temp_decls.iter().enumerate() {
        writeln!(w, "{}let mut {:?}: {};", INDENT, Lvalue::Temp(i as u32), temp.ty)?;
    }

    Ok(())
}
<|endoftext|>


<commit_before>// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use std::default::Default;
use std::fs::File;
use std::io::prelude::*;
use std::io;
use std::path::{PathBuf, Path};

use getopts;
use testing;
use rustc::session::search_paths::SearchPaths;
use rustc::session::config::Externs;
use syntax::codemap::DUMMY_SP;

use externalfiles::{ExternalHtml, LoadStringError, load_string};

use html::render::reset_ids;
use html::escape::Escape;
use html::markdown;
use html::markdown::{Markdown, MarkdownWithToc, find_testable_code, old_find_testable_code};
use html::markdown::RenderType;
use test::{TestOptions, Collector};

/// Separate any lines at the start of the file that begin with `# ` or `%`.
fn extract_leading_metadata<'a>(s: &'a str) -> (Vec<&'a str>, &'a str) {
    let mut metadata = Vec::new();
    let mut count = 0;

    for line in s.lines() {
        if line.starts_with("# ") || line.starts_with("%") {
            // trim the whitespace after the symbol
            metadata.push(line[1..].trim_left());
            count += line.len() + 1;
        } else {
            return (metadata, &s[count..]);
        }
    }

    // if we're here, then all lines were metadata `# ` or `%` lines.
    (metadata, "")
}

/// Render `input` (e.g. "foo.md") into an HTML file in `output`
/// (e.g. output = "bar" => "bar/foo.html").
pub fn render(input: &str, mut output: PathBuf, matches: &getopts::Matches,
              external_html: &ExternalHtml, include_toc: bool,
              render_type: RenderType) -> isize {
    let input_p = Path::new(input);
    output.push(input_p.file_stem().unwrap());
    output.set_extension("html");

    let mut css = String::new();
    for name in &matches.opt_strs("markdown-css") {
        let s = format!("<link rel=\"stylesheet\" type=\"text/css\" href=\"{}\">\n", name);
        css.push_str(&s)
    }

    let input_str = match load_string(input) {
        Ok(s) => s,
        Err(LoadStringError::ReadFail) => return 1,
        Err(LoadStringError::BadUtf8) => return 2,
    };
    if let Some(playground) = matches.opt_str("markdown-playground-url").or(
                              matches.opt_str("playground-url")) {
        markdown::PLAYGROUND.with(|s| { *s.borrow_mut() = Some((None, playground)); });
    }

    let mut out = match File::create(&output) {
        Err(e) => {
            let _ = writeln!(&mut io::stderr(),
                             "rustdoc: {}: {}",
                             output.display(), e);
            return 4;
        }
        Ok(f) => f
    };

    let (metadata, text) = extract_leading_metadata(&input_str);
    if metadata.is_empty() {
        let _ = writeln!(
            &mut io::stderr(),
            "rustdoc: invalid markdown file: no initial lines starting with `# ` or `%`"
        );
        return 5;
    }
    let title = metadata[0];

    reset_ids(false);

    let rendered = if include_toc {
        format!("{}", MarkdownWithToc(text, render_type))
    } else {
        format!("{}", Markdown(text, render_type))
    };

    let err = write!(
        &mut out,
        r#"<!DOCTYPE html>

    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta name="generator" content="rustdoc">
    <title>{title}</title>

    {css}
    {in_header}

    {before_content}

{title}

    {text}
    {after_content}

"#,
        title = Escape(title),
        css = css,
        in_header = external_html.in_header,
        before_content = external_html.before_content,
        text = rendered,
        after_content = external_html.after_content,
        );

    match err {
        Err(e) => {
            let _ = writeln!(&mut io::stderr(),
                             "rustdoc: cannot write to `{}`: {}",
                             output.display(), e);
            6
        }
        Ok(_) => 0
    }
}

/// Run any tests/code examples in the markdown file `input`.
pub fn test(input: &str, cfgs: Vec<String>, libs: SearchPaths, externs: Externs,
            mut test_args: Vec<String>, maybe_sysroot: Option<PathBuf>,
            render_type: RenderType, display_warnings: bool) -> isize {
    let input_str = match load_string(input) {
        Ok(s) => s,
        Err(LoadStringError::ReadFail) => return 1,
        Err(LoadStringError::BadUtf8) => return 2,
    };

    let mut opts = TestOptions::default();
    opts.no_crate_inject = true;
    let mut collector = Collector::new(input.to_string(), cfgs, libs, externs,
                                       true, opts, maybe_sysroot, None,
                                       Some(input.to_owned()),
                                       render_type);
    old_find_testable_code(&input_str, &mut collector, DUMMY_SP);
    find_testable_code(&input_str, &mut collector, DUMMY_SP);
    test_args.insert(0, "rustdoctest".to_string());
    testing::test_main(&test_args, collector.tests,
                       testing::Options::new().display_output(display_warnings));
    0
}
<commit_msg>Auto merge of #43068 - ollie27:rustdoc_markdown_tests, r=GuillaumeGomez<commit_after>// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use std::default::Default;
use std::fs::File;
use std::io::prelude::*;
use std::io;
use std::path::{PathBuf, Path};

use getopts;
use testing;
use rustc::session::search_paths::SearchPaths;
use rustc::session::config::Externs;
use syntax::codemap::DUMMY_SP;

use externalfiles::{ExternalHtml, LoadStringError, load_string};

use html::render::reset_ids;
use html::escape::Escape;
use html::markdown;
use html::markdown::{Markdown, MarkdownWithToc, find_testable_code, old_find_testable_code};
use html::markdown::RenderType;
use test::{TestOptions, Collector};

/// Separate any lines at the start of the file that begin with `# ` or `%`.
fn extract_leading_metadata<'a>(s: &'a str) -> (Vec<&'a str>, &'a str) {
    let mut metadata = Vec::new();
    let mut count = 0;

    for line in s.lines() {
        if line.starts_with("# ") || line.starts_with("%") {
            // trim the whitespace after the symbol
            metadata.push(line[1..].trim_left());
            count += line.len() + 1;
        } else {
            return (metadata, &s[count..]);
        }
    }

    // if we're here, then all lines were metadata `# ` or `%` lines.
    (metadata, "")
}

/// Render `input` (e.g. "foo.md") into an HTML file in `output`
/// (e.g. output = "bar" => "bar/foo.html").
pub fn render(input: &str, mut output: PathBuf, matches: &getopts::Matches,
              external_html: &ExternalHtml, include_toc: bool,
              render_type: RenderType) -> isize {
    let input_p = Path::new(input);
    output.push(input_p.file_stem().unwrap());
    output.set_extension("html");

    let mut css = String::new();
    for name in &matches.opt_strs("markdown-css") {
        let s = format!("<link rel=\"stylesheet\" type=\"text/css\" href=\"{}\">\n", name);
        css.push_str(&s)
    }

    let input_str = match load_string(input) {
        Ok(s) => s,
        Err(LoadStringError::ReadFail) => return 1,
        Err(LoadStringError::BadUtf8) => return 2,
    };
    if let Some(playground) = matches.opt_str("markdown-playground-url").or(
                              matches.opt_str("playground-url")) {
        markdown::PLAYGROUND.with(|s| { *s.borrow_mut() = Some((None, playground)); });
    }

    let mut out = match File::create(&output) {
        Err(e) => {
            let _ = writeln!(&mut io::stderr(),
                             "rustdoc: {}: {}",
                             output.display(), e);
            return 4;
        }
        Ok(f) => f
    };

    let (metadata, text) = extract_leading_metadata(&input_str);
    if metadata.is_empty() {
        let _ = writeln!(
            &mut io::stderr(),
            "rustdoc: invalid markdown file: no initial lines starting with `# ` or `%`"
        );
        return 5;
    }
    let title = metadata[0];

    reset_ids(false);

    let rendered = if include_toc {
        format!("{}", MarkdownWithToc(text, render_type))
    } else {
        format!("{}", Markdown(text, render_type))
    };

    let err = write!(
        &mut out,
        r#"<!DOCTYPE html>

    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta name="generator" content="rustdoc">
    <title>{title}</title>

    {css}
    {in_header}

    {before_content}

{title}

    {text}
    {after_content}

"#,
        title = Escape(title),
        css = css,
        in_header = external_html.in_header,
        before_content = external_html.before_content,
        text = rendered,
        after_content = external_html.after_content,
        );

    match err {
        Err(e) => {
            let _ = writeln!(&mut io::stderr(),
                             "rustdoc: cannot write to `{}`: {}",
                             output.display(), e);
            6
        }
        Ok(_) => 0
    }
}

/// Run any tests/code examples in the markdown file `input`.
pub fn test(input: &str, cfgs: Vec<String>, libs: SearchPaths, externs: Externs,
            mut test_args: Vec<String>, maybe_sysroot: Option<PathBuf>,
            render_type: RenderType, display_warnings: bool) -> isize {
    let input_str = match load_string(input) {
        Ok(s) => s,
        Err(LoadStringError::ReadFail) => return 1,
        Err(LoadStringError::BadUtf8) => return 2,
    };

    let mut opts = TestOptions::default();
    opts.no_crate_inject = true;
    let mut collector = Collector::new(input.to_string(), cfgs, libs, externs,
                                       true, opts, maybe_sysroot, None,
                                       Some(input.to_owned()),
                                       render_type);
    if render_type == RenderType::Pulldown {
        old_find_testable_code(&input_str, &mut collector, DUMMY_SP);
        find_testable_code(&input_str, &mut collector, DUMMY_SP);
    } else {
        old_find_testable_code(&input_str, &mut collector, DUMMY_SP);
    }
    test_args.insert(0, "rustdoctest".to_string());
    testing::test_main(&test_args, collector.tests,
                       testing::Options::new().display_output(display_warnings));
    0
}
<|endoftext|>