<commit_before>use futures::channel::oneshot;
use futures::future::{self, Future, FutureExt, TryFutureExt};
use futures::task::{Context, Poll};
use futures_test::future::FutureTestExt;
use pin_utils::unsafe_pinned;
use std::pin::Pin;
use std::sync::mpsc;

#[test]
fn map_ok() {
    // The closure given to `map_ok` should have been dropped by the time `map`
    // runs.
    let (tx1, rx1) = mpsc::channel::<()>();
    let (tx2, rx2) = mpsc::channel::<()>();

    future::ready::<Result<i32, i32>>(Err(1))
        .map_ok(move |_| { let _tx1 = tx1; panic!("should not run"); })
        .map(move |_| {
            assert!(rx1.recv().is_err());
            tx2.send(()).unwrap()
        })
        .run_in_background();

    rx2.recv().unwrap();
}

#[test]
fn map_err() {
    // The closure given to `map_err` should have been dropped by the time `map`
    // runs.
    let (tx1, rx1) = mpsc::channel::<()>();
    let (tx2, rx2) = mpsc::channel::<()>();

    future::ready::<Result<i32, i32>>(Ok(1))
        .map_err(move |_| { let _tx1 = tx1; panic!("should not run"); })
        .map(move |_| {
            assert!(rx1.recv().is_err());
            tx2.send(()).unwrap()
        })
        .run_in_background();

    rx2.recv().unwrap();
}

struct FutureData<F, T> {
    _data: T,
    future: F,
}

impl<F, T> FutureData<F, T> {
    unsafe_pinned!(future: F);
}

impl<F: Future, T: Send + 'static> Future for FutureData<F, T> {
    type Output = F::Output;

    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<F::Output> {
        self.future().poll(cx)
    }
}

#[test]
fn then_drops_eagerly() {
    let (tx0, rx0) = oneshot::channel::<()>();
    let (tx1, rx1) = mpsc::channel::<()>();
    let (tx2, rx2) = mpsc::channel::<()>();

    FutureData { _data: tx1, future: rx0.unwrap_or_else(|_| { panic!() }) }
        .then(move |_| {
            assert!(rx1.recv().is_err()); // tx1 should have been dropped
            tx2.send(()).unwrap();
            future::ready(())
        })
        .run_in_background();

    assert_eq!(Err(mpsc::TryRecvError::Empty), rx2.try_recv());
    tx0.send(()).unwrap();
    rx2.recv().unwrap();
}

#[test]
fn and_then_drops_eagerly() {
    let (tx0, rx0) = oneshot::channel::<Result<(), ()>>();
    let (tx1, rx1) = mpsc::channel::<()>();
    let (tx2, rx2) = mpsc::channel::<()>();

    FutureData { _data: tx1, future: rx0.unwrap_or_else(|_| { panic!() }) }
        .and_then(move |_| {
            assert!(rx1.recv().is_err()); // tx1 should have been dropped
            tx2.send(()).unwrap();
            future::ready(Ok(()))
        })
        .run_in_background();

    assert_eq!(Err(mpsc::TryRecvError::Empty), rx2.try_recv());
    tx0.send(Ok(())).unwrap();
    rx2.recv().unwrap();
}

#[test]
fn or_else_drops_eagerly() {
    let (tx0, rx0) = oneshot::channel::<Result<(), ()>>();
    let (tx1, rx1) = mpsc::channel::<()>();
    let (tx2, rx2) = mpsc::channel::<()>();

    FutureData { _data: tx1, future: rx0.unwrap_or_else(|_| { panic!() }) }
        .or_else(move |_| {
            assert!(rx1.recv().is_err()); // tx1 should have been dropped
            tx2.send(()).unwrap();
            future::ready::<Result<(), ()>>(Ok(()))
        })
        .run_in_background();

    assert_eq!(Err(mpsc::TryRecvError::Empty), rx2.try_recv());
    tx0.send(Err(())).unwrap();
    rx2.recv().unwrap();
}
<commit_msg>futures: tests/eager_drop.rs: Fix compiling w/o "alloc"<commit_after>#[test]
fn map_ok() {
    use futures::future::{self, FutureExt, TryFutureExt};
    use futures_test::future::FutureTestExt;
    use std::sync::mpsc;

    // The closure given to `map_ok` should have been dropped by the time `map`
    // runs.
    let (tx1, rx1) = mpsc::channel::<()>();
    let (tx2, rx2) = mpsc::channel::<()>();

    future::ready::<Result<i32, i32>>(Err(1))
        .map_ok(move |_| { let _tx1 = tx1; panic!("should not run"); })
        .map(move |_| {
            assert!(rx1.recv().is_err());
            tx2.send(()).unwrap()
        })
        .run_in_background();

    rx2.recv().unwrap();
}

#[test]
fn map_err() {
    use futures::future::{self, FutureExt, TryFutureExt};
    use futures_test::future::FutureTestExt;
    use std::sync::mpsc;

    // The closure given to `map_err` should have been dropped by the time `map`
    // runs.
    let (tx1, rx1) = mpsc::channel::<()>();
    let (tx2, rx2) = mpsc::channel::<()>();

    future::ready::<Result<i32, i32>>(Ok(1))
        .map_err(move |_| { let _tx1 = tx1; panic!("should not run"); })
        .map(move |_| {
            assert!(rx1.recv().is_err());
            tx2.send(()).unwrap()
        })
        .run_in_background();

    rx2.recv().unwrap();
}

mod channelled {
    use pin_utils::unsafe_pinned;
    use futures::future::Future;
    use std::pin::Pin;
    use futures::task::{Context,Poll};

    struct FutureData<F, T> {
        _data: T,
        future: F,
    }

    impl<F, T> FutureData<F, T> {
        unsafe_pinned!(future: F);
    }

    impl<F: Future, T: Send + 'static> Future for FutureData<F, T> {
        type Output = F::Output;

        fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<F::Output> {
            self.future().poll(cx)
        }
    }

    #[cfg(feature = "alloc")]
    #[test]
    fn then_drops_eagerly() {
        use futures::channel::oneshot;
        use futures::future::{self, FutureExt, TryFutureExt};
        use futures_test::future::FutureTestExt;
        use std::sync::mpsc;

        let (tx0, rx0) = oneshot::channel::<()>();
        let (tx1, rx1) = mpsc::channel::<()>();
        let (tx2, rx2) = mpsc::channel::<()>();

        FutureData { _data: tx1, future: rx0.unwrap_or_else(|_| { panic!() }) }
            .then(move |_| {
                assert!(rx1.recv().is_err()); // tx1 should have been dropped
                tx2.send(()).unwrap();
                future::ready(())
            })
            .run_in_background();

        assert_eq!(Err(mpsc::TryRecvError::Empty), rx2.try_recv());
        tx0.send(()).unwrap();
        rx2.recv().unwrap();
    }

    #[cfg(feature = "alloc")]
    #[test]
    fn and_then_drops_eagerly() {
        use futures::channel::oneshot;
        use futures::future::{self, TryFutureExt};
        use futures_test::future::FutureTestExt;
        use std::sync::mpsc;

        let (tx0, rx0) = oneshot::channel::<Result<(), ()>>();
        let (tx1, rx1) = mpsc::channel::<()>();
        let (tx2, rx2) = mpsc::channel::<()>();

        FutureData { _data: tx1, future: rx0.unwrap_or_else(|_| { panic!() }) }
            .and_then(move |_| {
                assert!(rx1.recv().is_err()); // tx1 should have been dropped
                tx2.send(()).unwrap();
                future::ready(Ok(()))
            })
            .run_in_background();

        assert_eq!(Err(mpsc::TryRecvError::Empty), rx2.try_recv());
        tx0.send(Ok(())).unwrap();
        rx2.recv().unwrap();
    }

    #[cfg(feature = "alloc")]
    #[test]
    fn or_else_drops_eagerly() {
        use futures::channel::oneshot;
        use futures::future::{self, TryFutureExt};
        use futures_test::future::FutureTestExt;
        use std::sync::mpsc;

        let (tx0, rx0) = oneshot::channel::<Result<(), ()>>();
        let (tx1, rx1) = mpsc::channel::<()>();
        let (tx2, rx2) = mpsc::channel::<()>();

        FutureData { _data: tx1, future: rx0.unwrap_or_else(|_| { panic!() }) }
            .or_else(move |_| {
                assert!(rx1.recv().is_err()); // tx1 should have been dropped
                tx2.send(()).unwrap();
                future::ready::<Result<(), ()>>(Ok(()))
            })
            .run_in_background();

        assert_eq!(Err(mpsc::TryRecvError::Empty), rx2.try_recv());
        tx0.send(Err(())).unwrap();
        rx2.recv().unwrap();
    }
}
<|endoftext|>


<commit_before>use std::default;
use std::process::Command;
use std::path::PathBuf;

use errors::*;
use output::{OutputAssertion, StdErr, StdOut};

/// Assertions for a specific command.
#[derive(Debug)]
pub struct Assert {
    cmd: Vec<String>,
    current_dir: Option<PathBuf>,
    expect_success: Option<bool>,
    expect_exit_code: Option<i32>,
    expect_stdout: Option<OutputAssertion<StdOut>>,
    expect_stderr: Option<OutputAssertion<StdErr>>,
}

impl default::Default for Assert {
    /// Construct an assert using `cargo run --` as command.
    ///
    /// Defaults to asserting _successful_ execution.
    fn default() -> Self {
        Assert {
            cmd: vec!["cargo", "run", "--"]
                .into_iter().map(String::from).collect(),
            current_dir: None,
            expect_success: Some(true),
            expect_exit_code: None,
            expect_stdout: None,
            expect_stderr: None,
        }
    }
}

impl Assert {
    /// Run the crate's main binary.
    ///
    /// Defaults to asserting _successful_ execution.
    pub fn main_binary() -> Self {
        Assert::default()
    }

    /// Run a specific binary of the current crate.
    ///
    /// Defaults to asserting _successful_ execution.
    pub fn cargo_binary(name: &str) -> Self {
        Assert {
            cmd: vec!["cargo", "run", "--bin", name, "--"]
                .into_iter().map(String::from).collect(),
            ..Self::default()
        }
    }

    /// Run a custom command.
    ///
    /// Defaults to asserting _successful_ execution.
    ///
    /// # Examples
    ///
    /// ```rust
    /// extern crate assert_cli;
    ///
    /// assert_cli::Assert::command(&["echo", "1337"])
    ///     .unwrap();
    /// ```
    pub fn command(cmd: &[&str]) -> Self {
        Assert {
            cmd: cmd.into_iter().cloned().map(String::from).collect(),
            ..Self::default()
        }
    }

    /// Add arguments to the command.
    ///
    /// # Examples
    ///
    /// ```rust
    /// extern crate assert_cli;
    ///
    /// assert_cli::Assert::command(&["echo"])
    ///     .with_args(&["42"])
    ///     .prints("42")
    ///     .unwrap();
    /// ```
    pub fn with_args(mut self, args: &[&str]) -> Self {
        self.cmd.extend(args.into_iter().cloned().map(String::from));
        self
    }

    /// Sets the working directory for the command.
    ///
    /// # Examples
    ///
    /// ```rust
    /// extern crate assert_cli;
    ///
    /// assert_cli::Assert::command(&["wc", "lib.rs"])
    ///     .current_dir(std::path::Path::new("src"))
    ///     .prints("lib.rs")
    ///     .execute()
    ///     .unwrap();
    /// ```
    pub fn current_dir<P: Into<PathBuf>>(mut self, dir: P) -> Self {
        self.current_dir = Some(dir.into());
        self
    }

    /// Small helper to make chains more readable.
    ///
    /// # Examples
    ///
    /// ```rust
    /// extern crate assert_cli;
    ///
    /// assert_cli::Assert::command(&["echo", "42"])
    ///     .prints("42")
    ///     .unwrap();
    /// ```
    pub fn and(self) -> Self {
        self
    }

