<commit_before>// Copyright 2013 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.

/*!

This modules provides bindings to the local event loop's TTY interface, using it
to have synchronous, but non-blocking versions of stdio. These handles can be
inspected for information about terminal dimensions or related information
about the stream or terminal that it is attached to.

# Example

```rust
use std::rt::io;

let mut out = io::stdout();
out.write(bytes!("Hello, world!"));
```

*/

use fmt;
use libc;
use option::{Option, Some, None};
use result::{Ok, Err};
use rt::io::buffered::{LineBufferedWriter, BufferedWriter};
use rt::rtio::{IoFactory, RtioTTY, RtioFileStream, with_local_io,
               CloseAsynchronously};
use super::{Reader, Writer, io_error, IoError, OtherIoError};

// And so begins the tale of acquiring a uv handle to a stdio stream on all
// platforms in all situations. Our story begins by splitting the world into two
// categories, windows and unix. Then one day the creators of unix said let
// there be redirection! And henceforth there was redirection away from the
// console for standard I/O streams.
//
// After this day, the world split into four factions:
//
// 1. Unix with stdout on a terminal.
// 2. Unix with stdout redirected.
// 3. Windows with stdout on a terminal.
// 4. Windows with stdout redirected.
//
// Many years passed, and then one day the nation of libuv decided to unify this
// world. After months of toiling, uv created three ideas: TTY, Pipe, File.
// These three ideas propagated throughout the lands and the four great factions
// decided to settle among them.
//
// The groups of 1, 2, and 3 all worked very hard towards the idea of TTY. Upon
// doing so, they even enhanced themselves further then their Pipe/File
// brethren, becoming the dominant powers.
//
// The group of 4, however, decided to work independently. They abandoned the
// common TTY belief throughout, and even abandoned the fledgling Pipe belief.
// The members of the 4th faction decided to only align themselves with File.
//
// tl;dr; TTY works on everything but when windows stdout is redirected, in that
//        case pipe also doesn't work, but magically file does!
enum StdSource {
    TTY(~RtioTTY),
    File(~RtioFileStream),
}

#[fixed_stack_segment] #[inline(never)]
fn src<T>(fd: libc::c_int, readable: bool, f: &fn(StdSource) -> T) -> T {
    do with_local_io |io| {
        let fd = unsafe { libc::dup(fd) };
        match io.tty_open(fd, readable) {
            Ok(tty) => Some(f(TTY(tty))),
            Err(_) => {
                // It's not really that desirable if these handles are closed
                // synchronously, and because they're squirreled away in a task
                // structure the destructors will be run when the task is
                // attempted to get destroyed. This means that if we run a
                // synchronous destructor we'll attempt to do some scheduling
                // operations which will just result in sadness.
                Some(f(File(io.fs_from_raw_fd(fd, CloseAsynchronously))))
            }
        }
    }.unwrap()
}

/// Creates a new non-blocking handle to the stdin of the current process.
///
/// See `stdout()` for notes about this function.
#[fixed_stack_segment] #[inline(never)]
pub fn stdin() -> StdReader {
    do src(libc::STDIN_FILENO, true) |src| { StdReader { inner: src } }
}

/// Creates a new non-blocking handle to the stdout of the current process.
///
/// Note that this is a fairly expensive operation in that at least one memory
/// allocation is performed. Additionally, this must be called from a runtime
/// task context because the stream returned will be a non-blocking object using
/// the local scheduler to perform the I/O.
pub fn stdout() -> StdWriter {
    do src(libc::STDOUT_FILENO, false) |src| { StdWriter { inner: src } }
}

/// Creates a new non-blocking handle to the stderr of the current process.
///
/// See `stdout()` for notes about this function.
pub fn stderr() -> StdWriter {
    do src(libc::STDERR_FILENO, false) |src| { StdWriter { inner: src } }
}

/// Executes a closure with the local task's handle on stdout. By default, this
/// stream is a buffering stream, so the handled yielded to the given closure
/// can be used to flush the stdout stream (if necessary). The buffering used is
/// line-buffering when stdout is attached to a terminal, and a fixed sized
/// buffer if it is not attached to a terminal.
///
/// Note that handles generated via the `stdout()` function all output to the
/// same stream, and output among all task may be interleaved as a result of
/// this. This is provided to have access to the default stream for `print` and
/// `println` (and the related macros) for this task.
///
/// Also note that logging macros do not use this stream. Using the logging
/// macros will emit output to stderr.
pub fn with_task_stdout(f: &fn(&mut Writer)) {
    use rt::local::Local;
    use rt::task::Task;

    unsafe {
        // Logging may require scheduling operations, so we can't remove the
        // task from TLS right now, hence the unsafe borrow. Sad.
        let task: *mut Task = Local::unsafe_borrow();

        match (*task).stdout_handle {
            Some(ref mut handle) => f(*handle),
            None => {
                let handle = stdout();
                let mut handle = if handle.isatty() {
                    ~LineBufferedWriter::new(handle) as ~Writer
                } else {
                    // The default capacity is very large, 64k, but this is just
                    // a stdout stream, and possibly per task, so let's not make
                    // this too expensive.
                    ~BufferedWriter::with_capacity(4096, handle) as ~Writer
                };
                f(handle);
                (*task).stdout_handle = Some(handle);
            }
        }
    }
}

/// Prints a string to the stdout of the current process. No newline is emitted
/// after the string is printed.
pub fn print(s: &str) {
    do with_task_stdout |io| {
        io.write(s.as_bytes());
    }
}

/// Prints a string as a line. to the stdout of the current process. A literal
/// `\n` character is printed to the console after the string.
pub fn println(s: &str) {
    do with_task_stdout |io| {
        io.write(s.as_bytes());
        io.write(['\n' as u8]);
    }
}

/// Similar to `print`, but takes a `fmt::Arguments` structure to be compatible
/// with the `format_args!` macro.
pub fn print_args(fmt: &fmt::Arguments) {
    do with_task_stdout |io| {
        fmt::write(io, fmt);
    }
}

/// Similar to `println`, but takes a `fmt::Arguments` structure to be
/// compatible with the `format_args!` macro.
pub fn println_args(fmt: &fmt::Arguments) {
    do with_task_stdout |io| {
        fmt::writeln(io, fmt);
    }
}

/// Representation of a reader of a standard input stream
pub struct StdReader {
    priv inner: StdSource
}

impl Reader for StdReader {
    fn read(&mut self, buf: &mut [u8]) -> Option<uint> {
        let ret = match self.inner {
            TTY(ref mut tty) => tty.read(buf),
            File(ref mut file) => file.read(buf).map_move(|i| i as uint),
        };
        match ret {
            Ok(amt) => Some(amt as uint),
            Err(e) => {
                io_error::cond.raise(e);
                None
            }
        }
    }

    fn eof(&mut self) -> bool { false }
}

/// Representation of a writer to a standard output stream
pub struct StdWriter {
    priv inner: StdSource
}

impl StdWriter {
    /// Gets the size of this output window, if possible. This is typically used
    /// when the writer is attached to something like a terminal, this is used
    /// to fetch the dimensions of the terminal.
    ///
    /// If successful, returns Some((width, height)).
    ///
    /// # Failure
    ///
    /// This function will raise on the `io_error` condition if an error
    /// happens.
    pub fn winsize(&mut self) -> Option<(int, int)> {
        match self.inner {
            TTY(ref mut tty) => {
                match tty.get_winsize() {
                    Ok(p) => Some(p),
                    Err(e) => {
                        io_error::cond.raise(e);
                        None
                    }
                }
            }
            File(*) => {
                io_error::cond.raise(IoError {
                    kind: OtherIoError,
                    desc: "stream is not a tty",
                    detail: None,
                });
                None
            }
        }
    }

    /// Controls whether this output stream is a "raw stream" or simply a normal
    /// stream.
    ///
    /// # Failure
    ///
    /// This function will raise on the `io_error` condition if an error
    /// happens.
    pub fn set_raw(&mut self, raw: bool) {
        match self.inner {
            TTY(ref mut tty) => {
                match tty.set_raw(raw) {
                    Ok(()) => {},
                    Err(e) => io_error::cond.raise(e),
                }
            }
            File(*) => {
                io_error::cond.raise(IoError {
                    kind: OtherIoError,
                    desc: "stream is not a tty",
                    detail: None,
                });
            }
        }
    }

    /// Returns whether this tream is attached to a TTY instance or not.
    ///
    /// This is similar to libc's isatty() function
    pub fn isatty(&self) -> bool {
        match self.inner {
            TTY(ref tty) => tty.isatty(),
            File(*) => false,
        }
    }
}