    /// Expect the command to be executed successfully.
    ///
    /// # Examples
    ///
    /// ```rust
    /// extern crate assert_cli;
    ///
    /// assert_cli::Assert::command(&["echo", "42"])
    ///     .unwrap();
    /// ```
    pub fn succeeds(mut self) -> Self {
        self.expect_exit_code = None;
        self.expect_success = Some(true);
        self
    }

    /// Expect the command to fail.
    ///
    /// Note: This does not include shell failures like `command not found`. I.e. the
    ///       command must _run_ and fail for this assertion to pass.
    ///
    /// # Examples
    ///
    /// ```rust
    /// extern crate assert_cli;
    ///
    /// assert_cli::Assert::command(&["cat", "non-existing-file"])
    ///     .fails()
    ///     .and()
    ///     .prints_error("non-existing-file")
    ///     .unwrap();
    /// ```
    pub fn fails(mut self) -> Self {
        self.expect_success = Some(false);
        self
    }

    /// Expect the command to fail and return a specific error code.
    ///
    /// # Examples
    ///
    /// ```rust
    /// extern crate assert_cli;
    ///
    /// assert_cli::Assert::command(&["cat", "non-existing-file"])
    ///     .fails_with(1)
    ///     .and()
    ///     .prints_error_exactly("cat: non-existing-file: No such file or directory")
    ///     .unwrap();
    /// ```
    pub fn fails_with(mut self, expect_exit_code: i32) -> Self {
        self.expect_success = Some(false);
        self.expect_exit_code = Some(expect_exit_code);
        self
    }

    /// Expect the command's output to **contain** `output`.
    ///
    /// # Examples
    ///
    /// ```rust
    /// extern crate assert_cli;
    ///
    /// assert_cli::Assert::command(&["echo", "42"])
    ///     .prints("42")
    ///     .unwrap();
    /// ```
    pub fn prints<O: Into<String>>(mut self, output: O) -> Self {
        self.expect_stdout = Some(OutputAssertion {
            expect: output.into(),
            fuzzy: true,
            expected_result: true,
            kind: StdOut,
        });
        self
    }

    /// Expect the command to output **exactly** this `output`.
    ///
    /// # Examples
    ///
    /// ```rust
    /// extern crate assert_cli;
    ///
    /// assert_cli::Assert::command(&["echo", "42"])
    ///     .prints_exactly("42")
    ///     .unwrap();
    /// ```
    pub fn prints_exactly<O: Into<String>>(mut self, output: O) -> Self {
        self.expect_stdout = Some(OutputAssertion {
            expect: output.into(),
            fuzzy: false,
            expected_result: true,
            kind: StdOut,
        });
        self
    }

    /// Expect the command's stderr output to **contain** `output`.
    ///
    /// # Examples
    ///
    /// ```rust
    /// extern crate assert_cli;
    ///
    /// assert_cli::Assert::command(&["cat", "non-existing-file"])
    ///     .fails()
    ///     .and()
    ///     .prints_error("non-existing-file")
    ///     .unwrap();
    /// ```
    pub fn prints_error<O: Into<String>>(mut self, output: O) -> Self {
        self.expect_stderr = Some(OutputAssertion {
            expect: output.into(),
            fuzzy: true,
            expected_result: true,
            kind: StdErr,
        });
        self
    }

    /// Expect the command to output **exactly** this `output` to stderr.
    ///
    /// # Examples
    ///
    /// ```rust
    /// extern crate assert_cli;
    ///
    /// assert_cli::Assert::command(&["cat", "non-existing-file"])
    ///     .fails_with(1)
    ///     .and()
    ///     .prints_error_exactly("cat: non-existing-file: No such file or directory")
    ///     .unwrap();
    /// ```
    pub fn prints_error_exactly<O: Into<String>>(mut self, output: O) -> Self {
        self.expect_stderr = Some(OutputAssertion {
            expect: output.into(),
            fuzzy: false,
            expected_result: true,
            kind: StdErr,
        });
        self
    }

    /// Expect the command's output to not **contain** `output`.
    ///
    /// # Examples
    ///
    /// ```rust
    /// extern crate assert_cli;
    ///
    /// assert_cli::Assert::command(&["echo", "42"])
    ///     .doesnt_print("73")
    ///     .execute()
    ///     .unwrap();
    /// ```
    pub fn doesnt_print<O: Into<String>>(mut self, output: O) -> Self {
        self.expect_stdout = Some(OutputAssertion {
            expect: output.into(),
            fuzzy: true,
            expected_result: false,
            kind: StdOut,
        });
        self
    }

    /// Expect the command to output to not be **exactly** this `output`.
    ///
    /// # Examples
    ///
    /// ```rust
    /// extern crate assert_cli;
    ///
    /// assert_cli::Assert::command(&["echo", "42"])
    ///     .doesnt_print_exactly("73")
    ///     .execute()
    ///     .unwrap();
    /// ```
    pub fn doesnt_print_exactly<O: Into<String>>(mut self, output: O) -> Self {
        self.expect_stdout = Some(OutputAssertion {
            expect: output.into(),
            fuzzy: false,
            expected_result: false,
            kind: StdOut,
        });
        self
    }

    /// Expect the command's stderr output to not **contain** `output`.
    ///
    /// # Examples
    ///
    /// ```rust
    /// extern crate assert_cli;
    ///
    /// assert_cli::Assert::command(&["cat", "non-existing-file"])
    ///     .fails()
    ///     .and()
    ///     .doesnt_print_error("content")
    ///     .execute()
    ///     .unwrap();
    /// ```
    pub fn doesnt_print_error<O: Into<String>>(mut self, output: O) -> Self {
        self.expect_stderr = Some(OutputAssertion {
            expect: output.into(),
            fuzzy: true,
            expected_result: false,
            kind: StdErr,
        });
        self
    }

    /// Expect the command to output to not be **exactly** this `output` to stderr.
    ///
    /// # Examples
    ///
    /// ```rust
    /// extern crate assert_cli;
    ///
    /// assert_cli::Assert::command(&["cat", "non-existing-file"])
    ///     .fails_with(1)
    ///     .and()
    ///     .doesnt_print_error_exactly("content")
    ///     .execute()
    ///     .unwrap();
    /// ```
    pub fn doesnt_print_error_exactly<O: Into<String>>(mut self, output: O) -> Self {
        self.expect_stderr = Some(OutputAssertion {
            expect: output.into(),
            fuzzy: false,
            expected_result: false,
            kind: StdErr,
        });
        self
    }

    /// Execute the command and check the assertions.
    ///
    /// # Examples
    ///
    /// ```rust
    /// extern crate assert_cli;
    ///
    /// let test = assert_cli::Assert::command(&["echo", "42"])
    ///     .prints("42")
    ///     .execute();
    /// assert!(test.is_ok());
    /// ```
    pub fn execute(self) -> Result<()> {
        let cmd = &self.cmd[0];
        let args: Vec<_> = self.cmd.iter().skip(1).collect();
        let mut command = Command::new(cmd);
        let command = command.args(&args);
        let command = match self.current_dir {
            Some(ref dir) => command.current_dir(dir),
            None => command,
        };
        let output = command.output()?;

        if let Some(expect_success) = self.expect_success {
            if expect_success != output.status.success() {
                bail!(ErrorKind::StatusMismatch(
                    self.cmd.clone(),
                    expect_success,
                ));
            }
        }

        if self.expect_exit_code.is_some() &&
            self.expect_exit_code != output.status.code() {
            bail!(ErrorKind::ExitCodeMismatch(
                self.cmd.clone(),
                self.expect_exit_code,
                output.status.code(),
            ));
        }

        if let Some(ref ouput_assertion) = self.expect_stdout {
            ouput_assertion.execute(&output)
                .map_err(|e| ErrorKind::StdoutMismatch(self.cmd.clone(), e))?;
        }

        if let Some(ref ouput_assertion) = self.expect_stderr {
            ouput_assertion.execute(&output)
                .map_err(|e| ErrorKind::StderrMismatch(self.cmd.clone(), e))?;
        }

        Ok(())
    }

    /// Execute the command, check the assertions, and panic when they fail.
    ///
    /// # Examples
    ///
    /// ```rust,should_panic="Assert CLI failure"
    /// extern crate assert_cli;
    ///
    /// assert_cli::Assert::command(&["echo", "42"])
    ///     .fails()
    ///     .unwrap(); // panics
    /// ```
    pub fn unwrap(self) {
        if let Err(err) = self.execute() {
            panic!("{}", err);
        }
    }
}
<commit_msg>Support more than one output assertion<commit_after>use std::default;
use std::process::Command;
use std::path::PathBuf;
use std::vec::Vec;

use errors::*;
use output::{OutputAssertion, StdErr, StdOut};

/// Assertions for a specific command.
#[derive(Debug)]
pub struct Assert {
    cmd: Vec<String>,
    current_dir: Option<PathBuf>,
    expect_success: Option<bool>,
    expect_exit_code: Option<i32>,
    expect_stdout: Vec<OutputAssertion<StdOut>>,
    expect_stderr: Vec<OutputAssertion<StdErr>>,
}

impl default::Default for Assert {
    /// Construct an assert using `cargo run --` as command.
    ///
    /// Defaults to asserting _successful_ execution.
    fn default() -> Self {
        Assert {
            cmd: vec!["cargo", "run", "--"]
                .into_iter().map(String::from).collect(),
            current_dir: None,
            expect_success: Some(true),
            expect_exit_code: None,
            expect_stdout: vec![],
            expect_stderr: vec![],
        }
    }
}

impl Assert {
    /// Run the crate's main binary.
    ///
    /// Defaults to asserting _successful_ execution.
    pub fn main_binary() -> Self {
        Assert::default()
    }

    /// Run a specific binary of the current crate.
    ///
    /// Defaults to asserting _successful_ execution.
    pub fn cargo_binary(name: &str) -> Self {
        Assert {
            cmd: vec!["cargo", "run", "--bin", name, "--"]
                .into_iter().map(String::from).collect(),
            ..Self::default()
        }
    }

    /// Run a custom command.
    ///
    /// Defaults to asserting _successful_ execution.
    ///
    /// # Examples
    ///
    /// ```rust
    /// extern crate assert_cli;
    ///
    /// assert_cli::Assert::command(&["echo", "1337"])
    ///     .unwrap();
    /// ```
    pub fn command(cmd: &[&str]) -> Self {
        Assert {
            cmd: cmd.into_iter().cloned().map(String::from).collect(),
            ..Self::default()
        }
    }

    /// Add arguments to the command.
    ///
    /// # Examples
    ///
    /// ```rust
    /// extern crate assert_cli;
    ///
    /// assert_cli::Assert::command(&["echo"])
    ///     .with_args(&["42"])
    ///     .prints("42")
    ///     .unwrap();
    /// ```
    pub fn with_args(mut self, args: &[&str]) -> Self {
        self.cmd.extend(args.into_iter().cloned().map(String::from));
        self
    }

    /// Sets the working directory for the command.
    ///
    /// # Examples
    ///
    /// ```rust
    /// extern crate assert_cli;
    ///
    /// assert_cli::Assert::command(&["wc", "lib.rs"])
    ///     .current_dir(std::path::Path::new("src"))
    ///     .prints("lib.rs")
    ///     .execute()
    ///     .unwrap();
    /// ```
    pub fn current_dir<P: Into<PathBuf>>(mut self, dir: P) -> Self {
        self.current_dir = Some(dir.into());
        self
    }

    /// Small helper to make chains more readable.
    ///
    /// # Examples
    ///
    /// ```rust
    /// extern crate assert_cli;
    ///
    /// assert_cli::Assert::command(&["echo", "42"])
    ///     .prints("42")
    ///     .unwrap();
    /// ```
    pub fn and(self) -> Self {
        self
    }

    /// Expect the command to be executed successfully.
    ///
    /// # Examples
    ///
    /// ```rust
    /// extern crate assert_cli;
    ///
    /// assert_cli::Assert::command(&["echo", "42"])
    ///     .unwrap();
    /// ```
    pub fn succeeds(mut self) -> Self {
        self.expect_exit_code = None;
        self.expect_success = Some(true);
        self
    }

    /// Expect the command to fail.
    ///
    /// Note: This does not include shell failures like `command not found`. I.e. the
    ///       command must _run_ and fail for this assertion to pass.
    ///
    /// # Examples
    ///
    /// ```rust
    /// extern crate assert_cli;
    ///
    /// assert_cli::Assert::command(&["cat", "non-existing-file"])
    ///     .fails()
    ///     .and()
    ///     .prints_error("non-existing-file")
    ///     .unwrap();
    /// ```
    pub fn fails(mut self) -> Self {
        self.expect_success = Some(false);
        self
    }

    /// Expect the command to fail and return a specific error code.
    ///
    /// # Examples
    ///
    /// ```rust
    /// extern crate assert_cli;
    ///
    /// assert_cli::Assert::command(&["cat", "non-existing-file"])
    ///     .fails_with(1)
    ///     .and()
    ///     .prints_error_exactly("cat: non-existing-file: No such file or directory")
    ///     .unwrap();
    /// ```
    pub fn fails_with(mut self, expect_exit_code: i32) -> Self {
        self.expect_success = Some(false);
        self.expect_exit_code = Some(expect_exit_code);
        self
    }

    /// Expect the command's output to **contain** `output`.
    ///
    /// # Examples
    ///
    /// ```rust
    /// extern crate assert_cli;
    ///
    /// assert_cli::Assert::command(&["echo", "42"])
    ///     .prints("42")
    ///     .unwrap();
    /// ```
    pub fn prints<O: Into<String>>(mut self, output: O) -> Self {
        self.expect_stdout.push(OutputAssertion {
            expect: output.into(),
            fuzzy: true,
            expected_result: true,
            kind: StdOut,
        });
        self
    }

    /// Expect the command to output **exactly** this `output`.
    ///
    /// # Examples
    ///
    /// ```rust
    /// extern crate assert_cli;
    ///
    /// assert_cli::Assert::command(&["echo", "42"])
    ///     .prints_exactly("42")
    ///     .unwrap();
    /// ```
    pub fn prints_exactly<O: Into<String>>(mut self, output: O) -> Self {
        self.expect_stdout.push(OutputAssertion {
            expect: output.into(),
            fuzzy: false,
            expected_result: true,
            kind: StdOut,
        });
        self
    }

    /// Expect the command's stderr output to **contain** `output`.
    ///
    /// # Examples
    ///
    /// ```rust
    /// extern crate assert_cli;
    ///
    /// assert_cli::Assert::command(&["cat", "non-existing-file"])
    ///     .fails()
    ///     .and()
    ///     .prints_error("non-existing-file")
    ///     .unwrap();
    /// ```
    pub fn prints_error<O: Into<String>>(mut self, output: O) -> Self {
        self.expect_stderr.push(OutputAssertion {
            expect: output.into(),
            fuzzy: true,
            expected_result: true,
            kind: StdErr,
        });
        self
    }

    /// Expect the command to output **exactly** this `output` to stderr.
    ///
    /// # Examples
    ///
    /// ```rust
    /// extern crate assert_cli;
    ///
    /// assert_cli::Assert::command(&["cat", "non-existing-file"])
    ///     .fails_with(1)
    ///     .and()
    ///     .prints_error_exactly("cat: non-existing-file: No such file or directory")
    ///     .unwrap();
    /// ```
    pub fn prints_error_exactly<O: Into<String>>(mut self, output: O) -> Self {
        self.expect_stderr.push(OutputAssertion {
            expect: output.into(),
            fuzzy: false,
            expected_result: true,
            kind: StdErr,
        });
        self
    }

    /// Expect the command's output to not **contain** `output`.
    ///
    /// # Examples
    ///
    /// ```rust
    /// extern crate assert_cli;
    ///
    /// assert_cli::Assert::command(&["echo", "42"])
    ///     .doesnt_print("73")
    ///     .execute()
    ///     .unwrap();
    /// ```
    pub fn doesnt_print<O: Into<String>>(mut self, output: O) -> Self {
        self.expect_stdout.push(OutputAssertion {
            expect: output.into(),
            fuzzy: true,
            expected_result: false,
            kind: StdOut,
        });
        self
    }

    /// Expect the command to output to not be **exactly** this `output`.
    ///
    /// # Examples
    ///
    /// ```rust
    /// extern crate assert_cli;
    ///
    /// assert_cli::Assert::command(&["echo", "42"])
    ///     .doesnt_print_exactly("73")
    ///     .execute()
    ///     .unwrap();
    /// ```
    pub fn doesnt_print_exactly<O: Into<String>>(mut self, output: O) -> Self {
        self.expect_stdout.push(OutputAssertion {
            expect: output.into(),
            fuzzy: false,
            expected_result: false,
            kind: StdOut,
        });
        self
    }

    /// Expect the command's stderr output to not **contain** `output`.
    ///
    /// # Examples
    ///
    /// ```rust
    /// extern crate assert_cli;
    ///
    /// assert_cli::Assert::command(&["cat", "non-existing-file"])
    ///     .fails()
    ///     .and()
    ///     .doesnt_print_error("content")
    ///     .execute()
    ///     .unwrap();
    /// ```
    pub fn doesnt_print_error<O: Into<String>>(mut self, output: O) -> Self {
        self.expect_stderr.push(OutputAssertion {
            expect: output.into(),
            fuzzy: true,
            expected_result: false,
            kind: StdErr,
        });
        self
    }

    /// Expect the command to output to not be **exactly** this `output` to stderr.
    ///
    /// # Examples
    ///
    /// ```rust
    /// extern crate assert_cli;
    ///
    /// assert_cli::Assert::command(&["cat", "non-existing-file"])
    ///     .fails_with(1)
    ///     .and()
    ///     .doesnt_print_error_exactly("content")
    ///     .execute()
    ///     .unwrap();
    /// ```
    pub fn doesnt_print_error_exactly<O: Into<String>>(mut self, output: O) -> Self {
        self.expect_stderr.push(OutputAssertion {
            expect: output.into(),
            fuzzy: false,
            expected_result: false,
            kind: StdErr,
        });
        self
    }

    /// Execute the command and check the assertions.
    ///
    /// # Examples
    ///
    /// ```rust
    /// extern crate assert_cli;
    ///
    /// let test = assert_cli::Assert::command(&["echo", "42"])
    ///     .prints("42")
    ///     .execute();
    /// assert!(test.is_ok());
    /// ```
    pub fn execute(self) -> Result<()> {
        let cmd = &self.cmd[0];
        let args: Vec<_> = self.cmd.iter().skip(1).collect();
        let mut command = Command::new(cmd);
        let command = command.args(&args);
        let command = match self.current_dir {
            Some(ref dir) => command.current_dir(dir),
            None => command,
        };
        let output = command.output()?;

        if let Some(expect_success) = self.expect_success {
            if expect_success != output.status.success() {
                bail!(ErrorKind::StatusMismatch(
                    self.cmd.clone(),
                    expect_success,
                ));
            }
        }

        if self.expect_exit_code.is_some() &&
            self.expect_exit_code != output.status.code() {
            bail!(ErrorKind::ExitCodeMismatch(
                self.cmd.clone(),
                self.expect_exit_code,
                output.status.code(),
            ));
        }

        self.expect_stdout
            .iter()
            .map(|a| a.execute(&output).map_err(|e| ErrorKind::StdoutMismatch(self.cmd.clone(), e).into()))
            .collect::<Result<Vec<()>>>()?;
        self.expect_stderr
            .iter()
            .map(|a| a.execute(&output).map_err(|e| ErrorKind::StderrMismatch(self.cmd.clone(), e).into()))
            .collect::<Result<Vec<()>>>()?;

        Ok(())
    }

    /// Execute the command, check the assertions, and panic when they fail.
    ///
    /// # Examples
    ///
    /// ```rust,should_panic="Assert CLI failure"
    /// extern crate assert_cli;
    ///
    /// assert_cli::Assert::command(&["echo", "42"])
    ///     .fails()
    ///     .unwrap(); // panics
    /// ```
    pub fn unwrap(self) {
        if let Err(err) = self.execute() {
            panic!("{}", err);
        }
    }
}
<|endoftext|>


<commit_before>//! A stably addressed token buffer supporting efficient traversal based on a
//! cheaply copyable cursor.
//!
//! *This module is available only if Syn is built with the `"parsing"` feature.*

// This module is heavily commented as it contains most of the unsafe code in
// Syn, and caution should be used when editing it. The public-facing interface
// is 100% safe but the implementation is fragile internally.

#[cfg(all(
    not(all(target_arch = "wasm32", any(target_os = "unknown", target_os = "wasi"))),
    feature = "proc-macro"
))]
use crate::proc_macro as pm;
use crate::Lifetime;
use proc_macro2::{Delimiter, Group, Ident, Literal, Punct, Spacing, Span, TokenStream, TokenTree};
use std::marker::PhantomData;

/// Internal type which is used instead of `TokenTree` to represent a token tree
/// within a `TokenBuffer`.
enum Entry {
    // Mimicking types from proc-macro.
    // Group entries contain the offset to the matching End entry.
    Group(Group, usize),
    Ident(Ident),
    Punct(Punct),
    Literal(Literal),
    End,
}

/// A buffer that can be efficiently traversed multiple times, unlike
/// `TokenStream` which requires a deep copy in order to traverse more than
/// once.
///
/// *This type is available only if Syn is built with the `"parsing"` feature.*
pub struct TokenBuffer {
    // NOTE: Do not implement clone on this - while the current design could be
    // cloned, other designs which could be desirable may not be cloneable.
    entries: Box<[Entry]>,
}

// Keep the explicit impl for backwards compatibility.
impl Drop for TokenBuffer {
    fn drop(&mut self) {}
}

impl TokenBuffer {
    fn new_inner(entries: &mut Vec<Entry>, stream: TokenStream) {
        for tt in stream {
            match tt {
                TokenTree::Ident(ident) => entries.push(Entry::Ident(ident)),
                TokenTree::Punct(punct) => entries.push(Entry::Punct(punct)),
                TokenTree::Literal(literal) => entries.push(Entry::Literal(literal)),
                TokenTree::Group(group) => {
                    let group_start_index = entries.len();
                    entries.push(Entry::End); // we replace this below
                    Self::new_inner(entries, group.stream());
                    let group_end_index = entries.len();
                    entries.push(Entry::End);
                    let group_end_offset = group_end_index - group_start_index;
                    entries[group_start_index] = Entry::Group(group, group_end_offset);
                }
            }
        }
    }

    /// Creates a `TokenBuffer` containing all the tokens from the input
    /// `proc_macro::TokenStream`.
    ///
    /// *This method is available only if Syn is built with both the `"parsing"` and
    /// `"proc-macro"` features.*
    #[cfg(all(
        not(all(target_arch = "wasm32", any(target_os = "unknown", target_os = "wasi"))),
        feature = "proc-macro"
    ))]
    pub fn new(stream: pm::TokenStream) -> Self {
        Self::new2(stream.into())
    }

    /// Creates a `TokenBuffer` containing all the tokens from the input
    /// `proc_macro2::TokenStream`.
    pub fn new2(stream: TokenStream) -> Self {
        let mut entries = Vec::new();
        Self::new_inner(&mut entries, stream);
        entries.push(Entry::End);
        Self {
            entries: entries.into_boxed_slice(),
        }
    }

    /// Creates a cursor referencing the first token in the buffer and able to
    /// traverse until the end of the buffer.
    pub fn begin(&self) -> Cursor {
        let ptr = self.entries.as_ptr();
        unsafe { Cursor::create(ptr, ptr.add(self.entries.len() - 1)) }
    }
}