impl Writer for StdWriter {
    fn write(&mut self, buf: &[u8]) {
        let ret = match self.inner {
            TTY(ref mut tty) => tty.write(buf),
            File(ref mut file) => file.write(buf),
        };
        match ret {
            Ok(()) => {}
            Err(e) => io_error::cond.raise(e)
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn smoke() {
        // Just make sure we can acquire handles
        stdin();
        stdout();
        stderr();
    }
}
<commit_msg>auto merge of #10218 : alexcrichton/rust/stdio-flush-safe, r=cmr<commit_after>// Copyright 2013 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.

/*!

This modules provides bindings to the local event loop's TTY interface, using it
to have synchronous, but non-blocking versions of stdio. These handles can be
inspected for information about terminal dimensions or related information
about the stream or terminal that it is attached to.

# Example

```rust
use std::rt::io;

let mut out = io::stdout();
out.write(bytes!("Hello, world!"));
```

*/

use fmt;
use libc;
use option::{Option, Some, None};
use result::{Ok, Err};
use rt::io::buffered::{LineBufferedWriter, BufferedWriter};
use rt::rtio::{IoFactory, RtioTTY, RtioFileStream, with_local_io,
               CloseAsynchronously};
use super::{Reader, Writer, io_error, IoError, OtherIoError};

// And so begins the tale of acquiring a uv handle to a stdio stream on all
// platforms in all situations. Our story begins by splitting the world into two
// categories, windows and unix. Then one day the creators of unix said let
// there be redirection! And henceforth there was redirection away from the
// console for standard I/O streams.
//
// After this day, the world split into four factions:
//
// 1. Unix with stdout on a terminal.
// 2. Unix with stdout redirected.
// 3. Windows with stdout on a terminal.
// 4. Windows with stdout redirected.
//
// Many years passed, and then one day the nation of libuv decided to unify this
// world. After months of toiling, uv created three ideas: TTY, Pipe, File.
// These three ideas propagated throughout the lands and the four great factions
// decided to settle among them.
//
// The groups of 1, 2, and 3 all worked very hard towards the idea of TTY. Upon
// doing so, they even enhanced themselves further then their Pipe/File
// brethren, becoming the dominant powers.
//
// The group of 4, however, decided to work independently. They abandoned the
// common TTY belief throughout, and even abandoned the fledgling Pipe belief.
// The members of the 4th faction decided to only align themselves with File.
//
// tl;dr; TTY works on everything but when windows stdout is redirected, in that
//        case pipe also doesn't work, but magically file does!
enum StdSource {
    TTY(~RtioTTY),
    File(~RtioFileStream),
}

#[fixed_stack_segment] #[inline(never)]
fn src<T>(fd: libc::c_int, readable: bool, f: &fn(StdSource) -> T) -> T {
    do with_local_io |io| {
        let fd = unsafe { libc::dup(fd) };
        match io.tty_open(fd, readable) {
            Ok(tty) => Some(f(TTY(tty))),
            Err(_) => {
                // It's not really that desirable if these handles are closed
                // synchronously, and because they're squirreled away in a task
                // structure the destructors will be run when the task is
                // attempted to get destroyed. This means that if we run a
                // synchronous destructor we'll attempt to do some scheduling
                // operations which will just result in sadness.
                Some(f(File(io.fs_from_raw_fd(fd, CloseAsynchronously))))
            }
        }
    }.unwrap()
}

/// Creates a new non-blocking handle to the stdin of the current process.
///
/// See `stdout()` for notes about this function.
#[fixed_stack_segment] #[inline(never)]
pub fn stdin() -> StdReader {
    do src(libc::STDIN_FILENO, true) |src| { StdReader { inner: src } }
}

/// Creates a new non-blocking handle to the stdout of the current process.
///
/// Note that this is a fairly expensive operation in that at least one memory
/// allocation is performed. Additionally, this must be called from a runtime
/// task context because the stream returned will be a non-blocking object using
/// the local scheduler to perform the I/O.
pub fn stdout() -> StdWriter {
    do src(libc::STDOUT_FILENO, false) |src| { StdWriter { inner: src } }
}

/// Creates a new non-blocking handle to the stderr of the current process.
///
/// See `stdout()` for notes about this function.
pub fn stderr() -> StdWriter {
    do src(libc::STDERR_FILENO, false) |src| { StdWriter { inner: src } }
}

// Helper to access the local task's stdout handle
//
// Note that this is not a safe function to expose because you can create an
// aliased pointer very easily:
//
//  do with_task_stdout |io1| {
//      do with_task_stdout |io2| {
//          // io1 aliases io2
//      }
//  }
fn with_task_stdout(f: &fn(&mut Writer)) {
    use rt::local::Local;
    use rt::task::Task;

    unsafe {
        // Logging may require scheduling operations, so we can't remove the
        // task from TLS right now, hence the unsafe borrow. Sad.
        let task: *mut Task = Local::unsafe_borrow();

        match (*task).stdout_handle {
            Some(ref mut handle) => f(*handle),
            None => {
                let handle = stdout();
                let mut handle = if handle.isatty() {
                    ~LineBufferedWriter::new(handle) as ~Writer
                } else {
                    // The default capacity is very large, 64k, but this is just
                    // a stdout stream, and possibly per task, so let's not make
                    // this too expensive.
                    ~BufferedWriter::with_capacity(4096, handle) as ~Writer
                };
                f(handle);
                (*task).stdout_handle = Some(handle);
            }
        }
    }
}

/// Flushes the local task's stdout handle.
///
/// By default, this stream is a buffering stream, flushing may be necessary to
/// ensure output is on the terminal screen. The buffering used is
/// line-buffering when stdout is attached to a terminal, and a fixed sized
/// buffer if it is not attached to a terminal.
///
/// Note that logging macros do not use this stream. Using the logging macros
/// will emit output to stderr, and while they are line buffered the log
/// messages are always terminated in a newline (no need to flush).
pub fn flush() {
    do with_task_stdout |io| {
        io.flush();
    }
}

/// Prints a string to the stdout of the current process. No newline is emitted
/// after the string is printed.
pub fn print(s: &str) {
    do with_task_stdout |io| {
        io.write(s.as_bytes());
    }
}

/// Prints a string as a line. to the stdout of the current process. A literal
/// `\n` character is printed to the console after the string.
pub fn println(s: &str) {
    do with_task_stdout |io| {
        io.write(s.as_bytes());
        io.write(['\n' as u8]);
    }
}

/// Similar to `print`, but takes a `fmt::Arguments` structure to be compatible
/// with the `format_args!` macro.
pub fn print_args(fmt: &fmt::Arguments) {
    do with_task_stdout |io| {
        fmt::write(io, fmt);
    }
}

/// Similar to `println`, but takes a `fmt::Arguments` structure to be
/// compatible with the `format_args!` macro.
pub fn println_args(fmt: &fmt::Arguments) {
    do with_task_stdout |io| {
        fmt::writeln(io, fmt);
    }
}

/// Representation of a reader of a standard input stream
pub struct StdReader {
    priv inner: StdSource
}

impl Reader for StdReader {
    fn read(&mut self, buf: &mut [u8]) -> Option<uint> {
        let ret = match self.inner {
            TTY(ref mut tty) => tty.read(buf),
            File(ref mut file) => file.read(buf).map_move(|i| i as uint),
        };
        match ret {
            Ok(amt) => Some(amt as uint),
            Err(e) => {
                io_error::cond.raise(e);
                None
            }
        }
    }

    fn eof(&mut self) -> bool { false }
}

/// Representation of a writer to a standard output stream
pub struct StdWriter {
    priv inner: StdSource
}

impl StdWriter {
    /// Gets the size of this output window, if possible. This is typically used
    /// when the writer is attached to something like a terminal, this is used
    /// to fetch the dimensions of the terminal.
    ///
    /// If successful, returns Some((width, height)).
    ///
    /// # Failure
    ///
    /// This function will raise on the `io_error` condition if an error
    /// happens.
    pub fn winsize(&mut self) -> Option<(int, int)> {
        match self.inner {
            TTY(ref mut tty) => {
                match tty.get_winsize() {
                    Ok(p) => Some(p),
                    Err(e) => {
                        io_error::cond.raise(e);
                        None
                    }
                }
            }
            File(*) => {
                io_error::cond.raise(IoError {
                    kind: OtherIoError,
                    desc: "stream is not a tty",
                    detail: None,
                });
                None
            }
        }
    }

    /// Controls whether this output stream is a "raw stream" or simply a normal
    /// stream.
    ///
    /// # Failure
    ///
    /// This function will raise on the `io_error` condition if an error
    /// happens.
    pub fn set_raw(&mut self, raw: bool) {
        match self.inner {
            TTY(ref mut tty) => {
                match tty.set_raw(raw) {
                    Ok(()) => {},
                    Err(e) => io_error::cond.raise(e),
                }
            }
            File(*) => {
                io_error::cond.raise(IoError {
                    kind: OtherIoError,
                    desc: "stream is not a tty",
                    detail: None,
                });
            }
        }
    }

    /// Returns whether this tream is attached to a TTY instance or not.
    ///
    /// This is similar to libc's isatty() function
    pub fn isatty(&self) -> bool {
        match self.inner {
            TTY(ref tty) => tty.isatty(),
            File(*) => false,
        }
    }
}

impl Writer for StdWriter {
    fn write(&mut self, buf: &[u8]) {
        let ret = match self.inner {
            TTY(ref mut tty) => tty.write(buf),
            File(ref mut file) => file.write(buf),
        };
        match ret {
            Ok(()) => {}
            Err(e) => io_error::cond.raise(e)
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn smoke() {
        // Just make sure we can acquire handles
        stdin();
        stdout();
        stderr();
    }
}
<|endoftext|>


<commit_before>// Copyright 2019 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

//! Simplified tempfile which doesn't depend on the `rand` crate.
//!
//! # Example
//!
//! ```
//! use std::io::Result;
//! use std::path::{Path, PathBuf};
//! use tempfile::TempDir;
//!
//! fn main() -> Result<()> {
//!     let t = TempDir::new()?;
//!     assert!(t.path().exists());
//!
//!     Ok(())
//! }
//! ```

use libc::mkdtemp;
use std::env;
use std::ffi::CString;
use std::fs;
use std::io::{Error, ErrorKind, Result};
use std::mem::ManuallyDrop;
use std::path::{Path, PathBuf};
use std::ptr;

pub struct Builder {
    prefix: String,
}

// Note: we implement a builder because the protoc-rust crate uses this API from
// crates.io's tempfile. Our code mostly uses TempDir::new directly.
impl Builder {
    pub fn new() -> Self {
        Builder {
            prefix: ".tmp".to_owned(),
        }
    }

    /// Set a custom filename prefix.
    ///
    /// Default: `.tmp`
    pub fn prefix(&mut self, prefix: &str) -> &mut Self {
        self.prefix = prefix.to_owned();
        self
    }

    /// Creates a new temporary directory under libc's preferred system
    /// temporary directory. The new directory will be removed when the returned
    /// handle of type `TempDir` is dropped.
    pub fn tempdir(&self) -> Result<TempDir> {
        // mkdtemp() requires the template to end in 6 X chars, which will be replaced
        // with random characters to make the path unique.
        let path_template = env::temp_dir().join(format!("{}.XXXXXX", self.prefix));
        let template = match path_template.to_str() {
            Some(s) => CString::new(s)?,
            None => {
                return Err(Error::new(
                    ErrorKind::InvalidData,
                    "Path to string conversion failed",
                ))
            }
        };
        let ptr = template.into_raw();
        // Safe because ownership of the buffer is handed off to mkdtemp() only
        // until it returns, and ownership is reclaimed by calling CString::from_raw()
        // on the same pointer returned by into_raw().
        let path = unsafe {
            let ret = mkdtemp(ptr);
            let path = CString::from_raw(ptr);
            if ret.is_null() {
                return Err(Error::last_os_error());
            }
            path
        };
        Ok(TempDir {
            path: PathBuf::from(path.to_str().map_err(|_| {
                Error::new(ErrorKind::InvalidData, "Path to string conversion failed")
            })?),
        })
    }
}

impl Default for Builder {
    fn default() -> Self {
        Self::new()
    }
}

/// Temporary directory. The directory will be removed when this object is
/// dropped.
pub struct TempDir {
    path: PathBuf,
    // When adding new fields to TempDir: note that anything with a Drop impl
    // will need to be dropped explicitly via ptr::read inside TempDir::remove
    // or else it gets leaked (memory safe but not ideal).
}

impl TempDir {
    pub fn new() -> Result<Self> {
        Builder::new().tempdir()
    }

    /// Accesses the tempdir's [`Path`].
    ///
    /// [`Path`]: http://doc.rust-lang.org/std/path/struct.Path.html
    pub fn path(&self) -> &Path {
        self.path.as_ref()
    }

    /// Removes the temporary directory.
    ///
    /// Calling this is optional as dropping a TempDir object will also remove
    /// the directory. Calling remove explicitly allows for any resulting error
    /// to be handled.
    pub fn remove(self) -> Result<()> {
        // Place self inside ManuallyDrop so its Drop impl doesn't run, but nor
        // does the path inside get dropped. Then use ptr::read to take out the
        // PathBuf so that it *does* get dropped correctly at the bottom of this
        // function.
        let dont_drop = ManuallyDrop::new(self);
        let path: PathBuf = unsafe { ptr::read(&dont_drop.path) };

        fs::remove_dir_all(path)
    }
}

impl Drop for TempDir {
    fn drop(&mut self) {
        let _ = fs::remove_dir_all(&self.path);
    }
}

#[cfg(test)]
mod tests {
    use crate::TempDir;

    #[test]
    fn create_dir() {
        let t = TempDir::new().unwrap();
        let path = t.path();
        assert!(path.exists());
        assert!(path.is_dir());
    }

    #[test]
    fn remove_dir() {
        let t = TempDir::new().unwrap();
        let path = t.path().to_owned();
        assert!(t.remove().is_ok());
        assert!(!path.exists());
    }
}
<commit_msg>tempfile: add tempfile() and NamedTempFile<commit_after>// Copyright 2019 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

//! Simplified tempfile which doesn't depend on the `rand` crate.
//!
//! # Example
//!
//! ```
//! use std::io::Result;
//! use std::path::{Path, PathBuf};
//! use tempfile::TempDir;
//!
//! fn main() -> Result<()> {
//!     let t = TempDir::new()?;
//!     assert!(t.path().exists());
//!
//!     Ok(())
//! }
//! ```

use libc::{mkdtemp, mkstemp};
use std::env;
use std::ffi::CString;
use std::fs::{self, File};
use std::io::{Error, ErrorKind, Result};
use std::mem::ManuallyDrop;
use std::os::unix::io::FromRawFd;
use std::path::{Path, PathBuf};
use std::ptr;

fn temp_path_template(prefix: &str) -> Result<CString> {
    // mkdtemp()/mkstemp() require the template to end in 6 X chars, which will be replaced
    // with random characters to make the path unique.
    let path_template = env::temp_dir().join(format!("{}.XXXXXX", prefix));
    match path_template.to_str() {
        Some(s) => Ok(CString::new(s)?),
        None => Err(Error::new(
            ErrorKind::InvalidData,
            "Path to string conversion failed",
        )),
    }
}

pub struct Builder {
    prefix: String,
}

// Note: we implement a builder because the protoc-rust crate uses this API from
// crates.io's tempfile. Our code mostly uses TempDir::new directly.
impl Builder {
    pub fn new() -> Self {
        Builder {
            prefix: ".tmp".to_owned(),
        }
    }

    /// Set a custom filename prefix.
    ///
    /// Default: `.tmp`
    pub fn prefix(&mut self, prefix: &str) -> &mut Self {
        self.prefix = prefix.to_owned();
        self
    }

    /// Creates a new temporary directory under libc's preferred system
    /// temporary directory. The new directory will be removed when the returned
    /// handle of type `TempDir` is dropped.
    pub fn tempdir(&self) -> Result<TempDir> {
        let template = temp_path_template(&self.prefix)?;
        let ptr = template.into_raw();
        // Safe because ownership of the buffer is handed off to mkdtemp() only
        // until it returns, and ownership is reclaimed by calling CString::from_raw()
        // on the same pointer returned by into_raw().
        let path = unsafe {
            let ret = mkdtemp(ptr);
            let path = CString::from_raw(ptr);
            if ret.is_null() {
                return Err(Error::last_os_error());
            }
            path
        };
        Ok(TempDir {
            path: PathBuf::from(path.to_str().map_err(|_| {
                Error::new(ErrorKind::InvalidData, "Path to string conversion failed")
            })?),
        })
    }

    /// Creates a new temporary file under libc's preferred system
    /// temporary directory. The new file will be removed when the returned
    /// handle of type `NamedTempFile` is dropped.
    pub fn tempfile(&self) -> Result<NamedTempFile> {
        let template = temp_path_template(&self.prefix)?;
        let ptr = template.into_raw();
        // Safe because ownership of the buffer is handed off to mkstemp() only
        // until it returns, and ownership is reclaimed by calling CString::from_raw()
        // on the same pointer returned by into_raw().
        let (file, path) = unsafe {
            let ret = mkstemp(ptr);
            let path = CString::from_raw(ptr);
            if ret < 0 {
                return Err(Error::last_os_error());
            }
            (File::from_raw_fd(ret), path)
        };

        Ok(NamedTempFile {
            path: TempPath {
                path: PathBuf::from(path.to_str().map_err(|_| {
                    Error::new(ErrorKind::InvalidData, "Path to string conversion failed")
                })?),
            },
            file,
        })
    }
}

impl Default for Builder {
    fn default() -> Self {
        Self::new()
    }
}

/// Temporary directory. The directory will be removed when this object is
/// dropped.
pub struct TempDir {
    path: PathBuf,
    // When adding new fields to TempDir: note that anything with a Drop impl
    // will need to be dropped explicitly via ptr::read inside TempDir::remove
    // or else it gets leaked (memory safe but not ideal).
}

impl TempDir {
    pub fn new() -> Result<Self> {
        Builder::new().tempdir()
    }

    /// Accesses the tempdir's [`Path`].
    ///
    /// [`Path`]: http://doc.rust-lang.org/std/path/struct.Path.html
    pub fn path(&self) -> &Path {
        self.path.as_ref()
    }

    /// Removes the temporary directory.
    ///
    /// Calling this is optional as dropping a TempDir object will also remove
    /// the directory. Calling remove explicitly allows for any resulting error
    /// to be handled.
    pub fn remove(self) -> Result<()> {
        // Place self inside ManuallyDrop so its Drop impl doesn't run, but nor
        // does the path inside get dropped. Then use ptr::read to take out the
        // PathBuf so that it *does* get dropped correctly at the bottom of this
        // function.
        let dont_drop = ManuallyDrop::new(self);
        let path: PathBuf = unsafe { ptr::read(&dont_drop.path) };

        fs::remove_dir_all(path)
    }
}

impl Drop for TempDir {
    fn drop(&mut self) {
        let _ = fs::remove_dir_all(&self.path);
    }
}

/// Temporary file with a known name.  The file will be removed when this object is dropped.
pub struct NamedTempFile {
    path: TempPath,
    file: File,
}

impl NamedTempFile {
    pub fn new() -> Result<Self> {
        Builder::new().tempfile()
    }

    /// Accesses the temporary file's `Path`.
    pub fn path(&self) -> &Path {
        self.path.path.as_ref()
    }

    /// Accesses the temporary file's `File` object.
    pub fn as_file(&self) -> &File {
        &self.file
    }

    /// Accesses the temporary file's `File` object mutably.
    pub fn as_file_mut(&mut self) -> &mut File {
        &mut self.file
    }

    /// Convert this `TempFile` into an open `File` and unlink it from the filesystem.
    pub fn into_file(self) -> File {
        self.file
    }
}

// Container for NamedTempFile's path so that it can be dropped separately from the File.
struct TempPath {
    path: PathBuf,
}

impl Drop for TempPath {
    fn drop(&mut self) {
        let _ = fs::remove_file(&self.path);
    }
}

/// Create a new anonymous temporary file under the preferred system
/// temporary directory. The new file will be removed when the returned
/// `File` is dropped.
pub fn tempfile() -> Result<File> {
    Ok(NamedTempFile::new()?.into_file())
}

#[cfg(test)]
mod tests {
    use std::io::{Read, Seek, SeekFrom, Write};

    use crate::{tempfile, NamedTempFile, TempDir};

    #[test]
    fn create_dir() {
        let t = TempDir::new().unwrap();
        let path = t.path();
        assert!(path.exists());
        assert!(path.is_dir());
    }

    #[test]
    fn remove_dir() {
        let t = TempDir::new().unwrap();
        let path = t.path().to_owned();
        assert!(t.remove().is_ok());
        assert!(!path.exists());
    }

    #[test]
    fn create_file() {
        let mut f = tempfile().expect("tempfile() failed");
        f.write_all(&[0, 1, 2, 3]).unwrap();
        f.seek(SeekFrom::Start(0)).unwrap();
        let mut data = vec![0u8; 4];
        f.read_exact(&mut data).unwrap();
        assert_eq!(data, [0, 1, 2, 3]);
    }

    #[test]
    fn create_named_file() {
        let named_temp = NamedTempFile::new().unwrap();
        let path = named_temp.path().to_owned();
        assert!(path.exists());

        // as_file() should not delete the file.
        let _f = named_temp.as_file();
        assert!(path.exists());

        // Dropping the NamedTempFile should delete the file.
        drop(named_temp);
        assert!(!path.exists());
    }
}
<|endoftext|>


<commit_before>pub fn classify(num: u64) -> Option<Classification> {
    if num == 0 {
        return None;
    }
    let sum: u64 = (1..num).filter(|i| num % i == 0).sum();
    match sum.cmp(&num) {
        std::cmp::Ordering::Equal => Some(Classification::Perfect),
        std::cmp::Ordering::Less => Some(Classification::Deficient),
        std::cmp::Ordering::Greater => Some(Classification::Abundant),
    }
}

#[derive(Debug, PartialEq, Eq)]
pub enum Classification {
    Abundant,
    Perfect,
    Deficient,
}
<commit_msg>perfect-numbers: extract Some<commit_after>pub fn classify(num: u64) -> Option<Classification> {
    if num == 0 {
        return None;
    }
    let sum: u64 = (1..num).filter(|i| num % i == 0).sum();
    Some(match sum.cmp(&num) {
        std::cmp::Ordering::Equal => Classification::Perfect,
        std::cmp::Ordering::Less => Classification::Deficient,
        std::cmp::Ordering::Greater => Classification::Abundant,
    })
}

#[derive(Debug, PartialEq, Eq)]
pub enum Classification {
    Abundant,
    Perfect,
    Deficient,
}
<|endoftext|>


<commit_before>extern crate futures;
extern crate ldap3;
extern crate tokio_core;

use std::io;
use std::result::Result;

use futures::{Future, Stream};
use ldap3::{LdapConnAsync, LdapResult, Scope};
use tokio_core::reactor::Core;

const ENTRIES_BEFORE_ABANDON: usize = 1;

fn main() {
    match do_abandon() {
        Ok(r) => println!("{:?}", r),
        Err(e) => println!("{:?}", e),
    }
}

fn do_abandon() -> Result<LdapResult, io::Error> {
    let mut core = Core::new()?;
    let handle = core.handle();
    let ldap = LdapConnAsync::new("ldap://localhost:2389", &handle)?;
    let srch = ldap
        .and_then(|ldap| {
            ldap.search(
                "ou=Places,dc=example,dc=org",
                Scope::Subtree,
                "objectClass=locality",
                vec!["l"]
        )})
        .and_then(|(mut strm, rx)| {
            let mut count = 0;
            let a_chan = strm.get_abandon_channel();
            a_chan.and_then(move |a_chan| {
                rx.map_err(|_e| io::Error::from(io::ErrorKind::Other))
                    .join(strm.for_each(move |_tag| {
                        if count == ENTRIES_BEFORE_ABANDON {
                            a_chan.send(())
                                .map_err(|_e| io::Error::new(io::ErrorKind::Other, "a_chan send"))
                        } else {
                            count += 1;
                            Ok(())
                        }
                    }))
            })
        })
        .map(|((res, _), _)| res);
    core.run(srch)
}
<commit_msg>Use new async return type in example<commit_after>extern crate futures;
extern crate ldap3;
extern crate tokio_core;

use std::io;
use std::result::Result;

use futures::{Future, Stream};
use ldap3::{LdapConnAsync, LdapResult, Scope};
use tokio_core::reactor::Core;

const ENTRIES_BEFORE_ABANDON: usize = 1;

fn main() {
    match do_abandon() {
        Ok(r) => println!("{:?}", r),
        Err(e) => println!("{:?}", e),
    }
}

fn do_abandon() -> Result<LdapResult, io::Error> {
    let mut core = Core::new()?;
    let handle = core.handle();
    let ldap = LdapConnAsync::new("ldap://localhost:2389", &handle)?;
    let srch = ldap
        .and_then(|ldap| {
            ldap.search(
                "ou=Places,dc=example,dc=org",
                Scope::Subtree,
                "objectClass=locality",
                vec!["l"]
        )})
        .and_then(|mut strm| {
            let mut count = 0;
            let rx = strm.get_result_rx().expect("rx");
            let a_chan = strm.get_abandon_channel();
            a_chan.and_then(move |a_chan| {
                rx.map_err(|_e| io::Error::from(io::ErrorKind::Other))
                    .join(strm.for_each(move |_tag| {
                        if count == ENTRIES_BEFORE_ABANDON {
                            a_chan.send(())
                                .map_err(|_e| io::Error::new(io::ErrorKind::Other, "a_chan send"))
                        } else {
                            count += 1;
                            Ok(())
                        }
                    }))
            })
        })
        .map(|(res, _)| res);
    core.run(srch)
}
<|endoftext|>


<commit_before>use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::higher;
use clippy_utils::method_chain_args;
use clippy_utils::source::snippet_with_applicability;
use clippy_utils::ty::is_type_diagnostic_item;
use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir::{Expr, ExprKind, PatKind, QPath};
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::sym;

declare_clippy_lint! {
    /// ### What it does
    /// Checks for unnecessary `ok()` in `while let`.
    ///
    /// ### Why is this bad?
    /// Calling `ok()` in `while let` is unnecessary, instead match
    /// on `Ok(pat)`
    ///
    /// ### Example
    /// ```ignore
    /// while let Some(value) = iter.next().ok() {
    ///     vec.push(value)
    /// }
    ///
    /// if let Some(valie) = iter.next().ok() {
    ///     vec.push(value)
    /// }
    /// ```
    /// Use instead:
    /// ```ignore
    /// while let Ok(value) = iter.next() {
    ///     vec.push(value)
    /// }
    ///
    /// if let Ok(value) = iter.next() {
    ///        vec.push_value)
    /// }
    /// ```
    pub MATCH_RESULT_OK,
    style,
    "usage of `ok()` in `let Some(pat)` statements is unnecessary, match on `Ok(pat)` instead"
}

declare_lint_pass!(MatchResultOk => [MATCH_RESULT_OK]);

impl<'tcx> LateLintPass<'tcx> for MatchResultOk {
    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
        let (let_pat, let_expr, ifwhile) =
            if let Some(higher::IfLet { let_pat, let_expr, .. }) = higher::IfLet::hir(cx, expr) {
                (let_pat, let_expr, "if")
            } else if let Some(higher::WhileLet { let_pat, let_expr, .. }) = higher::WhileLet::hir(expr) {
                (let_pat, let_expr, "while")
            } else {
                return;
            };

        if_chain! {
            if let ExprKind::MethodCall(_, ok_span, [ref result_types_0, ..], _) = let_expr.kind; //check is expr.ok() has type Result<T,E>.ok(, _)
            if let PatKind::TupleStruct(QPath::Resolved(_, x), y, _)  = let_pat.kind; //get operation
            if method_chain_args(let_expr, &["ok"]).is_some(); //test to see if using ok() methoduse std::marker::Sized;
            if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(result_types_0), sym::Result);
            if rustc_hir_pretty::to_string(rustc_hir_pretty::NO_ANN, |s| s.print_path(x, false)) == "Some";

            then {

                let mut applicability = Applicability::MachineApplicable;
                let some_expr_string = snippet_with_applicability(cx, y[0].span, "", &mut applicability);
                let trimmed_ok = snippet_with_applicability(cx, let_expr.span.until(ok_span), "", &mut applicability);
                let sugg = format!(
                    "{} let Ok({}) = {}",
                    ifwhile,
                    some_expr_string,
                    trimmed_ok.trim().trim_end_matches('.'),
                );
                span_lint_and_sugg(
                    cx,
                    MATCH_RESULT_OK,
                    expr.span.with_hi(let_expr.span.hi()),
                    "matching on `Some` with `ok()` is redundant",
                    &format!("consider matching on `Ok({})` and removing the call to `ok` instead", some_expr_string),
                    sugg,
                    applicability,
                );
            }
        }
    }
}
<commit_msg>Fix typo in example for `match_result_ok`<commit_after>use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::higher;
use clippy_utils::method_chain_args;
use clippy_utils::source::snippet_with_applicability;
use clippy_utils::ty::is_type_diagnostic_item;
use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir::{Expr, ExprKind, PatKind, QPath};
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::sym;

declare_clippy_lint! {
    /// ### What it does
    /// Checks for unnecessary `ok()` in `while let`.
    ///
    /// ### Why is this bad?
    /// Calling `ok()` in `while let` is unnecessary, instead match
    /// on `Ok(pat)`
    ///
    /// ### Example
    /// ```ignore
    /// while let Some(value) = iter.next().ok() {
    ///     vec.push(value)
    /// }
    ///
    /// if let Some(valie) = iter.next().ok() {
    ///     vec.push(value)
    /// }
    /// ```
    /// Use instead:
    /// ```ignore
    /// while let Ok(value) = iter.next() {
    ///     vec.push(value)
    /// }
    ///
    /// if let Ok(value) = iter.next() {
    ///        vec.push(value)
    /// }
    /// ```
    pub MATCH_RESULT_OK,
    style,
    "usage of `ok()` in `let Some(pat)` statements is unnecessary, match on `Ok(pat)` instead"
}

declare_lint_pass!(MatchResultOk => [MATCH_RESULT_OK]);

impl<'tcx> LateLintPass<'tcx> for MatchResultOk {
    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
        let (let_pat, let_expr, ifwhile) =
            if let Some(higher::IfLet { let_pat, let_expr, .. }) = higher::IfLet::hir(cx, expr) {
                (let_pat, let_expr, "if")
            } else if let Some(higher::WhileLet { let_pat, let_expr, .. }) = higher::WhileLet::hir(expr) {
                (let_pat, let_expr, "while")
            } else {
                return;
            };

        if_chain! {
            if let ExprKind::MethodCall(_, ok_span, [ref result_types_0, ..], _) = let_expr.kind; //check is expr.ok() has type Result<T,E>.ok(, _)
            if let PatKind::TupleStruct(QPath::Resolved(_, x), y, _)  = let_pat.kind; //get operation
            if method_chain_args(let_expr, &["ok"]).is_some(); //test to see if using ok() methoduse std::marker::Sized;
            if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(result_types_0), sym::Result);
            if rustc_hir_pretty::to_string(rustc_hir_pretty::NO_ANN, |s| s.print_path(x, false)) == "Some";

            then {

                let mut applicability = Applicability::MachineApplicable;
                let some_expr_string = snippet_with_applicability(cx, y[0].span, "", &mut applicability);
                let trimmed_ok = snippet_with_applicability(cx, let_expr.span.until(ok_span), "", &mut applicability);
                let sugg = format!(
                    "{} let Ok({}) = {}",
                    ifwhile,
                    some_expr_string,
                    trimmed_ok.trim().trim_end_matches('.'),
                );
                span_lint_and_sugg(
                    cx,
                    MATCH_RESULT_OK,
                    expr.span.with_hi(let_expr.span.hi()),
                    "matching on `Some` with `ok()` is redundant",
                    &format!("consider matching on `Ok({})` and removing the call to `ok` instead", some_expr_string),
                    sugg,
                    applicability,
                );
            }
        }
    }
}
<|endoftext|>


<commit_before>use super::{Parser, PathStyle};
use rustc_ast as ast;
use rustc_ast::attr;
use rustc_ast::token::{self, Nonterminal};
use rustc_ast_pretty::pprust;
use rustc_errors::{error_code, PResult};
use rustc_span::{sym, Span};

use tracing::debug;

#[derive(Debug)]
pub(super) enum InnerAttrPolicy<'a> {
    Permitted,
    Forbidden { reason: &'a str, saw_doc_comment: bool, prev_attr_sp: Option<Span> },
}

const DEFAULT_UNEXPECTED_INNER_ATTR_ERR_MSG: &str = "an inner attribute is not \
                                                     permitted in this context";

pub(super) const DEFAULT_INNER_ATTR_FORBIDDEN: InnerAttrPolicy<'_> = InnerAttrPolicy::Forbidden {
    reason: DEFAULT_UNEXPECTED_INNER_ATTR_ERR_MSG,
    saw_doc_comment: false,
    prev_attr_sp: None,
};

impl<'a> Parser<'a> {
    /// Parses attributes that appear before an item.
    pub(super) fn parse_outer_attributes(&mut self) -> PResult<'a, Vec<ast::Attribute>> {
        let mut attrs: Vec<ast::Attribute> = Vec::new();
        let mut just_parsed_doc_comment = false;
        loop {
            debug!("parse_outer_attributes: self.token={:?}", self.token);
            let attr = if self.check(&token::Pound) {
                let inner_error_reason = if just_parsed_doc_comment {
                    "an inner attribute is not permitted following an outer doc comment"
                } else if !attrs.is_empty() {
                    "an inner attribute is not permitted following an outer attribute"
                } else {
                    DEFAULT_UNEXPECTED_INNER_ATTR_ERR_MSG
                };
                let inner_parse_policy = InnerAttrPolicy::Forbidden {
                    reason: inner_error_reason,
                    saw_doc_comment: just_parsed_doc_comment,
                    prev_attr_sp: attrs.last().map(|a| a.span),
                };
                just_parsed_doc_comment = false;
                Some(self.parse_attribute(inner_parse_policy)?)
            } else if let token::DocComment(comment_kind, attr_style, data) = self.token.kind {
                if attr_style != ast::AttrStyle::Outer {
                    self.sess
                        .span_diagnostic
                        .struct_span_err_with_code(
                            self.token.span,
                            "expected outer doc comment",
                            error_code!(E0753),
                        )
                        .note(
                            "inner doc comments like this (starting with \
                         `//!` or `/*!`) can only appear before items",
                        )
                        .emit();
                }
                self.bump();
                just_parsed_doc_comment = true;
                Some(attr::mk_doc_comment(comment_kind, attr_style, data, self.prev_token.span))
            } else {
                None
            };

            if let Some(attr) = attr {
                attrs.push(attr);
            } else {
                break;
            }
        }
        Ok(attrs)
    }

    /// Matches `attribute = # ! [ meta_item ]`.
    /// `inner_parse_policy` prescribes how to handle inner attributes.
    fn parse_attribute(
        &mut self,
        inner_parse_policy: InnerAttrPolicy<'_>,
    ) -> PResult<'a, ast::Attribute> {
        debug!(
            "parse_attribute: inner_parse_policy={:?} self.token={:?}",
            inner_parse_policy, self.token
        );
        let lo = self.token.span;
        let ((item, style, span), tokens) = self.collect_tokens(|this| {
            if this.eat(&token::Pound) {
                let style = if this.eat(&token::Not) {
                    ast::AttrStyle::Inner
                } else {
                    ast::AttrStyle::Outer
                };

                this.expect(&token::OpenDelim(token::Bracket))?;
                let item = this.parse_attr_item(false)?;
                this.expect(&token::CloseDelim(token::Bracket))?;
                let attr_sp = lo.to(this.prev_token.span);

                // Emit error if inner attribute is encountered and forbidden.
                if style == ast::AttrStyle::Inner {
                    this.error_on_forbidden_inner_attr(attr_sp, inner_parse_policy);
                }

                Ok((item, style, attr_sp))
            } else {
                let token_str = pprust::token_to_string(&this.token);
                let msg = &format!("expected `#`, found `{}`", token_str);
                Err(this.struct_span_err(this.token.span, msg))
            }
        })?;

        Ok(attr::mk_attr_from_item(item, tokens, style, span))
    }

    pub(super) fn error_on_forbidden_inner_attr(&self, attr_sp: Span, policy: InnerAttrPolicy<'_>) {
        if let InnerAttrPolicy::Forbidden { reason, saw_doc_comment, prev_attr_sp } = policy {
            let prev_attr_note =
                if saw_doc_comment { "previous doc comment" } else { "previous outer attribute" };

            let mut diag = self.struct_span_err(attr_sp, reason);

            if let Some(prev_attr_sp) = prev_attr_sp {
                diag.span_label(attr_sp, "not permitted following an outer attribute")
                    .span_label(prev_attr_sp, prev_attr_note);
            }

            diag.note(
                "inner attributes, like `#![no_std]`, annotate the item enclosing them, \
                and are usually found at the beginning of source files. \
                Outer attributes, like `#[test]`, annotate the item following them.",
            )
            .emit();
        }
    }

    /// Parses an inner part of an attribute (the path and following tokens).
    /// The tokens must be either a delimited token stream, or empty token stream,
    /// or the "legacy" key-value form.
    ///     PATH `(` TOKEN_STREAM `)`
    ///     PATH `[` TOKEN_STREAM `]`
    ///     PATH `{` TOKEN_STREAM `}`
    ///     PATH
    ///     PATH `=` UNSUFFIXED_LIT
    /// The delimiters or `=` are still put into the resulting token stream.
    pub fn parse_attr_item(&mut self, capture_tokens: bool) -> PResult<'a, ast::AttrItem> {
        let item = match self.token.kind {
            token::Interpolated(ref nt) => match **nt {
                Nonterminal::NtMeta(ref item) => Some(item.clone().into_inner()),
                _ => None,
            },
            _ => None,
        };
        Ok(if let Some(item) = item {
            self.bump();
            item
        } else {
            let do_parse = |this: &mut Self| {
                let path = this.parse_path(PathStyle::Mod)?;
                let args = this.parse_attr_args()?;
                Ok(ast::AttrItem { path, args, tokens: None })
            };
            if capture_tokens {
                let (mut item, tokens) = self.collect_tokens(do_parse)?;
                item.tokens = tokens;
                item
            } else {
                do_parse(self)?
            }
        })
    }

    /// Parses attributes that appear after the opening of an item. These should
    /// be preceded by an exclamation mark, but we accept and warn about one
    /// terminated by a semicolon.
    ///
    /// Matches `inner_attrs*`.
    crate fn parse_inner_attributes(&mut self) -> PResult<'a, Vec<ast::Attribute>> {
        let mut attrs: Vec<ast::Attribute> = vec![];
        loop {
            // Only try to parse if it is an inner attribute (has `!`).
            let attr = if self.check(&token::Pound) && self.look_ahead(1, |t| t == &token::Not) {
                Some(self.parse_attribute(InnerAttrPolicy::Permitted)?)
            } else if let token::DocComment(comment_kind, attr_style, data) = self.token.kind {
                if attr_style == ast::AttrStyle::Inner {
                    self.bump();
                    Some(attr::mk_doc_comment(comment_kind, attr_style, data, self.prev_token.span))
                } else {
                    None
                }
            } else {
                None
            };
            if let Some(attr) = attr {
                attrs.push(attr);
            } else {
                break;
            }
        }
        Ok(attrs)
    }

    crate fn parse_unsuffixed_lit(&mut self) -> PResult<'a, ast::Lit> {
        let lit = self.parse_lit()?;
        debug!("checking if {:?} is unusuffixed", lit);

        if !lit.kind.is_unsuffixed() {
            self.struct_span_err(lit.span, "suffixed literals are not allowed in attributes")
                .help(
                    "instead of using a suffixed literal (`1u8`, `1.0f32`, etc.), \
                    use an unsuffixed version (`1`, `1.0`, etc.)",
                )
                .emit();
        }

        Ok(lit)
    }

    /// Parses `cfg_attr(pred, attr_item_list)` where `attr_item_list` is comma-delimited.
    pub fn parse_cfg_attr(&mut self) -> PResult<'a, (ast::MetaItem, Vec<(ast::AttrItem, Span)>)> {
        let cfg_predicate = self.parse_meta_item()?;
        self.expect(&token::Comma)?;

        // Presumably, the majority of the time there will only be one attr.
        let mut expanded_attrs = Vec::with_capacity(1);
        while self.token.kind != token::Eof {
            let lo = self.token.span;
            let item = self.parse_attr_item(true)?;
            expanded_attrs.push((item, lo.to(self.prev_token.span)));
            if !self.eat(&token::Comma) {
                break;
            }
        }

        Ok((cfg_predicate, expanded_attrs))
    }

    /// Matches `COMMASEP(meta_item_inner)`.
    crate fn parse_meta_seq_top(&mut self) -> PResult<'a, Vec<ast::NestedMetaItem>> {
        // Presumably, the majority of the time there will only be one attr.
        let mut nmis = Vec::with_capacity(1);
        while self.token.kind != token::Eof {
            nmis.push(self.parse_meta_item_inner()?);
            if !self.eat(&token::Comma) {
                break;
            }
        }
        Ok(nmis)
    }

    /// Matches the following grammar (per RFC 1559).
    ///
    ///     meta_item : PATH ( '=' UNSUFFIXED_LIT | '(' meta_item_inner? ')' )? ;
    ///     meta_item_inner : (meta_item | UNSUFFIXED_LIT) (',' meta_item_inner)? ;
    pub fn parse_meta_item(&mut self) -> PResult<'a, ast::MetaItem> {
        let nt_meta = match self.token.kind {
            token::Interpolated(ref nt) => match **nt {
                token::NtMeta(ref e) => Some(e.clone()),
                _ => None,
            },
            _ => None,
        };

        if let Some(item) = nt_meta {
            return match item.meta(item.path.span) {
                Some(meta) => {
                    self.bump();
                    Ok(meta)
                }
                None => self.unexpected(),
            };
        }

        let lo = self.token.span;
        let path = self.parse_path(PathStyle::Mod)?;
        let kind = self.parse_meta_item_kind()?;
        let span = lo.to(self.prev_token.span);
        Ok(ast::MetaItem { path, kind, span })
    }

    crate fn parse_meta_item_kind(&mut self) -> PResult<'a, ast::MetaItemKind> {
        Ok(if self.eat(&token::Eq) {
            ast::MetaItemKind::NameValue(self.parse_unsuffixed_lit()?)
        } else if self.check(&token::OpenDelim(token::Paren)) {
            // Matches `meta_seq = ( COMMASEP(meta_item_inner) )`.
            let (list, _) = self.parse_paren_comma_seq(|p| p.parse_meta_item_inner())?;
            ast::MetaItemKind::List(list)
        } else {
            ast::MetaItemKind::Word
        })
    }

    /// Matches `meta_item_inner : (meta_item | UNSUFFIXED_LIT) ;`.
    fn parse_meta_item_inner(&mut self) -> PResult<'a, ast::NestedMetaItem> {
        match self.parse_unsuffixed_lit() {
            Ok(lit) => return Ok(ast::NestedMetaItem::Literal(lit)),
            Err(ref mut err) => err.cancel(),
        }

        match self.parse_meta_item() {
            Ok(mi) => return Ok(ast::NestedMetaItem::MetaItem(mi)),
            Err(ref mut err) => err.cancel(),
        }

        let found = pprust::token_to_string(&self.token);
        let msg = format!("expected unsuffixed literal or identifier, found `{}`", found);
        Err(self.struct_span_err(self.token.span, &msg))
    }
}