/// A cheaply copyable cursor into a `TokenBuffer`.
///
/// This cursor holds a shared reference into the immutable data which is used
/// internally to represent a `TokenStream`, and can be efficiently manipulated
/// and copied around.
///
/// An empty `Cursor` can be created directly, or one may create a `TokenBuffer`
/// object and get a cursor to its first token with `begin()`.
///
/// Two cursors are equal if they have the same location in the same input
/// stream, and have the same scope.
///
/// *This type is available only if Syn is built with the `"parsing"` feature.*
pub struct Cursor<'a> {
    // The current entry which the `Cursor` is pointing at.
    ptr: *const Entry,
    // This is the only `Entry::End` object which this cursor is allowed to
    // point at. All other `End` objects are skipped over in `Cursor::create`.
    scope: *const Entry,
    // Cursor is covariant in 'a. This field ensures that our pointers are still
    // valid.
    marker: PhantomData<&'a Entry>,
}

impl<'a> Cursor<'a> {
    /// Creates a cursor referencing a static empty TokenStream.
    pub fn empty() -> Self {
        // It's safe in this situation for us to put an `Entry` object in global
        // storage, despite it not actually being safe to send across threads
        // (`Ident` is a reference into a thread-local table). This is because
        // this entry never includes a `Ident` object.
        //
        // This wrapper struct allows us to break the rules and put a `Sync`
        // object in global storage.
        struct UnsafeSyncEntry(Entry);
        unsafe impl Sync for UnsafeSyncEntry {}
        static EMPTY_ENTRY: UnsafeSyncEntry = UnsafeSyncEntry(Entry::End);

        Cursor {
            ptr: &EMPTY_ENTRY.0,
            scope: &EMPTY_ENTRY.0,
            marker: PhantomData,
        }
    }

    /// This create method intelligently exits non-explicitly-entered
    /// `None`-delimited scopes when the cursor reaches the end of them,
    /// allowing for them to be treated transparently.
    unsafe fn create(mut ptr: *const Entry, scope: *const Entry) -> Self {
        // NOTE: If we're looking at a `End`, we want to advance the cursor
        // past it, unless `ptr == scope`, which means that we're at the edge of
        // our cursor's scope. We should only have `ptr != scope` at the exit
        // from None-delimited groups entered with `ignore_none`.
        while let Entry::End = *ptr {
            if ptr == scope {
                break;
            }
            ptr = ptr.add(1);
        }

        Cursor {
            ptr,
            scope,
            marker: PhantomData,
        }
    }

    /// Get the current entry.
    fn entry(self) -> &'a Entry {
        unsafe { &*self.ptr }
    }

    /// Bump the cursor to point at the next token after the current one. This
    /// is undefined behavior if the cursor is currently looking at an
    /// `Entry::End`.
    ///
    /// If the cursor is looking at an `Entry::Group`, the bumped cursor will
    /// point at the first token in the group (with the same scope end).
    unsafe fn bump_ignore_group(self) -> Cursor<'a> {
        Cursor::create(self.ptr.offset(1), self.scope)
    }

    /// While the cursor is looking at a `None`-delimited group, move it to look
    /// at the first token inside instead. If the group is empty, this will move
    /// the cursor past the `None`-delimited group.
    ///
    /// WARNING: This mutates its argument.
    fn ignore_none(&mut self) {
        while let Entry::Group(group, _) = self.entry() {
            if group.delimiter() == Delimiter::None {
                unsafe { *self = self.bump_ignore_group() };
            } else {
                break;
            }
        }
    }

    /// Checks whether the cursor is currently pointing at the end of its valid
    /// scope.
    pub fn eof(self) -> bool {
        // We're at eof if we're at the end of our scope.
        self.ptr == self.scope
    }

    /// If the cursor is pointing at a `Group` with the given delimiter, returns
    /// a cursor into that group and one pointing to the next `TokenTree`.
    pub fn group(mut self, delim: Delimiter) -> Option<(Cursor<'a>, Span, Cursor<'a>)> {
        // If we're not trying to enter a none-delimited group, we want to
        // ignore them. We have to make sure to _not_ ignore them when we want
        // to enter them, of course. For obvious reasons.
        if delim != Delimiter::None {
            self.ignore_none();
        }

        if let Entry::Group(group, end_offset) = self.entry() {
            if group.delimiter() == delim {
                let end_of_group = unsafe { self.ptr.add(*end_offset) };
                let inside_of_group = unsafe { Cursor::create(self.ptr.add(1), end_of_group) };
                let after_group = unsafe { Cursor::create(end_of_group, self.scope) };
                return Some((inside_of_group, group.span(), after_group));
            }
        }

        None
    }

    /// If the cursor is pointing at a `Ident`, returns it along with a cursor
    /// pointing at the next `TokenTree`.
    pub fn ident(mut self) -> Option<(Ident, Cursor<'a>)> {
        self.ignore_none();
        match self.entry() {
            Entry::Ident(ident) => Some((ident.clone(), unsafe { self.bump_ignore_group() })),
            _ => None,
        }
    }

    /// If the cursor is pointing at a `Punct`, returns it along with a cursor
    /// pointing at the next `TokenTree`.
    pub fn punct(mut self) -> Option<(Punct, Cursor<'a>)> {
        self.ignore_none();
        match self.entry() {
            Entry::Punct(punct) if punct.as_char() != '\'' => {
                Some((punct.clone(), unsafe { self.bump_ignore_group() }))
            }
            _ => None,
        }
    }

    /// If the cursor is pointing at a `Literal`, return it along with a cursor
    /// pointing at the next `TokenTree`.
    pub fn literal(mut self) -> Option<(Literal, Cursor<'a>)> {
        self.ignore_none();
        match self.entry() {
            Entry::Literal(literal) => Some((literal.clone(), unsafe { self.bump_ignore_group() })),
            _ => None,
        }
    }

    /// If the cursor is pointing at a `Lifetime`, returns it along with a
    /// cursor pointing at the next `TokenTree`.
    pub fn lifetime(mut self) -> Option<(Lifetime, Cursor<'a>)> {
        self.ignore_none();
        match self.entry() {
            Entry::Punct(punct) if punct.as_char() == '\'' && punct.spacing() == Spacing::Joint => {
                let next = unsafe { self.bump_ignore_group() };
                match next.ident() {
                    Some((ident, rest)) => {
                        let lifetime = Lifetime {
                            apostrophe: punct.span(),
                            ident,
                        };
                        Some((lifetime, rest))
                    }
                    None => None,
                }
            }
            _ => None,
        }
    }

    /// Copies all remaining tokens visible from this cursor into a
    /// `TokenStream`.
    pub fn token_stream(self) -> TokenStream {
        let mut tts = Vec::new();
        let mut cursor = self;
        while let Some((tt, rest)) = cursor.token_tree() {
            tts.push(tt);
            cursor = rest;
        }
        tts.into_iter().collect()
    }

    /// If the cursor is pointing at a `TokenTree`, returns it along with a
    /// cursor pointing at the next `TokenTree`.
    ///
    /// Returns `None` if the cursor has reached the end of its stream.
    ///
    /// This method does not treat `None`-delimited groups as transparent, and
    /// will return a `Group(None, ..)` if the cursor is looking at one.
    pub fn token_tree(self) -> Option<(TokenTree, Cursor<'a>)> {
        let (tree, len) = match self.entry() {
            Entry::Group(group, end_offset) => (group.clone().into(), *end_offset),
            Entry::Literal(literal) => (literal.clone().into(), 1),
            Entry::Ident(ident) => (ident.clone().into(), 1),
            Entry::Punct(punct) => (punct.clone().into(), 1),
            Entry::End => return None,
        };

        let rest = unsafe { Cursor::create(self.ptr.add(len), self.scope) };
        Some((tree, rest))
    }

    /// Returns the `Span` of the current token, or `Span::call_site()` if this
    /// cursor points to eof.
    pub fn span(self) -> Span {
        match self.entry() {
            Entry::Group(group, _) => group.span(),
            Entry::Literal(literal) => literal.span(),
            Entry::Ident(ident) => ident.span(),
            Entry::Punct(punct) => punct.span(),
            Entry::End => Span::call_site(),
        }
    }

    /// Skip over the next token without cloning it. Returns `None` if this
    /// cursor points to eof.
    ///
    /// This method treats `'lifetimes` as a single token.
    pub(crate) fn skip(self) -> Option<Cursor<'a>> {
        let len = match self.entry() {
            Entry::End => return None,

            // Treat lifetimes as a single tt for the purposes of 'skip'.
            Entry::Punct(punct) if punct.as_char() == '\'' && punct.spacing() == Spacing::Joint => {
                match unsafe { &*self.ptr.add(1) } {
                    Entry::Ident(_) => 2,
                    _ => 1,
                }
            }

            Entry::Group(_, end_offset) => *end_offset,
            _ => 1,
        };

        Some(unsafe { Cursor::create(self.ptr.add(len), self.scope) })
    }
}

impl<'a> Copy for Cursor<'a> {}

impl<'a> Clone for Cursor<'a> {
    fn clone(&self) -> Self {
        *self
    }
}

impl<'a> Eq for Cursor<'a> {}

impl<'a> PartialEq for Cursor<'a> {
    fn eq(&self, other: &Self) -> bool {
        let Cursor { ptr, scope, marker } = self;
        let _ = marker;
        *ptr == other.ptr && *scope == other.scope
    }
}

pub(crate) fn same_scope(a: Cursor, b: Cursor) -> bool {
    a.scope == b.scope
}

pub(crate) fn open_span_of_group(cursor: Cursor) -> Span {
    match cursor.entry() {
        Entry::Group(group, _) => group.span_open(),
        _ => cursor.span(),
    }
}

pub(crate) fn close_span_of_group(cursor: Cursor) -> Span {
    match cursor.entry() {
        Entry::Group(group, _) => group.span_close(),
        _ => cursor.span(),
    }
}
<commit_msg>Simplify Cursor::lifetime using a question mark<commit_after>//! A stably addressed token buffer supporting efficient traversal based on a
//! cheaply copyable cursor.
//!
//! *This module is available only if Syn is built with the `"parsing"` feature.*

// This module is heavily commented as it contains most of the unsafe code in
// Syn, and caution should be used when editing it. The public-facing interface
// is 100% safe but the implementation is fragile internally.

#[cfg(all(
    not(all(target_arch = "wasm32", any(target_os = "unknown", target_os = "wasi"))),
    feature = "proc-macro"
))]
use crate::proc_macro as pm;
use crate::Lifetime;
use proc_macro2::{Delimiter, Group, Ident, Literal, Punct, Spacing, Span, TokenStream, TokenTree};
use std::marker::PhantomData;

/// Internal type which is used instead of `TokenTree` to represent a token tree
/// within a `TokenBuffer`.
enum Entry {
    // Mimicking types from proc-macro.
    // Group entries contain the offset to the matching End entry.
    Group(Group, usize),
    Ident(Ident),
    Punct(Punct),
    Literal(Literal),
    End,
}

/// A buffer that can be efficiently traversed multiple times, unlike
/// `TokenStream` which requires a deep copy in order to traverse more than
/// once.
///
/// *This type is available only if Syn is built with the `"parsing"` feature.*
pub struct TokenBuffer {
    // NOTE: Do not implement clone on this - while the current design could be
    // cloned, other designs which could be desirable may not be cloneable.
    entries: Box<[Entry]>,
}

// Keep the explicit impl for backwards compatibility.
impl Drop for TokenBuffer {
    fn drop(&mut self) {}
}

impl TokenBuffer {
    fn new_inner(entries: &mut Vec<Entry>, stream: TokenStream) {
        for tt in stream {
            match tt {
                TokenTree::Ident(ident) => entries.push(Entry::Ident(ident)),
                TokenTree::Punct(punct) => entries.push(Entry::Punct(punct)),
                TokenTree::Literal(literal) => entries.push(Entry::Literal(literal)),
                TokenTree::Group(group) => {
                    let group_start_index = entries.len();
                    entries.push(Entry::End); // we replace this below
                    Self::new_inner(entries, group.stream());
                    let group_end_index = entries.len();
                    entries.push(Entry::End);
                    let group_end_offset = group_end_index - group_start_index;
                    entries[group_start_index] = Entry::Group(group, group_end_offset);
                }
            }
        }
    }

    /// Creates a `TokenBuffer` containing all the tokens from the input
    /// `proc_macro::TokenStream`.
    ///
    /// *This method is available only if Syn is built with both the `"parsing"` and
    /// `"proc-macro"` features.*
    #[cfg(all(
        not(all(target_arch = "wasm32", any(target_os = "unknown", target_os = "wasi"))),
        feature = "proc-macro"
    ))]
    pub fn new(stream: pm::TokenStream) -> Self {
        Self::new2(stream.into())
    }

    /// Creates a `TokenBuffer` containing all the tokens from the input
    /// `proc_macro2::TokenStream`.
    pub fn new2(stream: TokenStream) -> Self {
        let mut entries = Vec::new();
        Self::new_inner(&mut entries, stream);
        entries.push(Entry::End);
        Self {
            entries: entries.into_boxed_slice(),
        }
    }

    /// Creates a cursor referencing the first token in the buffer and able to
    /// traverse until the end of the buffer.
    pub fn begin(&self) -> Cursor {
        let ptr = self.entries.as_ptr();
        unsafe { Cursor::create(ptr, ptr.add(self.entries.len() - 1)) }
    }
}

/// A cheaply copyable cursor into a `TokenBuffer`.
///
/// This cursor holds a shared reference into the immutable data which is used
/// internally to represent a `TokenStream`, and can be efficiently manipulated
/// and copied around.
///
/// An empty `Cursor` can be created directly, or one may create a `TokenBuffer`
/// object and get a cursor to its first token with `begin()`.
///
/// Two cursors are equal if they have the same location in the same input
/// stream, and have the same scope.
///
/// *This type is available only if Syn is built with the `"parsing"` feature.*
pub struct Cursor<'a> {
    // The current entry which the `Cursor` is pointing at.
    ptr: *const Entry,
    // This is the only `Entry::End` object which this cursor is allowed to
    // point at. All other `End` objects are skipped over in `Cursor::create`.
    scope: *const Entry,
    // Cursor is covariant in 'a. This field ensures that our pointers are still
    // valid.
    marker: PhantomData<&'a Entry>,
}

impl<'a> Cursor<'a> {
    /// Creates a cursor referencing a static empty TokenStream.
    pub fn empty() -> Self {
        // It's safe in this situation for us to put an `Entry` object in global
        // storage, despite it not actually being safe to send across threads
        // (`Ident` is a reference into a thread-local table). This is because
        // this entry never includes a `Ident` object.
        //
        // This wrapper struct allows us to break the rules and put a `Sync`
        // object in global storage.
        struct UnsafeSyncEntry(Entry);
        unsafe impl Sync for UnsafeSyncEntry {}
        static EMPTY_ENTRY: UnsafeSyncEntry = UnsafeSyncEntry(Entry::End);

        Cursor {
            ptr: &EMPTY_ENTRY.0,
            scope: &EMPTY_ENTRY.0,
            marker: PhantomData,
        }
    }

    /// This create method intelligently exits non-explicitly-entered
    /// `None`-delimited scopes when the cursor reaches the end of them,
    /// allowing for them to be treated transparently.
    unsafe fn create(mut ptr: *const Entry, scope: *const Entry) -> Self {
        // NOTE: If we're looking at a `End`, we want to advance the cursor
        // past it, unless `ptr == scope`, which means that we're at the edge of
        // our cursor's scope. We should only have `ptr != scope` at the exit
        // from None-delimited groups entered with `ignore_none`.
        while let Entry::End = *ptr {
            if ptr == scope {
                break;
            }
            ptr = ptr.add(1);
        }

        Cursor {
            ptr,
            scope,
            marker: PhantomData,
        }
    }

    /// Get the current entry.
    fn entry(self) -> &'a Entry {
        unsafe { &*self.ptr }
    }

    /// Bump the cursor to point at the next token after the current one. This
    /// is undefined behavior if the cursor is currently looking at an
    /// `Entry::End`.
    ///
    /// If the cursor is looking at an `Entry::Group`, the bumped cursor will
    /// point at the first token in the group (with the same scope end).
    unsafe fn bump_ignore_group(self) -> Cursor<'a> {
        Cursor::create(self.ptr.offset(1), self.scope)
    }

    /// While the cursor is looking at a `None`-delimited group, move it to look
    /// at the first token inside instead. If the group is empty, this will move
    /// the cursor past the `None`-delimited group.
    ///
    /// WARNING: This mutates its argument.
    fn ignore_none(&mut self) {
        while let Entry::Group(group, _) = self.entry() {
            if group.delimiter() == Delimiter::None {
                unsafe { *self = self.bump_ignore_group() };
            } else {
                break;
            }
        }
    }

    /// Checks whether the cursor is currently pointing at the end of its valid
    /// scope.
    pub fn eof(self) -> bool {
        // We're at eof if we're at the end of our scope.
        self.ptr == self.scope
    }

    /// If the cursor is pointing at a `Group` with the given delimiter, returns
    /// a cursor into that group and one pointing to the next `TokenTree`.
    pub fn group(mut self, delim: Delimiter) -> Option<(Cursor<'a>, Span, Cursor<'a>)> {
        // If we're not trying to enter a none-delimited group, we want to
        // ignore them. We have to make sure to _not_ ignore them when we want
        // to enter them, of course. For obvious reasons.
        if delim != Delimiter::None {
            self.ignore_none();
        }

        if let Entry::Group(group, end_offset) = self.entry() {
            if group.delimiter() == delim {
                let end_of_group = unsafe { self.ptr.add(*end_offset) };
                let inside_of_group = unsafe { Cursor::create(self.ptr.add(1), end_of_group) };
                let after_group = unsafe { Cursor::create(end_of_group, self.scope) };
                return Some((inside_of_group, group.span(), after_group));
            }
        }

        None
    }

    /// If the cursor is pointing at a `Ident`, returns it along with a cursor
    /// pointing at the next `TokenTree`.
    pub fn ident(mut self) -> Option<(Ident, Cursor<'a>)> {
        self.ignore_none();
        match self.entry() {
            Entry::Ident(ident) => Some((ident.clone(), unsafe { self.bump_ignore_group() })),
            _ => None,
        }
    }

    /// If the cursor is pointing at a `Punct`, returns it along with a cursor
    /// pointing at the next `TokenTree`.
    pub fn punct(mut self) -> Option<(Punct, Cursor<'a>)> {
        self.ignore_none();
        match self.entry() {
            Entry::Punct(punct) if punct.as_char() != '\'' => {
                Some((punct.clone(), unsafe { self.bump_ignore_group() }))
            }
            _ => None,
        }
    }

    /// If the cursor is pointing at a `Literal`, return it along with a cursor
    /// pointing at the next `TokenTree`.
    pub fn literal(mut self) -> Option<(Literal, Cursor<'a>)> {
        self.ignore_none();
        match self.entry() {
            Entry::Literal(literal) => Some((literal.clone(), unsafe { self.bump_ignore_group() })),
            _ => None,
        }
    }

    /// If the cursor is pointing at a `Lifetime`, returns it along with a
    /// cursor pointing at the next `TokenTree`.
    pub fn lifetime(mut self) -> Option<(Lifetime, Cursor<'a>)> {
        self.ignore_none();
        match self.entry() {
            Entry::Punct(punct) if punct.as_char() == '\'' && punct.spacing() == Spacing::Joint => {
                let next = unsafe { self.bump_ignore_group() };
                let (ident, rest) = next.ident()?;
                let lifetime = Lifetime {
                    apostrophe: punct.span(),
                    ident,
                };
                Some((lifetime, rest))
            }
            _ => None,
        }
    }

    /// Copies all remaining tokens visible from this cursor into a
    /// `TokenStream`.
    pub fn token_stream(self) -> TokenStream {
        let mut tts = Vec::new();
        let mut cursor = self;
        while let Some((tt, rest)) = cursor.token_tree() {
            tts.push(tt);
            cursor = rest;
        }
        tts.into_iter().collect()
    }

    /// If the cursor is pointing at a `TokenTree`, returns it along with a
    /// cursor pointing at the next `TokenTree`.
    ///
    /// Returns `None` if the cursor has reached the end of its stream.
    ///
    /// This method does not treat `None`-delimited groups as transparent, and
    /// will return a `Group(None, ..)` if the cursor is looking at one.
    pub fn token_tree(self) -> Option<(TokenTree, Cursor<'a>)> {
        let (tree, len) = match self.entry() {
            Entry::Group(group, end_offset) => (group.clone().into(), *end_offset),
            Entry::Literal(literal) => (literal.clone().into(), 1),
            Entry::Ident(ident) => (ident.clone().into(), 1),
            Entry::Punct(punct) => (punct.clone().into(), 1),
            Entry::End => return None,
        };

        let rest = unsafe { Cursor::create(self.ptr.add(len), self.scope) };
        Some((tree, rest))
    }

    /// Returns the `Span` of the current token, or `Span::call_site()` if this
    /// cursor points to eof.
    pub fn span(self) -> Span {
        match self.entry() {
            Entry::Group(group, _) => group.span(),
            Entry::Literal(literal) => literal.span(),
            Entry::Ident(ident) => ident.span(),
            Entry::Punct(punct) => punct.span(),
            Entry::End => Span::call_site(),
        }
    }

    /// Skip over the next token without cloning it. Returns `None` if this
    /// cursor points to eof.
    ///
    /// This method treats `'lifetimes` as a single token.
    pub(crate) fn skip(self) -> Option<Cursor<'a>> {
        let len = match self.entry() {
            Entry::End => return None,

            // Treat lifetimes as a single tt for the purposes of 'skip'.
            Entry::Punct(punct) if punct.as_char() == '\'' && punct.spacing() == Spacing::Joint => {
                match unsafe { &*self.ptr.add(1) } {
                    Entry::Ident(_) => 2,
                    _ => 1,
                }
            }

            Entry::Group(_, end_offset) => *end_offset,
            _ => 1,
        };

        Some(unsafe { Cursor::create(self.ptr.add(len), self.scope) })
    }
}

impl<'a> Copy for Cursor<'a> {}

impl<'a> Clone for Cursor<'a> {
    fn clone(&self) -> Self {
        *self
    }
}

impl<'a> Eq for Cursor<'a> {}

impl<'a> PartialEq for Cursor<'a> {
    fn eq(&self, other: &Self) -> bool {
        let Cursor { ptr, scope, marker } = self;
        let _ = marker;
        *ptr == other.ptr && *scope == other.scope
    }
}

pub(crate) fn same_scope(a: Cursor, b: Cursor) -> bool {
    a.scope == b.scope
}

pub(crate) fn open_span_of_group(cursor: Cursor) -> Span {
    match cursor.entry() {
        Entry::Group(group, _) => group.span_open(),
        _ => cursor.span(),
    }
}

pub(crate) fn close_span_of_group(cursor: Cursor) -> Span {
    match cursor.entry() {
        Entry::Group(group, _) => group.span_close(),
        _ => cursor.span(),
    }
}
<|endoftext|>


<commit_before>use std::io::{File, BufferedReader};
use std::cell::RefCell;

use utils;
use cursor::{Direction, Cursor};