pub fn maybe_needs_tokens(attrs: &[ast::Attribute]) -> bool {
    // One of the attributes may either itself be a macro, or apply derive macros (`derive`),
    // or expand to macro attributes (`cfg_attr`).
    attrs.iter().any(|attr| {
        attr.ident().map_or(true, |ident| {
            ident.name == sym::derive
                || ident.name == sym::cfg_attr
                || !rustc_feature::is_builtin_attr_name(ident.name)
        })
    })
}
<commit_msg>rustc_parse: restore pub vis on parse_attribute<commit_after>use super::{Parser, PathStyle};
use rustc_ast as ast;
use rustc_ast::attr;
use rustc_ast::token::{self, Nonterminal};
use rustc_ast_pretty::pprust;
use rustc_errors::{error_code, PResult};
use rustc_span::{sym, Span};

use tracing::debug;

// Public for rustfmt usage
#[derive(Debug)]
pub enum InnerAttrPolicy<'a> {
    Permitted,
    Forbidden { reason: &'a str, saw_doc_comment: bool, prev_attr_sp: Option<Span> },
}

const DEFAULT_UNEXPECTED_INNER_ATTR_ERR_MSG: &str = "an inner attribute is not \
                                                     permitted in this context";

pub(super) const DEFAULT_INNER_ATTR_FORBIDDEN: InnerAttrPolicy<'_> = InnerAttrPolicy::Forbidden {
    reason: DEFAULT_UNEXPECTED_INNER_ATTR_ERR_MSG,
    saw_doc_comment: false,
    prev_attr_sp: None,
};