pub struct Buffer<'b> {
    pub file_path: String,
    pub lines: Vec<RefCell<Line>>,

    pub cursor: Cursor<'b>,
}

impl<'b> Buffer<'b> {
    /// Create a new buffer instance
    pub fn new() -> Buffer<'b> {
        Buffer {
            file_path: String::new(),
            lines: Vec::new(),
            cursor: Cursor::new(),
        }
    }

    /// Create a new buffer instance and load the given file
    pub fn new_from_file(path: &Path) -> Buffer<'b> {
        let mut file = BufferedReader::new(File::open(path));
        let lines: Vec<String> = file.lines().map(|x| x.unwrap()).collect();
        let mut buffer = Buffer::new();

        buffer.file_path = path.as_str().unwrap().to_string();

        // for every line in the file we add a corresponding line to the buffer
        for line in lines.iter() {
            let mut data = line.clone();
            // remove \n chars
            data.pop();
            buffer.lines.push(RefCell::new(Line::new(data)));
        }
        buffer.cursor.set_line(Some(&buffer.lines[0]));

        buffer
    }

    /// Draw the contents of the buffer
    ///
    /// Loops over each line in the buffer and draws it to the screen
    pub fn draw_contents(&self) {
        for (index, line) in self.lines.iter().enumerate() {
            let ln = line.borrow();
            utils::draw(index, ln.data.clone());
        }
    }

    pub fn draw_status(&self) {
        let height = utils::get_term_height();
        let cursor = self.cursor.get_position();
        let data = self.file_path.clone();
        let line_count = self.lines.len();
        utils::draw(
            height - 1,
            format!("{}, cursor: {}, term: {}, lines: {}",
                    data, cursor, utils::get_term_stats(), line_count));
    }

    pub fn adjust_cursor(&mut self, dir: Direction) {
        let y = self.cursor.get_linenum();
        match dir {
            Direction::Up    => { self.move_cursor_to(y-1); },
            Direction::Down  => { self.move_cursor_to(y+1); },
            Direction::Right => { self.cursor.move_right(); },
            Direction::Left  => { self.cursor.move_left(); },
        }
    }

    pub fn delete_char(&mut self) {
        let (offset, line_num) = self.cursor.get_position();

        if offset == 0 {
            return self.join_line_with_previous(line_num);
        }

        self.cursor.delete_char()
    }

    pub fn insert_char(&mut self, ch: char) {
        self.cursor.insert_char(ch);
    }

    pub fn insert_line(&mut self) {
        let (offset, mut line_num) = self.cursor.get_position();

        // split the current line at the cursor position
        let bits = &self.split_line();
        {
            // truncate the current line
            let line = &self.get_line_at(line_num);
            line.unwrap().borrow_mut().data.truncate(offset);
        }

        line_num += 1;

        // add new line below current
        utils::clear_line(line_num);
        self.lines.insert(line_num, RefCell::new(Line::new(bits.clone().remove(1).unwrap())));

        // move the cursor down and to the start of the next line
        self.move_cursor_to(line_num);
    }

    /// Join the line identified by `line_num` with the one at `line_num - 1 `.
    fn join_line_with_previous(&mut self, line_num: uint) {
        let mut current_line_data: String;
        let mut prev_line_data: String;
        let line_len: uint;
        {
            let prev_line = self.get_line_at(line_num - 1);
            if prev_line.is_none() {
                return
            }
            prev_line_data = prev_line.unwrap().borrow().data.clone();
            line_len = prev_line_data.len();
        }

        // get current line data
        let current_line = self.cursor.get_line();
        current_line_data = current_line.borrow().data.clone();

        {
            // append current line data to prev line
            // FIXME: this is duplicated above in a different scope...
            let prev_line = self.get_line_at(line_num - 1).unwrap();

            let new_data = format!("{}{}", prev_line_data, current_line_data);
            prev_line.borrow_mut().data = new_data;
        }

        utils::clear_line(line_num);
        self.lines.remove(line_num);
        self.cursor.set_position(line_len, line_num - 1);
    }

    fn split_line(&mut self) -> Vec<String> {
        let (x, _) = self.cursor.get_position();
        let line = self.cursor.get_line();

        let data = line.borrow().data.clone().into_bytes();
        let old_data = data.slice_to(x);
        let new_data = data.slice_from(x);

        vec!(
            String::from_utf8_lossy(old_data).into_string(),
            String::from_utf8_lossy(new_data).into_string(),
        )
    }

    fn get_line_at(&self, line_num: uint) -> Option<&RefCell<Line>> {
        let num_lines = self.lines.len() -1;
        if line_num > num_lines { return None }
        Some(&self.lines[line_num])
    }

    fn move_cursor_to(&mut self, line_num: uint) -> Option<&RefCell<Line>> {
        // get the line identified by line_num
        let num_lines = self.lines.len() -1;
        if line_num > num_lines { return None }
        let line = &self.lines[line_num];

        // set it on the cursor
        self.cursor.set_line(Some(line));
        self.cursor.set_linenum(line_num);

        Some(self.cursor.get_line())
    }

}

pub struct Line {
    pub data: String,
}

impl Line {
    /// Create a new line instance
    pub fn new(data: String) -> Line {
        Line{
            data: data,
        }
    }

    /// Get the length of the current line
    pub fn len(&self) -> uint {
        self.data.len()
    }
}

<commit_msg>Fix cursor movement when pressing enter<commit_after>use std::io::{File, BufferedReader};
use std::cell::RefCell;

use utils;
use cursor::{Direction, Cursor};

pub struct Buffer<'b> {
    pub file_path: String,
    pub lines: Vec<RefCell<Line>>,

    pub cursor: Cursor<'b>,
}

impl<'b> Buffer<'b> {
    /// Create a new buffer instance
    pub fn new() -> Buffer<'b> {
        Buffer {
            file_path: String::new(),
            lines: Vec::new(),
            cursor: Cursor::new(),
        }
    }

    /// Create a new buffer instance and load the given file
    pub fn new_from_file(path: &Path) -> Buffer<'b> {
        let mut file = BufferedReader::new(File::open(path));
        let lines: Vec<String> = file.lines().map(|x| x.unwrap()).collect();
        let mut buffer = Buffer::new();

        buffer.file_path = path.as_str().unwrap().to_string();

        // for every line in the file we add a corresponding line to the buffer
        for line in lines.iter() {
            let mut data = line.clone();
            // remove \n chars
            data.pop();
            buffer.lines.push(RefCell::new(Line::new(data)));
        }
        buffer.cursor.set_line(Some(&buffer.lines[0]));

        buffer
    }

    /// Draw the contents of the buffer
    ///
    /// Loops over each line in the buffer and draws it to the screen
    pub fn draw_contents(&self) {
        for (index, line) in self.lines.iter().enumerate() {
            let ln = line.borrow();
            utils::draw(index, ln.data.clone());
        }
    }

    pub fn draw_status(&self) {
        let height = utils::get_term_height();
        let cursor = self.cursor.get_position();
        let data = self.file_path.clone();
        let line_count = self.lines.len();
        utils::draw(
            height - 1,
            format!("{}, cursor: {}, term: {}, lines: {}",
                    data, cursor, utils::get_term_stats(), line_count));
    }

    pub fn adjust_cursor(&mut self, dir: Direction) {
        let y = self.cursor.get_linenum();
        match dir {
            Direction::Up    => { self.move_cursor_to(y-1); },
            Direction::Down  => { self.move_cursor_to(y+1); },
            Direction::Right => { self.cursor.move_right(); },
            Direction::Left  => { self.cursor.move_left(); },
        }
    }

    pub fn delete_char(&mut self) {
        let (offset, line_num) = self.cursor.get_position();

        if offset == 0 {
            return self.join_line_with_previous(line_num);
        }

        self.cursor.delete_char()
    }

    pub fn insert_char(&mut self, ch: char) {
        self.cursor.insert_char(ch);
    }

    pub fn insert_line(&mut self) {
        let (offset, mut line_num) = self.cursor.get_position();

        // split the current line at the cursor position
        let bits = &self.split_line();
        {
            // truncate the current line
            let line = &self.get_line_at(line_num);
            line.unwrap().borrow_mut().data.truncate(offset);
        }

        line_num += 1;

        // add new line below current
        utils::clear_line(line_num);
        self.lines.insert(line_num, RefCell::new(Line::new(bits.clone().remove(1).unwrap())));

        // move the cursor down and to the start of the next line
        self.move_cursor_to(line_num);
        self.cursor.set_offset(0);
    }

    /// Join the line identified by `line_num` with the one at `line_num - 1 `.
    fn join_line_with_previous(&mut self, line_num: uint) {
        let mut current_line_data: String;
        let mut prev_line_data: String;
        let line_len: uint;
        {
            let prev_line = self.get_line_at(line_num - 1);
            if prev_line.is_none() {
                return
            }
            prev_line_data = prev_line.unwrap().borrow().data.clone();
            line_len = prev_line_data.len();
        }

        // get current line data
        let current_line = self.cursor.get_line();
        current_line_data = current_line.borrow().data.clone();

        {
            // append current line data to prev line
            // FIXME: this is duplicated above in a different scope...
            let prev_line = self.get_line_at(line_num - 1).unwrap();

            let new_data = format!("{}{}", prev_line_data, current_line_data);
            prev_line.borrow_mut().data = new_data;
        }

        utils::clear_line(line_num);
        self.lines.remove(line_num);
        self.cursor.set_position(line_len, line_num - 1);
    }

    fn split_line(&mut self) -> Vec<String> {
        let (x, _) = self.cursor.get_position();
        let line = self.cursor.get_line();

        let data = line.borrow().data.clone().into_bytes();
        let old_data = data.slice_to(x);
        let new_data = data.slice_from(x);

        vec!(
            String::from_utf8_lossy(old_data).into_string(),
            String::from_utf8_lossy(new_data).into_string(),
        )
    }

    fn get_line_at(&self, line_num: uint) -> Option<&RefCell<Line>> {
        let num_lines = self.lines.len() -1;
        if line_num > num_lines { return None }
        Some(&self.lines[line_num])
    }

    fn move_cursor_to(&mut self, line_num: uint) -> Option<&RefCell<Line>> {
        // get the line identified by line_num
        let num_lines = self.lines.len() -1;
        if line_num > num_lines { return None }
        let line = &self.lines[line_num];

        // set it on the cursor
        self.cursor.set_line(Some(line));
        self.cursor.set_linenum(line_num);

        Some(self.cursor.get_line())
    }

}

pub struct Line {
    pub data: String,
}

impl Line {
    /// Create a new line instance
    pub fn new(data: String) -> Line {
        Line{
            data: data,
        }
    }

    /// Get the length of the current line
    pub fn len(&self) -> uint {
        self.data.len()
    }
}

<|endoftext|>


<commit_before>use std::net::TcpStream;
use openssl::ssl::{SslContext, SslStream};
use std::io::{Error, ErrorKind, Read, Result, Write};
use regex::Regex;

enum IMAPStreamTypes {
	Basic(TcpStream),
	Ssl(SslStream<TcpStream>)
}

pub struct IMAPStream {
	stream: IMAPStreamTypes,
	pub host: String,
	pub port: u16,
	tag: u32,
	tag_prefix: &'static str
}

pub struct IMAPMailbox {
	pub flags: String,
	pub exists: u32,
	pub recent: u32,
	pub unseen: Option<u32>,
	pub permanent_flags: Option<String>,
	pub uid_next: Option<u32>,
	pub uid_validity: Option<u32>
}

impl IMAPStream {

	pub fn connect<S: Into<String>>(host: S, port: u16, ssl_context: Option<SslContext>) -> Result<IMAPStream> {
                let host_string = host.into();
		let connect_string = format!("{}:{}", host_string, port);
		let tcp_stream = TcpStream::connect(&*connect_string).unwrap();
		let mut socket = match ssl_context {
			Some(context) => IMAPStream { stream: IMAPStreamTypes::Ssl(SslStream::connect(&context, tcp_stream).unwrap()), host: host_string, port: port, tag: 1, tag_prefix: "a"},
			None => IMAPStream { stream: IMAPStreamTypes::Basic(tcp_stream), host: host_string, port: port, tag: 1, tag_prefix: "a"},
		};

		match socket.read_greeting() {
			Ok(_) => (),
			Err(_) => return Err(Error::new(ErrorKind::Other, "Failed to read greet response"))
		}

		Ok(socket)
	}

	//LOGIN
	pub fn login(&mut self, username: & str, password: & str) -> Result<()> {
		self.run_command_and_check_ok(&format!("LOGIN {} {}", username, password).to_string())
	}

	//SELECT
	pub fn select(&mut self, mailbox_name: &str) -> Result<IMAPMailbox> {
		match self.run_command(&format!("SELECT {}", mailbox_name).to_string()) {
			Ok(lines) => IMAPStream::parse_select_or_examine(lines),
			Err(e) => Err(e)
		}
	}

	fn parse_select_or_examine(lines: Vec<String>) -> Result<IMAPMailbox> {
		let exists_regex = match Regex::new(r"^\* (\d+) EXISTS\r\n") {
    		Ok(re) => re,
    		Err(err) => panic!("{}", err),
		};

		let recent_regex = match Regex::new(r"^\* (\d+) RECENT\r\n") {
    		Ok(re) => re,
    		Err(err) => panic!("{}", err),
		};

		let flags_regex = match Regex::new(r"^\* FLAGS (.+)\r\n") {
    		Ok(re) => re,
    		Err(err) => panic!("{}", err),
		};

		let unseen_regex = match Regex::new(r"^OK \[UNSEEN (\d+)\](.*)\r\n") {
    		Ok(re) => re,
    		Err(err) => panic!("{}", err),
		};

		let uid_validity_regex = match Regex::new(r"^OK \[UIDVALIDITY (\d+)\](.*)\r\n") {
    		Ok(re) => re,
    		Err(err) => panic!("{}", err),
		};

		let uid_next_regex = match Regex::new(r"^OK \[UIDNEXT (\d+)\](.*)\r\n") {
    		Ok(re) => re,
    		Err(err) => panic!("{}", err),
		};

		let permanent_flags_regex = match Regex::new(r"^OK \[PERMANENTFLAGS (.+)\]\r\n") {
    		Ok(re) => re,
    		Err(err) => panic!("{}", err),
		};

		//Check Ok
		match IMAPStream::parse_response_ok(lines.clone()) {
			Ok(_) => (),
			Err(e) => return Err(e)
		};

		let mut mailbox = IMAPMailbox{
			flags: "".to_string(),
			exists: 0,
			recent: 0,
			unseen: None,
			permanent_flags: None,
			uid_next: None,
			uid_validity: None
		};

		for line in lines.iter() {
			if exists_regex.is_match(line) {
				let cap = exists_regex.captures(line).unwrap();
				mailbox.exists = cap.at(1).unwrap().parse::<u32>().unwrap();
			} else if recent_regex.is_match(line) {
				let cap = recent_regex.captures(line).unwrap();
				mailbox.recent = cap.at(1).unwrap().parse::<u32>().unwrap();
			} else if flags_regex.is_match(line) {
				let cap = flags_regex.captures(line).unwrap();
				mailbox.flags = cap.at(1).unwrap().to_string();
			} else if unseen_regex.is_match(line) {
				let cap = unseen_regex.captures(line).unwrap();
				mailbox.unseen = Some(cap.at(1).unwrap().parse::<u32>().unwrap());
			} else if uid_validity_regex.is_match(line) {
				let cap = uid_validity_regex.captures(line).unwrap();
				mailbox.uid_validity = Some(cap.at(1).unwrap().parse::<u32>().unwrap());
			} else if uid_next_regex.is_match(line) {
				let cap = uid_next_regex.captures(line).unwrap();
				mailbox.uid_next = Some(cap.at(1).unwrap().parse::<u32>().unwrap());
			} else if permanent_flags_regex.is_match(line) {
				let cap = permanent_flags_regex.captures(line).unwrap();
				mailbox.permanent_flags = Some(cap.at(1).unwrap().to_string());
			}
		}

		return Ok(mailbox);
	}

	//EXAMINE
	pub fn examine(&mut self, mailbox_name: &str) -> Result<IMAPMailbox> {
		match self.run_command(&format!("EXAMINE {}", mailbox_name).to_string()) {
			Ok(lines) => IMAPStream::parse_select_or_examine(lines),
			Err(e) => Err(e)
		}
	}

	//FETCH
	pub fn fetch(&mut self, sequence_set: &str, query: &str) -> Result<Vec<String>> {
		self.run_command(&format!("FETCH {} {}", sequence_set, query).to_string())
	}

	//NOOP
	pub fn noop(&mut self) -> Result<()> {
		self.run_command_and_check_ok("NOOP")
	}

	//LOGOUT
	pub fn logout(&mut self) -> Result<()> {
		self.run_command_and_check_ok("LOGOUT")
	}

	//CREATE
	pub fn create(&mut self, mailbox_name: &str) -> Result<()> {
		self.run_command_and_check_ok(&format!("CREATE {}", mailbox_name).to_string())
	}

	//DELETE
	pub fn delete(&mut self, mailbox_name: &str) -> Result<()> {
		self.run_command_and_check_ok(&format!("DELETE {}", mailbox_name).to_string())
	}

	//RENAME
	pub fn rename(&mut self, current_mailbox_name: &str, new_mailbox_name: &str) -> Result<()> {
		self.run_command_and_check_ok(&format!("RENAME {} {}", current_mailbox_name, new_mailbox_name).to_string())
	}

	//SUBSCRIBE
	pub fn subscribe(&mut self, mailbox: &str) -> Result<()> {
		self.run_command_and_check_ok(&format!("SUBSCRIBE {}", mailbox).to_string())
	}

	//UNSUBSCRIBE
	pub fn unsubscribe(&mut self, mailbox: &str) -> Result<()> {
		self.run_command_and_check_ok(&format!("UNSUBSCRIBE {}", mailbox).to_string())
	}

	//CAPABILITY
	pub fn capability(&mut self) -> Result<Vec<String>> {
		match self.run_command(&format!("CAPABILITY").to_string()) {
			Ok(lines) => IMAPStream::parse_capability(lines),
			Err(e) => Err(e)
		}
	}

	fn parse_capability(lines: Vec<String>) -> Result<Vec<String>> {
		let capability_regex = match Regex::new(r"^\* CAPABILITY (.*)\r\n") {
    		Ok(re) => re,
    		Err(err) => panic!("{}", err),
		};

		//Check Ok
		match IMAPStream::parse_response_ok(lines.clone()) {
			Ok(_) => (),
			Err(e) => return Err(e)
		};

		for line in lines.iter() {
			if capability_regex.is_match(line) {
				let cap = capability_regex.captures(line).unwrap();
				let capabilities_str = cap.at(1).unwrap();
				return Ok(capabilities_str.split(' ').map(|x| x.to_string()).collect());
			}
		}

		Err(Error::new(ErrorKind::Other, "Error parsing capabilities response"))
	}

	//COPY
	pub fn copy(&mut self, sequence_set: &str, mailbox_name: &str) -> Result<()> {
		self.run_command_and_check_ok(&format!("COPY {} {}", sequence_set, mailbox_name).to_string())
	}

	pub fn run_command_and_check_ok(&mut self, command: &str) -> Result<()> {
		match self.run_command(command) {
			Ok(lines) => IMAPStream::parse_response_ok(lines),
			Err(e) => Err(e)
		}
	}

	pub fn run_command(&mut self, untagged_command: &str) -> Result<Vec<String>> {
		let command = self.create_command(untagged_command.to_string());

		match self.write_str(&*command) {
			Ok(_) => (),
			Err(_) => return Err(Error::new(ErrorKind::Other, "Failed to write")),
		};

		let ret = match self.read_response() {
			Ok(lines) => Ok(lines),
			Err(_) => Err(Error::new(ErrorKind::Other, "Failed to read")),
		};

		self.tag += 1;

		return ret;
	}

	fn parse_response_ok(lines: Vec<String>) -> Result<()> {
		let ok_regex = match Regex::new(r"^([a-zA-Z0-9]+) ([a-zA-Z0-9]+)(.*)") {
    		Ok(re) => re,
    		Err(err) => panic!("{}", err),
		};
		let last_line = lines.last().unwrap();

		for cap in ok_regex.captures_iter(last_line) {
			let response_type = cap.at(2).unwrap_or("");
			if response_type == "OK" {
				return Ok(());
			}
		}

		return Err(Error::new(ErrorKind::Other, format!("Invalid Response: {}", last_line).to_string()));
	}

	fn write_str(&mut self, s: &str) -> Result<()> {
		match self.stream {
			IMAPStreamTypes::Ssl(ref mut stream) => stream.write_fmt(format_args!("{}", s)),
			IMAPStreamTypes::Basic(ref mut stream) => stream.write_fmt(format_args!("{}", s)),
		}
	}

	fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
		match self.stream {
			IMAPStreamTypes::Ssl(ref mut stream) => stream.read(buf),
			IMAPStreamTypes::Basic(ref mut stream) => stream.read(buf),
		}
	}

	fn read_response(&mut self) -> Result<Vec<String>> {
		//Carriage return
		let cr = 0x0d;
		//Line Feed
		let lf = 0x0a;
		let mut found_tag_line = false;
		let start_str = format!("a{} ", self.tag);
		let mut lines: Vec<String> = Vec::new();

		while !found_tag_line {
			let mut line_buffer: Vec<u8> = Vec::new();
			while line_buffer.len() < 2 || (line_buffer[line_buffer.len()-1] != lf && line_buffer[line_buffer.len()-2] != cr) {
					let byte_buffer: &mut [u8] = &mut [0];
					match self.read(byte_buffer) {
						Ok(_) => {},
						Err(_) => return Err(Error::new(ErrorKind::Other, "Failed to read the response")),
					}
					line_buffer.push(byte_buffer[0]);
			}

			let line = String::from_utf8(line_buffer).unwrap();

			lines.push(line.clone());

			if (&*line).starts_with(&*start_str) {
				found_tag_line = true;
			}
		}

		Ok(lines)
	}

	fn read_greeting(&mut self) -> Result<()> {
		//Carriage return
		let cr = 0x0d;
		//Line Feed
		let lf = 0x0a;

		let mut line_buffer: Vec<u8> = Vec::new();
		while line_buffer.len() < 2 || (line_buffer[line_buffer.len()-1] != lf && line_buffer[line_buffer.len()-2] != cr) {
				let byte_buffer: &mut [u8] = &mut [0];
				match self.read(byte_buffer) {
					Ok(_) => {},
					Err(_) => return Err(Error::new(ErrorKind::Other, "Failed to read the response")),
				}
				line_buffer.push(byte_buffer[0]);
		}

		Ok(())
	}

	fn create_command(&mut self, command: String) -> String {
		let command = format!("{}{} {}\r\n", self.tag_prefix, self.tag, command);
		return command;
	}
}
<commit_msg>Try connection instead of unwrapping<commit_after>use std::net::TcpStream;
use openssl::ssl::{SslContext, SslStream};
use std::io::{Error, ErrorKind, Read, Result, Write};
use regex::Regex;

enum IMAPStreamTypes {
	Basic(TcpStream),
	Ssl(SslStream<TcpStream>)
}

pub struct IMAPStream {
	stream: IMAPStreamTypes,
	pub host: String,
	pub port: u16,
	tag: u32,
	tag_prefix: &'static str
}

pub struct IMAPMailbox {
	pub flags: String,
	pub exists: u32,
	pub recent: u32,
	pub unseen: Option<u32>,
	pub permanent_flags: Option<String>,
	pub uid_next: Option<u32>,
	pub uid_validity: Option<u32>
}