impl<'a> Parser<'a> {
    /// Parses attributes that appear before an item.
    pub(super) fn parse_outer_attributes(&mut self) -> PResult<'a, Vec<ast::Attribute>> {
        let mut attrs: Vec<ast::Attribute> = Vec::new();
        let mut just_parsed_doc_comment = false;
        loop {
            debug!("parse_outer_attributes: self.token={:?}", self.token);
            let attr = if self.check(&token::Pound) {
                let inner_error_reason = if just_parsed_doc_comment {
                    "an inner attribute is not permitted following an outer doc comment"
                } else if !attrs.is_empty() {
                    "an inner attribute is not permitted following an outer attribute"
                } else {
                    DEFAULT_UNEXPECTED_INNER_ATTR_ERR_MSG
                };
                let inner_parse_policy = InnerAttrPolicy::Forbidden {
                    reason: inner_error_reason,
                    saw_doc_comment: just_parsed_doc_comment,
                    prev_attr_sp: attrs.last().map(|a| a.span),
                };
                just_parsed_doc_comment = false;
                Some(self.parse_attribute(inner_parse_policy)?)
            } else if let token::DocComment(comment_kind, attr_style, data) = self.token.kind {
                if attr_style != ast::AttrStyle::Outer {
                    self.sess
                        .span_diagnostic
                        .struct_span_err_with_code(
                            self.token.span,
                            "expected outer doc comment",
                            error_code!(E0753),
                        )
                        .note(
                            "inner doc comments like this (starting with \
                         `//!` or `/*!`) can only appear before items",
                        )
                        .emit();
                }
                self.bump();
                just_parsed_doc_comment = true;
                Some(attr::mk_doc_comment(comment_kind, attr_style, data, self.prev_token.span))
            } else {
                None
            };

            if let Some(attr) = attr {
                attrs.push(attr);
            } else {
                break;
            }
        }
        Ok(attrs)
    }

    /// Matches `attribute = # ! [ meta_item ]`.
    /// `inner_parse_policy` prescribes how to handle inner attributes.
    // Public for rustfmt usage.
    pub fn parse_attribute(
        &mut self,
        inner_parse_policy: InnerAttrPolicy<'_>,
    ) -> PResult<'a, ast::Attribute> {
        debug!(
            "parse_attribute: inner_parse_policy={:?} self.token={:?}",
            inner_parse_policy, self.token
        );
        let lo = self.token.span;
        let ((item, style, span), tokens) = self.collect_tokens(|this| {
            if this.eat(&token::Pound) {
                let style = if this.eat(&token::Not) {
                    ast::AttrStyle::Inner
                } else {
                    ast::AttrStyle::Outer
                };

                this.expect(&token::OpenDelim(token::Bracket))?;
                let item = this.parse_attr_item(false)?;
                this.expect(&token::CloseDelim(token::Bracket))?;
                let attr_sp = lo.to(this.prev_token.span);

                // Emit error if inner attribute is encountered and forbidden.
                if style == ast::AttrStyle::Inner {
                    this.error_on_forbidden_inner_attr(attr_sp, inner_parse_policy);
                }

                Ok((item, style, attr_sp))
            } else {
                let token_str = pprust::token_to_string(&this.token);
                let msg = &format!("expected `#`, found `{}`", token_str);
                Err(this.struct_span_err(this.token.span, msg))
            }
        })?;

        Ok(attr::mk_attr_from_item(item, tokens, style, span))
    }

    pub(super) fn error_on_forbidden_inner_attr(&self, attr_sp: Span, policy: InnerAttrPolicy<'_>) {
        if let InnerAttrPolicy::Forbidden { reason, saw_doc_comment, prev_attr_sp } = policy {
            let prev_attr_note =
                if saw_doc_comment { "previous doc comment" } else { "previous outer attribute" };

            let mut diag = self.struct_span_err(attr_sp, reason);

            if let Some(prev_attr_sp) = prev_attr_sp {
                diag.span_label(attr_sp, "not permitted following an outer attribute")
                    .span_label(prev_attr_sp, prev_attr_note);
            }

            diag.note(
                "inner attributes, like `#![no_std]`, annotate the item enclosing them, \
                and are usually found at the beginning of source files. \
                Outer attributes, like `#[test]`, annotate the item following them.",
            )
            .emit();
        }
    }

    /// Parses an inner part of an attribute (the path and following tokens).
    /// The tokens must be either a delimited token stream, or empty token stream,
    /// or the "legacy" key-value form.
    ///     PATH `(` TOKEN_STREAM `)`
    ///     PATH `[` TOKEN_STREAM `]`
    ///     PATH `{` TOKEN_STREAM `}`
    ///     PATH
    ///     PATH `=` UNSUFFIXED_LIT
    /// The delimiters or `=` are still put into the resulting token stream.
    pub fn parse_attr_item(&mut self, capture_tokens: bool) -> PResult<'a, ast::AttrItem> {
        let item = match self.token.kind {
            token::Interpolated(ref nt) => match **nt {
                Nonterminal::NtMeta(ref item) => Some(item.clone().into_inner()),
                _ => None,
            },
            _ => None,
        };
        Ok(if let Some(item) = item {
            self.bump();
            item
        } else {
            let do_parse = |this: &mut Self| {
                let path = this.parse_path(PathStyle::Mod)?;
                let args = this.parse_attr_args()?;
                Ok(ast::AttrItem { path, args, tokens: None })
            };
            if capture_tokens {
                let (mut item, tokens) = self.collect_tokens(do_parse)?;
                item.tokens = tokens;
                item
            } else {
                do_parse(self)?
            }
        })
    }

    /// Parses attributes that appear after the opening of an item. These should
    /// be preceded by an exclamation mark, but we accept and warn about one
    /// terminated by a semicolon.
    ///
    /// Matches `inner_attrs*`.
    crate fn parse_inner_attributes(&mut self) -> PResult<'a, Vec<ast::Attribute>> {
        let mut attrs: Vec<ast::Attribute> = vec![];
        loop {
            // Only try to parse if it is an inner attribute (has `!`).
            let attr = if self.check(&token::Pound) && self.look_ahead(1, |t| t == &token::Not) {
                Some(self.parse_attribute(InnerAttrPolicy::Permitted)?)
            } else if let token::DocComment(comment_kind, attr_style, data) = self.token.kind {
                if attr_style == ast::AttrStyle::Inner {
                    self.bump();
                    Some(attr::mk_doc_comment(comment_kind, attr_style, data, self.prev_token.span))
                } else {
                    None
                }
            } else {
                None
            };
            if let Some(attr) = attr {
                attrs.push(attr);
            } else {
                break;
            }
        }
        Ok(attrs)
    }

    crate fn parse_unsuffixed_lit(&mut self) -> PResult<'a, ast::Lit> {
        let lit = self.parse_lit()?;
        debug!("checking if {:?} is unusuffixed", lit);

        if !lit.kind.is_unsuffixed() {
            self.struct_span_err(lit.span, "suffixed literals are not allowed in attributes")
                .help(
                    "instead of using a suffixed literal (`1u8`, `1.0f32`, etc.), \
                    use an unsuffixed version (`1`, `1.0`, etc.)",
                )
                .emit();
        }

        Ok(lit)
    }

    /// Parses `cfg_attr(pred, attr_item_list)` where `attr_item_list` is comma-delimited.
    pub fn parse_cfg_attr(&mut self) -> PResult<'a, (ast::MetaItem, Vec<(ast::AttrItem, Span)>)> {
        let cfg_predicate = self.parse_meta_item()?;
        self.expect(&token::Comma)?;

        // Presumably, the majority of the time there will only be one attr.
        let mut expanded_attrs = Vec::with_capacity(1);
        while self.token.kind != token::Eof {
            let lo = self.token.span;
            let item = self.parse_attr_item(true)?;
            expanded_attrs.push((item, lo.to(self.prev_token.span)));
            if !self.eat(&token::Comma) {
                break;
            }
        }

        Ok((cfg_predicate, expanded_attrs))
    }

    /// Matches `COMMASEP(meta_item_inner)`.
    crate fn parse_meta_seq_top(&mut self) -> PResult<'a, Vec<ast::NestedMetaItem>> {
        // Presumably, the majority of the time there will only be one attr.
        let mut nmis = Vec::with_capacity(1);
        while self.token.kind != token::Eof {
            nmis.push(self.parse_meta_item_inner()?);
            if !self.eat(&token::Comma) {
                break;
            }
        }
        Ok(nmis)
    }

    /// Matches the following grammar (per RFC 1559).
    ///
    ///     meta_item : PATH ( '=' UNSUFFIXED_LIT | '(' meta_item_inner? ')' )? ;
    ///     meta_item_inner : (meta_item | UNSUFFIXED_LIT) (',' meta_item_inner)? ;
    pub fn parse_meta_item(&mut self) -> PResult<'a, ast::MetaItem> {
        let nt_meta = match self.token.kind {
            token::Interpolated(ref nt) => match **nt {
                token::NtMeta(ref e) => Some(e.clone()),
                _ => None,
            },
            _ => None,
        };

        if let Some(item) = nt_meta {
            return match item.meta(item.path.span) {
                Some(meta) => {
                    self.bump();
                    Ok(meta)
                }
                None => self.unexpected(),
            };
        }

        let lo = self.token.span;
        let path = self.parse_path(PathStyle::Mod)?;
        let kind = self.parse_meta_item_kind()?;
        let span = lo.to(self.prev_token.span);
        Ok(ast::MetaItem { path, kind, span })
    }

    crate fn parse_meta_item_kind(&mut self) -> PResult<'a, ast::MetaItemKind> {
        Ok(if self.eat(&token::Eq) {
            ast::MetaItemKind::NameValue(self.parse_unsuffixed_lit()?)
        } else if self.check(&token::OpenDelim(token::Paren)) {
            // Matches `meta_seq = ( COMMASEP(meta_item_inner) )`.
            let (list, _) = self.parse_paren_comma_seq(|p| p.parse_meta_item_inner())?;
            ast::MetaItemKind::List(list)
        } else {
            ast::MetaItemKind::Word
        })
    }

    /// Matches `meta_item_inner : (meta_item | UNSUFFIXED_LIT) ;`.
    fn parse_meta_item_inner(&mut self) -> PResult<'a, ast::NestedMetaItem> {
        match self.parse_unsuffixed_lit() {
            Ok(lit) => return Ok(ast::NestedMetaItem::Literal(lit)),
            Err(ref mut err) => err.cancel(),
        }

        match self.parse_meta_item() {
            Ok(mi) => return Ok(ast::NestedMetaItem::MetaItem(mi)),
            Err(ref mut err) => err.cancel(),
        }

        let found = pprust::token_to_string(&self.token);
        let msg = format!("expected unsuffixed literal or identifier, found `{}`", found);
        Err(self.struct_span_err(self.token.span, &msg))
    }
}

pub fn maybe_needs_tokens(attrs: &[ast::Attribute]) -> bool {
    // One of the attributes may either itself be a macro, or apply derive macros (`derive`),
    // or expand to macro attributes (`cfg_attr`).
    attrs.iter().any(|attr| {
        attr.ident().map_or(true, |ident| {
            ident.name == sym::derive
                || ident.name == sym::cfg_attr
                || !rustc_feature::is_builtin_attr_name(ident.name)
        })
    })
}
<|endoftext|>


<commit_before>#![feature(asm)]
#![feature(rand)]

extern crate syscall;
extern crate raw_cpuid;
extern crate rand;

use std::fs::File;
use std::io::{Read, Write};

use rand::chacha::ChaChaRng;
use rand::Rng;

use raw_cpuid::CpuId;

use syscall::{Packet, Result, SchemeMut};

//TODO: Use a CSPRNG, allow write of entropy
struct RandScheme {
   prng: ChaChaRng
}

impl SchemeMut for RandScheme {
    fn open(&mut self, _path: &[u8], _flags: usize, _uid: u32, _gid: u32) -> Result<usize> {
        Ok(0)
    }

    fn dup(&mut self, file: usize, _buf: &[u8]) -> Result<usize> {
        Ok(file)
    }

    fn read(&mut self, _file: usize, buf: &mut [u8]) -> Result<usize> {
        let mut i = 0;
        for chunk in buf.chunks_mut(8) {
            let mut rand = self.prng.next_u64();
            for b in chunk.iter_mut() {
                *b = rand as u8;
                rand = rand >> 8;
                i += 1;
            }
        }
        Ok(i)
    }