impl IMAPStream {

	pub fn connect<S: Into<String>>(host: S, port: u16, ssl_context: Option<SslContext>) -> Result<IMAPStream> {
                let host_string = host.into();
		let connect_string = format!("{}:{}", host_string, port);
		let tcp_stream = try!(TcpStream::connect(&*connect_string));
		let mut socket = match ssl_context {
			Some(context) => IMAPStream { stream: IMAPStreamTypes::Ssl(SslStream::connect(&context, tcp_stream).unwrap()), host: host_string, port: port, tag: 1, tag_prefix: "a"},
			None => IMAPStream { stream: IMAPStreamTypes::Basic(tcp_stream), host: host_string, port: port, tag: 1, tag_prefix: "a"},
		};

		match socket.read_greeting() {
			Ok(_) => (),
			Err(_) => return Err(Error::new(ErrorKind::Other, "Failed to read greet response"))
		}

		Ok(socket)
	}

	//LOGIN
	pub fn login(&mut self, username: & str, password: & str) -> Result<()> {
		self.run_command_and_check_ok(&format!("LOGIN {} {}", username, password).to_string())
	}

	//SELECT
	pub fn select(&mut self, mailbox_name: &str) -> Result<IMAPMailbox> {
		match self.run_command(&format!("SELECT {}", mailbox_name).to_string()) {
			Ok(lines) => IMAPStream::parse_select_or_examine(lines),
			Err(e) => Err(e)
		}
	}

	fn parse_select_or_examine(lines: Vec<String>) -> Result<IMAPMailbox> {
		let exists_regex = match Regex::new(r"^\* (\d+) EXISTS\r\n") {
    		Ok(re) => re,
    		Err(err) => panic!("{}", err),
		};

		let recent_regex = match Regex::new(r"^\* (\d+) RECENT\r\n") {
    		Ok(re) => re,
    		Err(err) => panic!("{}", err),
		};

		let flags_regex = match Regex::new(r"^\* FLAGS (.+)\r\n") {
    		Ok(re) => re,
    		Err(err) => panic!("{}", err),
		};

		let unseen_regex = match Regex::new(r"^OK \[UNSEEN (\d+)\](.*)\r\n") {
    		Ok(re) => re,
    		Err(err) => panic!("{}", err),
		};

		let uid_validity_regex = match Regex::new(r"^OK \[UIDVALIDITY (\d+)\](.*)\r\n") {
    		Ok(re) => re,
    		Err(err) => panic!("{}", err),
		};

		let uid_next_regex = match Regex::new(r"^OK \[UIDNEXT (\d+)\](.*)\r\n") {
    		Ok(re) => re,
    		Err(err) => panic!("{}", err),
		};

		let permanent_flags_regex = match Regex::new(r"^OK \[PERMANENTFLAGS (.+)\]\r\n") {
    		Ok(re) => re,
    		Err(err) => panic!("{}", err),
		};

		//Check Ok
		match IMAPStream::parse_response_ok(lines.clone()) {
			Ok(_) => (),
			Err(e) => return Err(e)
		};

		let mut mailbox = IMAPMailbox{
			flags: "".to_string(),
			exists: 0,
			recent: 0,
			unseen: None,
			permanent_flags: None,
			uid_next: None,
			uid_validity: None
		};

		for line in lines.iter() {
			if exists_regex.is_match(line) {
				let cap = exists_regex.captures(line).unwrap();
				mailbox.exists = cap.at(1).unwrap().parse::<u32>().unwrap();
			} else if recent_regex.is_match(line) {
				let cap = recent_regex.captures(line).unwrap();
				mailbox.recent = cap.at(1).unwrap().parse::<u32>().unwrap();
			} else if flags_regex.is_match(line) {
				let cap = flags_regex.captures(line).unwrap();
				mailbox.flags = cap.at(1).unwrap().to_string();
			} else if unseen_regex.is_match(line) {
				let cap = unseen_regex.captures(line).unwrap();
				mailbox.unseen = Some(cap.at(1).unwrap().parse::<u32>().unwrap());
			} else if uid_validity_regex.is_match(line) {
				let cap = uid_validity_regex.captures(line).unwrap();
				mailbox.uid_validity = Some(cap.at(1).unwrap().parse::<u32>().unwrap());
			} else if uid_next_regex.is_match(line) {
				let cap = uid_next_regex.captures(line).unwrap();
				mailbox.uid_next = Some(cap.at(1).unwrap().parse::<u32>().unwrap());
			} else if permanent_flags_regex.is_match(line) {
				let cap = permanent_flags_regex.captures(line).unwrap();
				mailbox.permanent_flags = Some(cap.at(1).unwrap().to_string());
			}
		}

		return Ok(mailbox);
	}

	//EXAMINE
	pub fn examine(&mut self, mailbox_name: &str) -> Result<IMAPMailbox> {
		match self.run_command(&format!("EXAMINE {}", mailbox_name).to_string()) {
			Ok(lines) => IMAPStream::parse_select_or_examine(lines),
			Err(e) => Err(e)
		}
	}

	//FETCH
	pub fn fetch(&mut self, sequence_set: &str, query: &str) -> Result<Vec<String>> {
		self.run_command(&format!("FETCH {} {}", sequence_set, query).to_string())
	}

	//NOOP
	pub fn noop(&mut self) -> Result<()> {
		self.run_command_and_check_ok("NOOP")
	}

	//LOGOUT
	pub fn logout(&mut self) -> Result<()> {
		self.run_command_and_check_ok("LOGOUT")
	}

	//CREATE
	pub fn create(&mut self, mailbox_name: &str) -> Result<()> {
		self.run_command_and_check_ok(&format!("CREATE {}", mailbox_name).to_string())
	}

	//DELETE
	pub fn delete(&mut self, mailbox_name: &str) -> Result<()> {
		self.run_command_and_check_ok(&format!("DELETE {}", mailbox_name).to_string())
	}

	//RENAME
	pub fn rename(&mut self, current_mailbox_name: &str, new_mailbox_name: &str) -> Result<()> {
		self.run_command_and_check_ok(&format!("RENAME {} {}", current_mailbox_name, new_mailbox_name).to_string())
	}

	//SUBSCRIBE
	pub fn subscribe(&mut self, mailbox: &str) -> Result<()> {
		self.run_command_and_check_ok(&format!("SUBSCRIBE {}", mailbox).to_string())
	}

	//UNSUBSCRIBE
	pub fn unsubscribe(&mut self, mailbox: &str) -> Result<()> {
		self.run_command_and_check_ok(&format!("UNSUBSCRIBE {}", mailbox).to_string())
	}

	//CAPABILITY
	pub fn capability(&mut self) -> Result<Vec<String>> {
		match self.run_command(&format!("CAPABILITY").to_string()) {
			Ok(lines) => IMAPStream::parse_capability(lines),
			Err(e) => Err(e)
		}
	}

	fn parse_capability(lines: Vec<String>) -> Result<Vec<String>> {
		let capability_regex = match Regex::new(r"^\* CAPABILITY (.*)\r\n") {
    		Ok(re) => re,
    		Err(err) => panic!("{}", err),
		};

		//Check Ok
		match IMAPStream::parse_response_ok(lines.clone()) {
			Ok(_) => (),
			Err(e) => return Err(e)
		};

		for line in lines.iter() {
			if capability_regex.is_match(line) {
				let cap = capability_regex.captures(line).unwrap();
				let capabilities_str = cap.at(1).unwrap();
				return Ok(capabilities_str.split(' ').map(|x| x.to_string()).collect());
			}
		}

		Err(Error::new(ErrorKind::Other, "Error parsing capabilities response"))
	}

	//COPY
	pub fn copy(&mut self, sequence_set: &str, mailbox_name: &str) -> Result<()> {
		self.run_command_and_check_ok(&format!("COPY {} {}", sequence_set, mailbox_name).to_string())
	}

	pub fn run_command_and_check_ok(&mut self, command: &str) -> Result<()> {
		match self.run_command(command) {
			Ok(lines) => IMAPStream::parse_response_ok(lines),
			Err(e) => Err(e)
		}
	}

	pub fn run_command(&mut self, untagged_command: &str) -> Result<Vec<String>> {
		let command = self.create_command(untagged_command.to_string());

		match self.write_str(&*command) {
			Ok(_) => (),
			Err(_) => return Err(Error::new(ErrorKind::Other, "Failed to write")),
		};

		let ret = match self.read_response() {
			Ok(lines) => Ok(lines),
			Err(_) => Err(Error::new(ErrorKind::Other, "Failed to read")),
		};

		self.tag += 1;

		return ret;
	}

	fn parse_response_ok(lines: Vec<String>) -> Result<()> {
		let ok_regex = match Regex::new(r"^([a-zA-Z0-9]+) ([a-zA-Z0-9]+)(.*)") {
    		Ok(re) => re,
    		Err(err) => panic!("{}", err),
		};
		let last_line = lines.last().unwrap();

		for cap in ok_regex.captures_iter(last_line) {
			let response_type = cap.at(2).unwrap_or("");
			if response_type == "OK" {
				return Ok(());
			}
		}

		return Err(Error::new(ErrorKind::Other, format!("Invalid Response: {}", last_line).to_string()));
	}

	fn write_str(&mut self, s: &str) -> Result<()> {
		match self.stream {
			IMAPStreamTypes::Ssl(ref mut stream) => stream.write_fmt(format_args!("{}", s)),
			IMAPStreamTypes::Basic(ref mut stream) => stream.write_fmt(format_args!("{}", s)),
		}
	}

	fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
		match self.stream {
			IMAPStreamTypes::Ssl(ref mut stream) => stream.read(buf),
			IMAPStreamTypes::Basic(ref mut stream) => stream.read(buf),
		}
	}

	fn read_response(&mut self) -> Result<Vec<String>> {
		//Carriage return
		let cr = 0x0d;
		//Line Feed
		let lf = 0x0a;
		let mut found_tag_line = false;
		let start_str = format!("a{} ", self.tag);
		let mut lines: Vec<String> = Vec::new();

		while !found_tag_line {
			let mut line_buffer: Vec<u8> = Vec::new();
			while line_buffer.len() < 2 || (line_buffer[line_buffer.len()-1] != lf && line_buffer[line_buffer.len()-2] != cr) {
					let byte_buffer: &mut [u8] = &mut [0];
					match self.read(byte_buffer) {
						Ok(_) => {},
						Err(_) => return Err(Error::new(ErrorKind::Other, "Failed to read the response")),
					}
					line_buffer.push(byte_buffer[0]);
			}

			let line = String::from_utf8(line_buffer).unwrap();

			lines.push(line.clone());

			if (&*line).starts_with(&*start_str) {
				found_tag_line = true;
			}
		}

		Ok(lines)
	}

	fn read_greeting(&mut self) -> Result<()> {
		//Carriage return
		let cr = 0x0d;
		//Line Feed
		let lf = 0x0a;

		let mut line_buffer: Vec<u8> = Vec::new();
		while line_buffer.len() < 2 || (line_buffer[line_buffer.len()-1] != lf && line_buffer[line_buffer.len()-2] != cr) {
				let byte_buffer: &mut [u8] = &mut [0];
				match self.read(byte_buffer) {
					Ok(_) => {},
					Err(_) => return Err(Error::new(ErrorKind::Other, "Failed to read the response")),
				}
				line_buffer.push(byte_buffer[0]);
		}

		Ok(())
	}

	fn create_command(&mut self, command: String) -> String {
		let command = format!("{}{} {}\r\n", self.tag_prefix, self.tag, command);
		return command;
	}
}

#[test]
fn connect() {
    let imap = IMAPStream::connect("this-is-not-an-imap-server", 143, None);
    assert!(imap.is_err());
}
<|endoftext|>