    fn close(&mut self, _file: usize) -> Result<usize> {
        Ok(0)
    }
}

fn main(){
    let has_rdrand = CpuId::new().get_feature_info().unwrap().has_rdrand();

    // Daemonize
    if unsafe { syscall::clone(0).unwrap() } == 0 {
        let mut socket = File::create(":rand").expect("rand: failed to create rand scheme");

        let mut rng = ChaChaRng::new_unseeded();

        if has_rdrand {
            println!("rand: seeding with rdrand");
            let rand: u64;
            unsafe {
                asm!("rdrand rax"
                    : "={rax}"(rand)
                    :
                    :
                    : "intel", "volatile");
            }
            rng.set_counter(0, rand);
        } else {
            println!("rand: unseeded");
        }

        let mut scheme = RandScheme{prng: rng};
        loop {
            let mut packet = Packet::default();
            socket.read(&mut packet).expect("rand: failed to read events from rand scheme");
            scheme.handle(&mut packet);
            socket.write(&packet).expect("rand: failed to write responses to rand scheme");
        }
    }
}
<commit_msg>Add path implementation to rand<commit_after>#![feature(asm)]
#![feature(rand)]

extern crate syscall;
extern crate raw_cpuid;
extern crate rand;

use std::fs::File;
use std::io::{Read, Write};

use rand::chacha::ChaChaRng;
use rand::Rng;

use raw_cpuid::CpuId;

use syscall::{Packet, Result, SchemeMut};

//TODO: Use a CSPRNG, allow write of entropy
struct RandScheme {
   prng: ChaChaRng
}

impl SchemeMut for RandScheme {
    fn open(&mut self, _path: &[u8], _flags: usize, _uid: u32, _gid: u32) -> Result<usize> {
        Ok(0)
    }

    fn dup(&mut self, file: usize, _buf: &[u8]) -> Result<usize> {
        Ok(file)
    }

    fn read(&mut self, _file: usize, buf: &mut [u8]) -> Result<usize> {
        let mut i = 0;
        for chunk in buf.chunks_mut(8) {
            let mut rand = self.prng.next_u64();
            for b in chunk.iter_mut() {
                *b = rand as u8;
                rand = rand >> 8;
                i += 1;
            }
        }
        Ok(i)
    }

    fn fpath(&mut self, _file: usize, buf: &mut [u8]) -> Result<usize> {
        let mut i = 0;
        let scheme_path = b"rand";
        while i < buf.len() && i < scheme_path.len() {
            buf[i] = scheme_path[i];
            i += 1;
        }
        Ok(i)
    }

    fn close(&mut self, _file: usize) -> Result<usize> {
        Ok(0)
    }
}

fn main(){
    let has_rdrand = CpuId::new().get_feature_info().unwrap().has_rdrand();

    // Daemonize
    if unsafe { syscall::clone(0).unwrap() } == 0 {
        let mut socket = File::create(":rand").expect("rand: failed to create rand scheme");

        let mut rng = ChaChaRng::new_unseeded();

        if has_rdrand {
            println!("rand: seeding with rdrand");
            let rand: u64;
            unsafe {
                asm!("rdrand rax"
                    : "={rax}"(rand)
                    :
                    :
                    : "intel", "volatile");
            }
            rng.set_counter(0, rand);
        } else {
            println!("rand: unseeded");
        }

        let mut scheme = RandScheme{prng: rng};
        loop {
            let mut packet = Packet::default();
            socket.read(&mut packet).expect("rand: failed to read events from rand scheme");
            scheme.handle(&mut packet);
            socket.write(&packet).expect("rand: failed to write responses to rand scheme");
        }
    }
}
<|endoftext|>


<commit_before>use std::hash;
use std::hash::Hash;

#[derive(Show,Clone)]
pub enum Exp<'x> {
    Value(int),
    Plus(Box<Exp<'x>>, Box<Exp<'x>>),
    Ref(&'x Exp<'x>) // Refs allow for (non-affine) sharing.
}

pub fn step<'x> (e:&'x Exp<'x>) -> Option<Exp<'x>> {
    match *e {
        Exp::Value(_) => None,
        Exp::Ref(e) => step(e),
        Exp::Plus(ref e1, ref e2) =>
            match **e1 {
                Exp::Value(n) =>
                    match **e2 {
                        Exp::Value(m) => Some(Exp::Value(n+m)),
                        _ => {
                            let e2_ = step(&**e2) ;
                            match e2_ {
                                None => panic!("impossible"),
                                Some(e2_) => Some(Exp::Plus(box Exp::Value(n), box e2_))
                            }
                        }
                    },

                _ => {
                    let e1_ = step(&**e1) ;
                    match e1_ {
                        None => panic!("impossible"),
                        Some(e1_) => Some(Exp::Plus(box e1_, box Exp::Ref(&**e2)))
                    }
                }
            }
    }
}

#[test]
pub fn print() {
    let e0 = Exp::Plus(box Exp::Value(1),
                       box Exp::Plus(box Exp::Value(2),
                                     box Exp::Plus(box Exp::Value(3),
                                                   box Exp::Plus(box Exp::Value(4),
                                                                 box Exp::Value(5))))) ;
    let e1 = step(e0) ;
    let e2 = step(e1) ;
    let e3 = step(e2) ;
    print!("{} {} {} {}", e0, e1, e2, e3);
}

pub fn test1 () {
    let e0 = Exp::Plus(box Exp::Value(1),
                       box Exp::Plus(box Exp::Value(2),
                                     box Exp::Plus(box Exp::Value(3),
                                                   box Exp::Plus(box Exp::Value(4),
                                                                 box Exp::Value(5))))) ;
    let e1 = step(&e0) ;
    match e1 {
        None => (),
        Some(ref e1) => {
            println!("{} --> {}", e0, e1) ;
            let e2 = step( e1 ) ;
            match e2 {
                None => (),
                Some(ref e2) => {
                    println!("{} --> {}", e1, e2) ;
                    let e3 = step( e2 ) ;
                    match e3 {
                        None => (),
                        Some(ref e3) => {
                            println!("{} --> {}", e2, e3) ;
                            let e4 = step( e3 ) ;
                            match e4 {
                                None => (),
                                Some(ref e4) => {
                                    println!("{} --> {}", e3, e4) ;
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}

pub fn test2 () {
    let e0 = Exp::Plus(box Exp::Value(1),
                       box Exp::Plus(box Exp::Value(2),
                                     box Exp::Plus(box Exp::Value(3),
                                                   box Exp::Plus(box Exp::Value(4),
                                                                 box Exp::Value(5))))) ;
    let mut exp = & e0 ;
    loop {
        let s = step(&e0) ;
        match s {
            None => break,
            Some(ref exp_) => {
                println!("{} --> {}", exp, exp_) ;
                // exp = exp_.clone () ;
                continue
            }
        }
    }
}

pub fn main () {
    if true {
        test1 ()
    }
    else {
        test2 ()
    }
}

//     let mut e = e0.clone () ;
// loop {
//         match step(&e) {
//             None => break,
//             Some(e2) => {
//                 println!("{} --> {}", e, e2) ;
//                 //let e3 = e2.clone() ;
//                 //e = e3 ;
//                 continue ;
//             }
//     }}
// }
<commit_msg>example that uses Ref case during stepping<commit_after>use std::hash;
use std::hash::Hash;

#[derive(Show,Clone)]
pub enum Exp<'x> {
    Value(int),
    Plus(Box<Exp<'x>>, Box<Exp<'x>>),
    Ref(&'x Exp<'x>) // Refs allow for (non-affine) sharing.
}

pub fn step<'x> (e:&'x Exp<'x>) -> Option<Exp<'x>> {
    match *e {
        Exp::Value(_) => None,
        Exp::Ref(e) => step(e),
        Exp::Plus(ref e1, ref e2) =>
            match **e1 {
                Exp::Value(n) =>
                    match **e2 {
                        Exp::Value(m) => Some(Exp::Value(n+m)),
                        _ => {
                            let e2_ = step(&**e2) ;
                            match e2_ {
                                None => panic!("impossible"),
                                Some(e2_) => Some(Exp::Plus(box Exp::Value(n), box e2_))
                            }
                        }
                    },

                _ => {
                    let e1_ = step(&**e1) ;
                    match e1_ {
                        None => panic!("impossible"),
                        Some(e1_) => Some(Exp::Plus(box e1_, box Exp::Ref(&**e2)))
                    }
                }
            }
    }
}

#[test]
pub fn print() {
    let e0 = Exp::Plus(box Exp::Value(1),
                       box Exp::Plus(box Exp::Value(2),
                                     box Exp::Plus(box Exp::Value(3),
                                                   box Exp::Plus(box Exp::Value(4),
                                                                 box Exp::Value(5))))) ;
    let e1 = step(e0) ;
    let e2 = step(e1) ;
    let e3 = step(e2) ;
    print!("{} {} {} {}", e0, e1, e2, e3);
}

pub fn test1 () {
    let e0 = Exp::Plus(box Exp::Plus(box Exp::Value(0),
                                     box Exp::Value(1)),
                       box Exp::Plus(box Exp::Value(2),
                                     box Exp::Plus(box Exp::Plus(box Exp::Value(0),
                                                                 box Exp::Value(3)),
                                                   box Exp::Plus(box Exp::Value(4),
                                                                 box Exp::Value(5))))) ;
    let e1 = step(&e0) ;
    match e1 {
        None => (),
        Some(ref e1) => {
            println!("{} --> {}", e0, e1) ;
            let e2 = step( e1 ) ;
            match e2 {
                None => (),
                Some(ref e2) => {
                    println!("{} --> {}", e1, e2) ;
                    let e3 = step( e2 ) ;
                    match e3 {
                        None => (),
                        Some(ref e3) => {
                            println!("{} --> {}", e2, e3) ;
                            let e4 = step( e3 ) ;
                            match e4 {
                                None => (),
                                Some(ref e4) => {
                                    println!("{} --> {}", e3, e4) ;
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}

pub fn test2 () {
    let e0 = Exp::Plus(box Exp::Value(1),
                       box Exp::Plus(box Exp::Value(2),
                                     box Exp::Plus(box Exp::Value(3),
                                                   box Exp::Plus(box Exp::Value(4),
                                                                 box Exp::Value(5))))) ;
    let mut exp = & e0 ;
    loop {
        let s = step(&e0) ;
        match s {
            None => break,
            Some(ref exp_) => {
                println!("{} --> {}", exp, exp_) ;
                // exp = exp_.clone () ;
                continue
            }
        }
    }
}

pub fn main () {
    if true {
        test1 ()
    }
    else {
        test2 ()
    }
}

//     let mut e = e0.clone () ;
// loop {
//         match step(&e) {
//             None => break,
//             Some(e2) => {
//                 println!("{} --> {}", e, e2) ;
//                 //let e3 = e2.clone() ;
//                 //e = e3 ;
//                 continue ;
//             }
//     }}
// }
<|endoftext|>