<commit_before>// Claxon -- A FLAC decoding library in Rust
// Copyright 2014 Ruud van Asseldonk
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// A copy of the License has been included in the root of the repository.

//! Claxon, a FLAC decoding library.
//!
//! Examples
//! ========
//!
//! The following example computes the root mean square (RMS) of a FLAC file.
//!
//! ```
//! # use claxon;
//! let mut reader = claxon::FlacReader::open("testsamples/pop.flac").unwrap();
//! let mut sqr_sum = 0.0;
//! let mut count = 0;
//! for sample in reader.samples() {
//!     let s = sample.unwrap() as f64;
//!     sqr_sum += s * s;
//!     count += 1;
//! }
//! println!("RMS is {}", (sqr_sum / count as f64).sqrt());
//! ```
//!
//! A simple way to decode a file to wav with Claxon and
//! [Hound](https://github.com/ruuda/hound):
//!
//! ```
//! # extern crate hound;
//! # extern crate claxon;
//! # use std::path::Path;
//! # fn decode_file(fname: &Path) {
//! let mut reader = claxon::FlacReader::open(fname).expect("failed to open FLAC stream");
//!
//! let spec = hound::WavSpec {
//!     channels: reader.streaminfo().channels as u16,
//!     sample_rate: reader.streaminfo().sample_rate,
//!     bits_per_sample: reader.streaminfo().bits_per_sample as u16,
//!     sample_format: hound::SampleFormat::Int,
//! };
//!
//! let fname_wav = fname.with_extension("wav");
//! let opt_wav_writer = hound::WavWriter::create(fname_wav, spec);
//! let mut wav_writer = opt_wav_writer.expect("failed to create wav file");
//!
//! for opt_sample in reader.samples() {
//!     let sample = opt_sample.expect("failed to decode FLAC stream");
//!     wav_writer.write_sample(sample).expect("failed to write wav file");
//! }
//! # }
//! ```
//!
//! For more examples, see the [examples](https://github.com/ruuda/claxon/tree/master/examples)
//! directory in the crate.

#![warn(missing_docs)]

use std::fs;
use std::io;
use std::mem;
use std::path;
use error::fmt_err;
use frame::FrameReader;
use input::{BufferedReader, ReadBytes};
use metadata::{MetadataBlock, MetadataBlockReader, StreamInfo, VorbisComment};

mod crc;
mod error;
pub mod frame;
pub mod input;
pub mod metadata;
pub mod subframe;

pub use error::{Error, Result};
pub use frame::Block;

/// A FLAC decoder that can decode the stream from the underlying reader.
///
/// TODO: Add an example.
pub struct FlacReader<R: io::Read> {
    streaminfo: StreamInfo,
    #[allow(dead_code)] // TODO: Expose metadata nicely.
    metadata_blocks: Vec<MetadataBlock>,
    input: BufferedReader<R>,
}

/// An iterator that yields samples read from a `FlacReader`.
pub struct FlacSamples<R: ReadBytes> {
    frame_reader: FrameReader<R>,
    block: Block,
    sample: u32,
    channel: u32,

    /// If reading ever failed, this flag is set, so that the iterator knows not
    /// to return any new values.
    has_failed: bool,
}

// TODO: Add a `FlacIntoSamples`.

fn read_stream_header<R: ReadBytes>(input: &mut R) -> Result<()> {
    // A FLAC stream starts with a 32-bit header 'fLaC' (big endian).
    const FLAC_HEADER: u32 = 0x66_4c_61_43;

    // Some files start with ID3 tag data. The reference decoder supports this
    // for convenience. Claxon does not, but we can at least generate a helpful
    // error message if a file starts like this.
    const ID3_HEADER: u32 = 0x49_44_33_00;

    let header = try!(input.read_be_u32());
    if header != FLAC_HEADER {
        if (header & 0xff_ff_ff_00) == ID3_HEADER {
            fmt_err("stream starts with ID3 header rather than FLAC header")
        } else {
            fmt_err("invalid stream header")
        }
    } else {
        Ok(())
    }
}

impl<R: io::Read> FlacReader<R> {
    /// Attempts to create a reader that reads the FLAC format.
    ///
    /// The header and metadata blocks are read immediately. Audio frames will
    /// be read on demand.
    pub fn new(reader: R) -> Result<FlacReader<R>> {
        let mut buf_reader = BufferedReader::new(reader);

        // A flac stream first of all starts with a stream header.
        try!(read_stream_header(&mut buf_reader));

        // Start a new scope, because the input reader must be available again
        // for the frame reader next.
        let (streaminfo, metadata_blocks) = {
            // Next are one or more metadata blocks. The flac specification
            // dictates that the streaminfo block is the first block. The metadata
            // block reader will yield at least one element, so the unwrap is safe.
            let mut metadata_iter = MetadataBlockReader::new(&mut buf_reader);
            let streaminfo_block = try!(metadata_iter.next().unwrap());
            let streaminfo = match streaminfo_block {
                MetadataBlock::StreamInfo(info) => info,
                _ => return fmt_err("streaminfo block missing"),
            };

            // There might be more metadata blocks, read and store them.
            let mut metadata_blocks = Vec::new();
            for block_result in metadata_iter {
                match block_result {
                    Err(error) => return Err(error),
                    Ok(block) => metadata_blocks.push(block),
                }
            }

            (streaminfo, metadata_blocks)
        };

        // The flac reader will contain the reader that will read frames.
        let flac_reader = FlacReader {
            streaminfo: streaminfo,
            metadata_blocks: metadata_blocks,
            input: buf_reader,
        };

        Ok(flac_reader)
    }

    /// Returns the streaminfo metadata.
    ///
    /// This contains information like the sample rate and number of channels.
    pub fn streaminfo(&self) -> StreamInfo {
        self.streaminfo
    }

    fn vorbis_comment_block(&self) -> Option<&VorbisComment> {
        for metadata_block in &self.metadata_blocks {
            match *metadata_block {
                MetadataBlock::VorbisComment(ref vc) => return Some(vc),
                _ => continue,
            }
        }
        None
    }

    /// Returns the vendor string of the Vorbis comment block, if present.
    ///
    /// This string usually contains the name and version of the program that
    /// produced the FLAC stream, such as `reference libFLAC 1.3.2 20170101`
    /// or `Lavf57.25.100`.
    pub fn vendor(&self) -> Option<&str> {
        self.vorbis_comment_block().map(|vc| &vc.vendor[..])
    }

    /// Returns an iterator that decodes a single frame on every iteration.
    /// TODO: It is not an iterator.
    ///
    /// This is a low-level primitive that gives you control over when decoding
    /// happens. The representation of the decoded audio is somewhat specific to
    /// the FLAC format. For a higher-level interface, see `samples()`.
    pub fn blocks<'r>(&'r mut self) -> FrameReader<&'r mut BufferedReader<R>> {
        FrameReader::new(&mut self.input)
    }

    /// Returns an iterator over all samples.
    ///
    /// This is a user-friendly interface that trades performance for ease of
    /// use. If performance is an issue, consider using `blocks()` instead.
    ///
    /// This is a high-level interface to the decoder. The cost of retrieving
    /// the next sample can vary significantly, as sometimes a new block has to
    /// be decoded. Additionally, there is a cost to every iteration returning a
    /// `Result`. When a block has been decoded, iterating the samples in that
    /// block can never fail, but a match on every sample is required
    /// nonetheless. For more control over when decoding happens, and less error
    /// handling overhead, use `blocks()`.
    ///
    /// The channel data is is interleaved. The iterator is streaming. That is,
    /// if you call this method once, read a few samples, and call this method
    /// again, the second iterator will not start again from the beginning of
    /// the file. It will continue somewhere after where the first iterator
    /// stopped, and it might skip some samples. (This is because FLAC divides
    /// a stream into blocks, which have to be decoded entirely. If you drop the
    /// iterator, you lose the unread samples in that block.)
    pub fn samples<'r>(&'r mut self) -> FlacSamples<&'r mut BufferedReader<R>> {
        FlacSamples {
            frame_reader: frame::FrameReader::new(&mut self.input),
            block: Block::empty(),
            sample: 0,
            channel: 0,
            has_failed: false,
        }
    }

    /// Destroys the FLAC reader and returns the underlying reader.
    ///
    /// Because the reader employs buffering internally, anything in the buffer
    /// will be lost.
    pub fn into_inner(self) -> R {
        self.input.into_inner()
    }
}

impl FlacReader<fs::File> {
    /// Attempts to create a reader that reads from the specified file.
    ///
    /// This is a convenience constructor that opens a `File`, and constructs a
    /// `FlacReader` from it. There is no need to wrap the file in a
    /// `BufReader`, as the `FlacReader` employs buffering already.
    pub fn open<P: AsRef<path::Path>>(filename: P) -> Result<FlacReader<fs::File>> {
        let file = try!(fs::File::open(filename));
        FlacReader::new(file)
    }
}

impl<R: ReadBytes> Iterator for FlacSamples<R> {
    type Item = Result<i32>;

    fn next(&mut self) -> Option<Result<i32>> {
        // If the previous read failed, end iteration.
        if self.has_failed {
            return None;
        }

        // Iterate the samples channel interleaved, so first increment the
        // channel.
        self.channel += 1;

        // If that was the last channel, increment the sample number.
        if self.channel >= self.block.channels() {
            self.channel = 0;
            self.sample += 1;

            // If that was the last sample in the block, decode the next block.
            if self.sample >= self.block.duration() {
                self.sample = 0;

                // Replace the current block with an empty one so that we may
                // reuse the current buffer to decode again.
                let current_block = mem::replace(&mut self.block, Block::empty());

                match self.frame_reader.read_next_or_eof(current_block.into_buffer()) {
                    Ok(Some(next_block)) => {
                        self.block = next_block;
                    }
                    Ok(None) => {
                        // The stream ended with EOF.
                        // TODO: If a number of samples was specified in the
                        // streaminfo metadata block, verify that we did not
                        // read more or less samples.
                        return None;
                    }
                    Err(error) => {
                        self.has_failed = true;
                        return Some(Err(error));
                    }
                }
            }
        }

        Some(Ok(self.block.sample(self.channel, self.sample)))
    }
}
<commit_msg>Store Vorbis comment block immediately when found<commit_after>// Claxon -- A FLAC decoding library in Rust
// Copyright 2014 Ruud van Asseldonk
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// A copy of the License has been included in the root of the repository.

//! Claxon, a FLAC decoding library.
//!
//! Examples
//! ========
//!
//! The following example computes the root mean square (RMS) of a FLAC file.
//!
//! ```
//! # use claxon;
//! let mut reader = claxon::FlacReader::open("testsamples/pop.flac").unwrap();
//! let mut sqr_sum = 0.0;
//! let mut count = 0;
//! for sample in reader.samples() {
//!     let s = sample.unwrap() as f64;
//!     sqr_sum += s * s;
//!     count += 1;
//! }
//! println!("RMS is {}", (sqr_sum / count as f64).sqrt());
//! ```
//!
//! A simple way to decode a file to wav with Claxon and
//! [Hound](https://github.com/ruuda/hound):
//!
//! ```
//! # extern crate hound;
//! # extern crate claxon;
//! # use std::path::Path;
//! # fn decode_file(fname: &Path) {
//! let mut reader = claxon::FlacReader::open(fname).expect("failed to open FLAC stream");
//!
//! let spec = hound::WavSpec {
//!     channels: reader.streaminfo().channels as u16,
//!     sample_rate: reader.streaminfo().sample_rate,
//!     bits_per_sample: reader.streaminfo().bits_per_sample as u16,
//!     sample_format: hound::SampleFormat::Int,
//! };
//!
//! let fname_wav = fname.with_extension("wav");
//! let opt_wav_writer = hound::WavWriter::create(fname_wav, spec);
//! let mut wav_writer = opt_wav_writer.expect("failed to create wav file");
//!
//! for opt_sample in reader.samples() {
//!     let sample = opt_sample.expect("failed to decode FLAC stream");
//!     wav_writer.write_sample(sample).expect("failed to write wav file");
//! }
//! # }
//! ```
//!
//! For more examples, see the [examples](https://github.com/ruuda/claxon/tree/master/examples)
//! directory in the crate.

#![warn(missing_docs)]

use std::fs;
use std::io;
use std::mem;
use std::path;
use error::fmt_err;
use frame::FrameReader;
use input::{BufferedReader, ReadBytes};
use metadata::{MetadataBlock, MetadataBlockReader, StreamInfo, VorbisComment};

mod crc;
mod error;
pub mod frame;
pub mod input;
pub mod metadata;
pub mod subframe;

pub use error::{Error, Result};
pub use frame::Block;

/// A FLAC decoder that can decode the stream from the underlying reader.
///
/// TODO: Add an example.
pub struct FlacReader<R: io::Read> {
    streaminfo: StreamInfo,
    vorbis_comment: Option<VorbisComment>,
    #[allow(dead_code)] // TODO: Expose metadata nicely.
    metadata_blocks: Vec<MetadataBlock>,
    input: BufferedReader<R>,
}

/// An iterator that yields samples read from a `FlacReader`.
pub struct FlacSamples<R: ReadBytes> {
    frame_reader: FrameReader<R>,
    block: Block,
    sample: u32,
    channel: u32,

    /// If reading ever failed, this flag is set, so that the iterator knows not
    /// to return any new values.
    has_failed: bool,
}

// TODO: Add a `FlacIntoSamples`.

fn read_stream_header<R: ReadBytes>(input: &mut R) -> Result<()> {
    // A FLAC stream starts with a 32-bit header 'fLaC' (big endian).
    const FLAC_HEADER: u32 = 0x66_4c_61_43;

    // Some files start with ID3 tag data. The reference decoder supports this
    // for convenience. Claxon does not, but we can at least generate a helpful
    // error message if a file starts like this.
    const ID3_HEADER: u32 = 0x49_44_33_00;

    let header = try!(input.read_be_u32());
    if header != FLAC_HEADER {
        if (header & 0xff_ff_ff_00) == ID3_HEADER {
            fmt_err("stream starts with ID3 header rather than FLAC header")
        } else {
            fmt_err("invalid stream header")
        }
    } else {
        Ok(())
    }
}

impl<R: io::Read> FlacReader<R> {
    /// Attempts to create a reader that reads the FLAC format.
    ///
    /// The header and metadata blocks are read immediately. Audio frames will
    /// be read on demand.
    pub fn new(reader: R) -> Result<FlacReader<R>> {
        let mut buf_reader = BufferedReader::new(reader);

        // A flac stream first of all starts with a stream header.
        try!(read_stream_header(&mut buf_reader));

        // Start a new scope, because the input reader must be available again
        // for the frame reader next.
        let (streaminfo, vorbis_comment, metadata_blocks) = {
            // Next are one or more metadata blocks. The flac specification
            // dictates that the streaminfo block is the first block. The metadata
            // block reader will yield at least one element, so the unwrap is safe.
            let mut metadata_iter = MetadataBlockReader::new(&mut buf_reader);
            let streaminfo_block = try!(metadata_iter.next().unwrap());
            let streaminfo = match streaminfo_block {
                MetadataBlock::StreamInfo(info) => info,
                _ => return fmt_err("streaminfo block missing"),
            };

            let mut vorbis_comment = None;

            // There might be more metadata blocks, read and store them.
            let mut metadata_blocks = Vec::new();
            for block_result in metadata_iter {
                match try!(block_result) {
                    MetadataBlock::VorbisComment(vc) => {
                        // The Vorbis comment block need not be present, but
                        // when it is, it must be unique.
                        if vorbis_comment.is_some() {
                            return fmt_err("encountered second Vorbis comment block")
                        } else {
                            vorbis_comment = Some(vc);
                        }
                    }
                    MetadataBlock::StreamInfo(..) => {
                        return fmt_err("encountered second streaminfo block")
                    }
                    // Other blocks are currently not handled.
                    block => metadata_blocks.push(block),
                }
            }

            (streaminfo, vorbis_comment, metadata_blocks)
        };

        // The flac reader will contain the reader that will read frames.
        let flac_reader = FlacReader {
            streaminfo: streaminfo,
            vorbis_comment: vorbis_comment,
            metadata_blocks: metadata_blocks,
            input: buf_reader,
        };

        Ok(flac_reader)
    }

    /// Returns the streaminfo metadata.
    ///
    /// This contains information like the sample rate and number of channels.
    pub fn streaminfo(&self) -> StreamInfo {
        self.streaminfo
    }

    /// Returns the vendor string of the Vorbis comment block, if present.
    ///
    /// This string usually contains the name and version of the program that
    /// produced the FLAC stream, such as `reference libFLAC 1.3.2 20170101`
    /// or `Lavf57.25.100`.
    pub fn vendor(&self) -> Option<&str> {
        self.vorbis_comment.as_ref().map(|vc| &vc.vendor[..])
    }

    /// Returns an iterator that decodes a single frame on every iteration.
    /// TODO: It is not an iterator.
    ///
    /// This is a low-level primitive that gives you control over when decoding
    /// happens. The representation of the decoded audio is somewhat specific to
    /// the FLAC format. For a higher-level interface, see `samples()`.
    pub fn blocks<'r>(&'r mut self) -> FrameReader<&'r mut BufferedReader<R>> {
        FrameReader::new(&mut self.input)
    }

    /// Returns an iterator over all samples.
    ///
    /// This is a user-friendly interface that trades performance for ease of
    /// use. If performance is an issue, consider using `blocks()` instead.
    ///
    /// This is a high-level interface to the decoder. The cost of retrieving
    /// the next sample can vary significantly, as sometimes a new block has to
    /// be decoded. Additionally, there is a cost to every iteration returning a
    /// `Result`. When a block has been decoded, iterating the samples in that
    /// block can never fail, but a match on every sample is required
    /// nonetheless. For more control over when decoding happens, and less error
    /// handling overhead, use `blocks()`.
    ///
    /// The channel data is is interleaved. The iterator is streaming. That is,
    /// if you call this method once, read a few samples, and call this method
    /// again, the second iterator will not start again from the beginning of
    /// the file. It will continue somewhere after where the first iterator
    /// stopped, and it might skip some samples. (This is because FLAC divides
    /// a stream into blocks, which have to be decoded entirely. If you drop the
    /// iterator, you lose the unread samples in that block.)
    pub fn samples<'r>(&'r mut self) -> FlacSamples<&'r mut BufferedReader<R>> {
        FlacSamples {
            frame_reader: frame::FrameReader::new(&mut self.input),
            block: Block::empty(),
            sample: 0,
            channel: 0,
            has_failed: false,
        }
    }

    /// Destroys the FLAC reader and returns the underlying reader.
    ///
    /// Because the reader employs buffering internally, anything in the buffer
    /// will be lost.
    pub fn into_inner(self) -> R {
        self.input.into_inner()
    }
}

impl FlacReader<fs::File> {
    /// Attempts to create a reader that reads from the specified file.
    ///
    /// This is a convenience constructor that opens a `File`, and constructs a
    /// `FlacReader` from it. There is no need to wrap the file in a
    /// `BufReader`, as the `FlacReader` employs buffering already.
    pub fn open<P: AsRef<path::Path>>(filename: P) -> Result<FlacReader<fs::File>> {
        let file = try!(fs::File::open(filename));
        FlacReader::new(file)
    }
}

impl<R: ReadBytes> Iterator for FlacSamples<R> {
    type Item = Result<i32>;

    fn next(&mut self) -> Option<Result<i32>> {
        // If the previous read failed, end iteration.
        if self.has_failed {
            return None;
        }

        // Iterate the samples channel interleaved, so first increment the
        // channel.
        self.channel += 1;

        // If that was the last channel, increment the sample number.
        if self.channel >= self.block.channels() {
            self.channel = 0;
            self.sample += 1;

            // If that was the last sample in the block, decode the next block.
            if self.sample >= self.block.duration() {
                self.sample = 0;

                // Replace the current block with an empty one so that we may
                // reuse the current buffer to decode again.
                let current_block = mem::replace(&mut self.block, Block::empty());

                match self.frame_reader.read_next_or_eof(current_block.into_buffer()) {
                    Ok(Some(next_block)) => {
                        self.block = next_block;
                    }
                    Ok(None) => {
                        // The stream ended with EOF.
                        // TODO: If a number of samples was specified in the
                        // streaminfo metadata block, verify that we did not
                        // read more or less samples.
                        return None;
                    }
                    Err(error) => {
                        self.has_failed = true;
                        return Some(Err(error));
                    }
                }
            }
        }

        Some(Ok(self.block.sample(self.channel, self.sample)))
    }
}
<|endoftext|>


<commit_before>extern crate futures;

use futures::{Async, Future, Poll};

use std::marker::PhantomData;
use std::mem;

mod and_then;
mod chain;
mod map;

pub use and_then::AndThen;
pub use map::TaskedMap;

pub trait TaskedFuture {
    type Item;
    type Error;
    type Task;

    fn poll(&mut self, t: &mut Self::Task) -> Poll<Self::Item, Self::Error>;

    fn map<F, U>(self, f: F) -> TaskedMap<Self, F> where F: FnOnce(Self::Item, &mut Self::Task) -> U, Self: Sized {
        map::new(self, f)
    }

    fn and_then<F, B>(self, f: F) -> AndThen<Self, B, F>
        where F: FnOnce(Self::Item, &mut Self::Task) -> B,
              B: IntoTaskedFuture<Error = Self::Error, Task=Self::Task>,
              Self: Sized,
    {
        and_then::new(self, f)
    }

}

struct FnWrapper<F, T, R, E> where F: FnMut(&mut T) -> Poll<R, E> {
    func: F,
    _phantom_data: PhantomData<(T, R, E)>,
}

impl<F, T, R, E> FnWrapper<F, T, R, E> where F: FnMut(&mut T) -> Poll<R, E> {
    pub fn new(f: F) -> FnWrapper<F, T, R, E> {
        FnWrapper {
            func: f,
            _phantom_data: PhantomData,
        }
    }
}

impl<F, T, R, E> TaskedFuture for FnWrapper<F, T, R, E> where F: FnMut(&mut T) -> Poll<R, E> {
    type Item = R;
    type Error = E;
    type Task = T;

    fn poll(&mut self, task: &mut Self::Task) -> Poll<Self::Item, Self::Error> {
        (self.func)(task)
    }
}

pub trait IntoTaskedFuture {
    /// The future that this type can be converted into.
    type TaskedFuture: TaskedFuture<Item=Self::Item, Error=Self::Error, Task=Self::Task>;

    type Item;
    type Error;
    type Task;

    fn into_tasked_future(self) -> Self::TaskedFuture;
}

impl<T> IntoTaskedFuture for T where T: TaskedFuture {
    type TaskedFuture = Self;

    type Item = <Self as TaskedFuture>::Item;
    type Error = <Self as TaskedFuture>::Error;
    type Task = <Self as TaskedFuture>::Task;

    fn into_tasked_future(self) -> Self::TaskedFuture {
        self
    }
}

pub trait FutureTaskedExt: Future + Sized {
    fn into_tasked<T>(self) -> TaskedFutureAdaptor<Self, T> {
        TaskedFutureAdaptor::new(self)
    }
}

impl<F: Future + Sized> FutureTaskedExt for F {}

pub struct TaskedFutureAdaptor<F, T> {
    future: F,
    _phantom_data: PhantomData<T>,
}

impl<F, T> TaskedFutureAdaptor<F, T> {
    pub fn new(future: F) -> TaskedFutureAdaptor<F, T> {
        TaskedFutureAdaptor {
            future: future,
            _phantom_data: PhantomData,
        }
    }
}

impl<F, I, E, T> TaskedFuture for TaskedFutureAdaptor<F, T> where F: Future<Item=I, Error=E> {
    type Item = I;
    type Error = E;
    type Task = T;

    fn poll(&mut self, _task: &mut Self::Task) -> Poll<I, E> {
        self.future.poll()
    }
}

type BoxedExecutorFuture<T, E> = Box<TaskedFuture<Item=(), Error=E, Task=T>>;

pub struct TaskExecutorQueue<T, E> {
    queue: Vec<BoxedExecutorFuture<T, E>>,
}

impl<T, E> TaskExecutorQueue<T, E> {
    pub fn new() -> TaskExecutorQueue<T, E> {
        TaskExecutorQueue {
            queue: Vec::new(),
        }
    }
}

impl<T, E> Default for TaskExecutorQueue<T, E> {
    fn default() -> TaskExecutorQueue<T, E> {
        TaskExecutorQueue {
            queue: Vec::new(),
        }
    }
}

pub trait TaskExecutor: Sized + 'static {
    type Error;

    fn task_executor_mut(&mut self) -> &mut TaskExecutorQueue<Self, Self::Error>;

    fn spawn<F>(&mut self, future: F) where F: IntoTaskedFuture<Item=(), Error=Self::Error, Task=Self> + 'static {
        self.task_executor_mut().queue.push(Box::new(future.into_tasked_future()))
    }

    fn spawn_fn<F>(&mut self, func: F) where F: FnMut(&mut Self) -> Poll<(), Self::Error> + 'static {
        self.task_executor_mut().queue.push(Box::new(FnWrapper::new(func)))
    }

    fn poll(&mut self) -> Poll<(), Self::Error> {
        let len = self.task_executor_mut().queue.len();
        let queue = mem::replace(&mut self.task_executor_mut().queue, Vec::with_capacity(len));

        let mut to_append = Vec::with_capacity(len);
        for mut future in queue {
            if let Async::NotReady = try!(future.poll(self)) {
                to_append.push(future);
            }
        }

        self.task_executor_mut().queue.append(&mut to_append);

        if self.task_executor_mut().queue.is_empty() {
            Ok(Async::Ready(()))
        } else {
            Ok(Async::NotReady)
        }
    }

    fn into_future(self) -> TaskExecutorFuture<Self> {
        TaskExecutorFuture { inner: self }
    }
}

pub struct TaskExecutorFuture<T> {
    inner: T
}

impl<T, E> Future for TaskExecutorFuture<T> where T: TaskExecutor<Error=E> {
    type Item = ();
    type Error = E;

    fn poll(&mut self) -> Poll<(), Self::Error> {
        self.inner.poll()
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use futures::{Async, Future, empty, oneshot, task, lazy};
    use std::sync::Arc;
    use std::cell::Cell;

    struct DummyUnpark;

    impl task::Unpark for DummyUnpark {
        fn unpark(&self) {}
    }

    #[derive(Default)]
    struct TestTask {
        data: Arc<Cell<u8>>,
        executor: TaskExecutorQueue<TestTask, ()>,
    }

    impl TaskExecutor for TestTask {
        type Error = ();

        fn task_executor_mut(&mut self) -> &mut TaskExecutorQueue<Self, Self::Error> {
            &mut self.executor
        }
    }

    #[test]
    fn simple_no_future() {
        let mut task = TestTask::default();
        assert_eq!(Ok(Async::Ready(())), task.poll());
    }

    #[test]
    fn simple_empty_future() {
        let mut task = TestTask::default();

        task.spawn(empty().into_tasked());

        assert_eq!(Ok(Async::NotReady), task.poll());
    }

    #[test]
    fn simeple_oneshot() {
        let (c, p) = oneshot();

        let mut task = TestTask::default();
        task.spawn(p.map_err(|_| ()).into_tasked());

        let mut task = task::spawn(task.into_future());

        assert_eq!(Ok(Async::NotReady), task.poll_future(Arc::new(DummyUnpark)));

        c.complete(());

        assert_eq!(Ok(Async::Ready(())), task.poll_future(Arc::new(DummyUnpark)));
    }

    #[test]
    fn map() {
        let (c, p) = oneshot();

        let mut task = TestTask::default();
        task.spawn(
            p.map_err(|_| ())
                .into_tasked::<TestTask>()
                .map(|res, task| task.data.set(res))
        );

        let data = task.data.clone();
        let mut task = task::spawn(task.into_future());

        assert_eq!(Ok(Async::NotReady), task.poll_future(Arc::new(DummyUnpark)));
        assert_eq!(data.get(), 0);

        c.complete(2u8);

        assert_eq!(Ok(Async::Ready(())), task.poll_future(Arc::new(DummyUnpark)));
        assert_eq!(data.get(), 2);
    }

    #[test]
    fn and_then() {
        let (c, p) = oneshot();

        let mut task = TestTask::default();
        task.spawn(
            p.map_err(|_| ())
                .into_tasked::<TestTask>()
                .and_then(|_, _| {
                    lazy(|| Ok(2u8))
                        .map_err(|_: ()| ())
                        .into_tasked::<TestTask>()
                        .map(|res, task| task.data.set(res))
                })
        );

        let data = task.data.clone();
        let mut task = task::spawn(task.into_future());

        assert_eq!(Ok(Async::NotReady), task.poll_future(Arc::new(DummyUnpark)));
        assert_eq!(data.get(), 0);

        c.complete(2u8);

        assert_eq!(Ok(Async::Ready(())), task.poll_future(Arc::new(DummyUnpark)));
        assert_eq!(data.get(), 2);
    }

    #[test]
    fn spawn() {
        let mut task = TestTask::default();
        task.spawn(
            lazy(|| Ok(()))
                .map_err(|_: ()| ())
                .into_tasked::<TestTask>()
                .map(|_, task| {
                    task.spawn(
                        lazy(|| Ok(2u8))
                            .map_err(|_: ()| ())
                            .into_tasked::<TestTask>()
                            .map(|res, task| task.data.set(res))
                    )
                })
        );

        let data = task.data.clone();
        let mut task = task::spawn(task.into_future());

        assert_eq!(data.get(), 0u8);
        while let Async::NotReady = task.poll_future(Arc::new(DummyUnpark)).unwrap() {}
        assert_eq!(data.get(), 2u8);
    }

    #[test]
    fn fnmut() {
        let mut task = TestTask::default();
        task.spawn_fn(|task| {
            task.data.set(task.data.get() + 1);
            Ok(Async::NotReady)
        });

        let data = task.data.clone();
        assert_eq!(Ok(Async::NotReady), task.poll());
        assert_eq!(data.get(), 1);
        assert_eq!(Ok(Async::NotReady), task.poll());
        assert_eq!(data.get(), 2);
    }
}
<commit_msg>Add stop on TaskExecutor<commit_after>extern crate futures;

use futures::{Async, Future, Poll};

use std::marker::PhantomData;
use std::mem;

mod and_then;
mod chain;
mod map;

pub use and_then::AndThen;
pub use map::TaskedMap;

pub trait TaskedFuture {
    type Item;
    type Error;
    type Task;

    fn poll(&mut self, t: &mut Self::Task) -> Poll<Self::Item, Self::Error>;

    fn map<F, U>(self, f: F) -> TaskedMap<Self, F> where F: FnOnce(Self::Item, &mut Self::Task) -> U, Self: Sized {
        map::new(self, f)
    }

    fn and_then<F, B>(self, f: F) -> AndThen<Self, B, F>
        where F: FnOnce(Self::Item, &mut Self::Task) -> B,
              B: IntoTaskedFuture<Error = Self::Error, Task=Self::Task>,
              Self: Sized,
    {
        and_then::new(self, f)
    }

}

struct FnWrapper<F, T, R, E> where F: FnMut(&mut T) -> Poll<R, E> {
    func: F,
    _phantom_data: PhantomData<(T, R, E)>,
}

impl<F, T, R, E> FnWrapper<F, T, R, E> where F: FnMut(&mut T) -> Poll<R, E> {
    pub fn new(f: F) -> FnWrapper<F, T, R, E> {
        FnWrapper {
            func: f,
            _phantom_data: PhantomData,
        }
    }
}

impl<F, T, R, E> TaskedFuture for FnWrapper<F, T, R, E> where F: FnMut(&mut T) -> Poll<R, E> {
    type Item = R;
    type Error = E;
    type Task = T;

    fn poll(&mut self, task: &mut Self::Task) -> Poll<Self::Item, Self::Error> {
        (self.func)(task)
    }
}

pub trait IntoTaskedFuture {
    /// The future that this type can be converted into.
    type TaskedFuture: TaskedFuture<Item=Self::Item, Error=Self::Error, Task=Self::Task>;

    type Item;
    type Error;
    type Task;

    fn into_tasked_future(self) -> Self::TaskedFuture;
}

impl<T> IntoTaskedFuture for T where T: TaskedFuture {
    type TaskedFuture = Self;

    type Item = <Self as TaskedFuture>::Item;
    type Error = <Self as TaskedFuture>::Error;
    type Task = <Self as TaskedFuture>::Task;

    fn into_tasked_future(self) -> Self::TaskedFuture {
        self
    }
}

pub trait FutureTaskedExt: Future + Sized {
    fn into_tasked<T>(self) -> TaskedFutureAdaptor<Self, T> {
        TaskedFutureAdaptor::new(self)
    }
}

impl<F: Future + Sized> FutureTaskedExt for F {}

pub struct TaskedFutureAdaptor<F, T> {
    future: F,
    _phantom_data: PhantomData<T>,
}

impl<F, T> TaskedFutureAdaptor<F, T> {
    pub fn new(future: F) -> TaskedFutureAdaptor<F, T> {
        TaskedFutureAdaptor {
            future: future,
            _phantom_data: PhantomData,
        }
    }
}

impl<F, I, E, T> TaskedFuture for TaskedFutureAdaptor<F, T> where F: Future<Item=I, Error=E> {
    type Item = I;
    type Error = E;
    type Task = T;

    fn poll(&mut self, _task: &mut Self::Task) -> Poll<I, E> {
        self.future.poll()
    }
}

type BoxedExecutorFuture<T, E> = Box<TaskedFuture<Item=(), Error=E, Task=T>>;

pub struct TaskExecutorQueue<T, E> {
    queue: Vec<BoxedExecutorFuture<T, E>>,
    stopped: bool,
}

impl<T, E> TaskExecutorQueue<T, E> {
    pub fn new() -> TaskExecutorQueue<T, E> {
        TaskExecutorQueue {
            queue: Vec::new(),
            stopped: false,
        }
    }

    pub fn stop(&mut self) {
        self.queue.clear();
        self.stopped = true;
    }

    pub fn is_stopped(&self) -> bool {
        self.stopped
    }
}

impl<T, E> Default for TaskExecutorQueue<T, E> {
    fn default() -> TaskExecutorQueue<T, E> {
        TaskExecutorQueue::new()
    }
}

pub trait TaskExecutor: Sized + 'static {
    type Error;

    fn task_executor_mut(&mut self) -> &mut TaskExecutorQueue<Self, Self::Error>;

    fn stop(&mut self) {
        self.task_executor_mut().stop();
    }

    fn spawn<F>(&mut self, future: F) where F: IntoTaskedFuture<Item=(), Error=Self::Error, Task=Self> + 'static {
        if !self.task_executor_mut().is_stopped() {
            self.task_executor_mut().queue.push(Box::new(future.into_tasked_future()));
        }
    }

    fn spawn_fn<F>(&mut self, func: F) where F: FnMut(&mut Self) -> Poll<(), Self::Error> + 'static {
        if !self.task_executor_mut().is_stopped() {
            self.task_executor_mut().queue.push(Box::new(FnWrapper::new(func)));
        }
    }

    fn poll(&mut self) -> Poll<(), Self::Error> {
        if self.task_executor_mut().is_stopped() {
            return Ok(Async::Ready(()));
        }

        let len = self.task_executor_mut().queue.len();
        let queue = mem::replace(&mut self.task_executor_mut().queue, Vec::with_capacity(len));

        let mut to_append = Vec::with_capacity(len);
        for mut future in queue {
            if let Async::NotReady = try!(future.poll(self)) {
                to_append.push(future);
            }
        }

        self.task_executor_mut().queue.append(&mut to_append);

        if self.task_executor_mut().queue.is_empty() {
            Ok(Async::Ready(()))
        } else {
            Ok(Async::NotReady)
        }
    }

    fn into_future(self) -> TaskExecutorFuture<Self> {
        TaskExecutorFuture { inner: self }
    }
}

pub struct TaskExecutorFuture<T> {
    inner: T
}

impl<T, E> Future for TaskExecutorFuture<T> where T: TaskExecutor<Error=E> {
    type Item = ();
    type Error = E;

    fn poll(&mut self) -> Poll<(), Self::Error> {
        self.inner.poll()
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use futures::{Async, Future, empty, oneshot, task, lazy};
    use std::sync::Arc;
    use std::cell::Cell;

    struct DummyUnpark;

    impl task::Unpark for DummyUnpark {
        fn unpark(&self) {}
    }

    #[derive(Default)]
    struct TestTask {
        data: Arc<Cell<u8>>,
        executor: TaskExecutorQueue<TestTask, ()>,
    }

    impl TaskExecutor for TestTask {
        type Error = ();

        fn task_executor_mut(&mut self) -> &mut TaskExecutorQueue<Self, Self::Error> {
            &mut self.executor
        }
    }

    #[test]
    fn simple_no_future() {
        let mut task = TestTask::default();
        assert_eq!(Ok(Async::Ready(())), task.poll());
    }

    #[test]
    fn simple_empty_future() {
        let mut task = TestTask::default();

        task.spawn(empty().into_tasked());

        assert_eq!(Ok(Async::NotReady), task.poll());
    }

    #[test]
    fn simeple_oneshot() {
        let (c, p) = oneshot();

        let mut task = TestTask::default();
        task.spawn(p.map_err(|_| ()).into_tasked());

        let mut task = task::spawn(task.into_future());

        assert_eq!(Ok(Async::NotReady), task.poll_future(Arc::new(DummyUnpark)));

        c.complete(());

        assert_eq!(Ok(Async::Ready(())), task.poll_future(Arc::new(DummyUnpark)));
    }

    #[test]
    fn map() {
        let (c, p) = oneshot();

        let mut task = TestTask::default();
        task.spawn(
            p.map_err(|_| ())
                .into_tasked::<TestTask>()
                .map(|res, task| task.data.set(res))
        );

        let data = task.data.clone();
        let mut task = task::spawn(task.into_future());

        assert_eq!(Ok(Async::NotReady), task.poll_future(Arc::new(DummyUnpark)));
        assert_eq!(data.get(), 0);

        c.complete(2u8);

        assert_eq!(Ok(Async::Ready(())), task.poll_future(Arc::new(DummyUnpark)));
        assert_eq!(data.get(), 2);
    }

    #[test]
    fn and_then() {
        let (c, p) = oneshot();

        let mut task = TestTask::default();
        task.spawn(
            p.map_err(|_| ())
                .into_tasked::<TestTask>()
                .and_then(|_, _| {
                    lazy(|| Ok(2u8))
                        .map_err(|_: ()| ())
                        .into_tasked::<TestTask>()
                        .map(|res, task| task.data.set(res))
                })
        );

        let data = task.data.clone();
        let mut task = task::spawn(task.into_future());

        assert_eq!(Ok(Async::NotReady), task.poll_future(Arc::new(DummyUnpark)));
        assert_eq!(data.get(), 0);

        c.complete(2u8);

        assert_eq!(Ok(Async::Ready(())), task.poll_future(Arc::new(DummyUnpark)));
        assert_eq!(data.get(), 2);
    }

    #[test]
    fn spawn() {
        let mut task = TestTask::default();
        task.spawn(
            lazy(|| Ok(()))
                .map_err(|_: ()| ())
                .into_tasked::<TestTask>()
                .map(|_, task| {
                    task.spawn(
                        lazy(|| Ok(2u8))
                            .map_err(|_: ()| ())
                            .into_tasked::<TestTask>()
                            .map(|res, task| task.data.set(res))
                    )
                })
        );

        let data = task.data.clone();
        let mut task = task::spawn(task.into_future());

        assert_eq!(data.get(), 0u8);
        while let Async::NotReady = task.poll_future(Arc::new(DummyUnpark)).unwrap() {}
        assert_eq!(data.get(), 2u8);
    }

    #[test]
    fn fnmut() {
        let mut task = TestTask::default();
        task.spawn_fn(|task| {
            task.data.set(task.data.get() + 1);
            Ok(Async::NotReady)
        });

        let data = task.data.clone();
        assert_eq!(Ok(Async::NotReady), task.poll());
        assert_eq!(data.get(), 1);
        assert_eq!(Ok(Async::NotReady), task.poll());
        assert_eq!(data.get(), 2);
    }
}
<|endoftext|>


<commit_before>/*! A library for the hyphenation of UTF-8 strings

## Usage

A typical import comprises the [`Hyphenator`] trait, the [`Standard`]
dictionary type, and the [`Language`] enum. This exposes the crate's core
functionality, as well as the set of available languages.

```no_run
extern crate hyphenation;

use hyphenation::{Hyphenator, Standard, Language};
```

To begin with, we must initiate the hyphenation dictionary for our working
language. Dictionaries come bundled with the `hyphenation` crate, but they
must still be loaded into memory. The most convenient way to do so is the
[`Load`] trait.

```ignore
use hyphenation::Load;

let path_to_dict = "/path/to/english-dictionary.bincode";
let en_us = Standard::from_path(Language::EnglishUS, path_to_dict) ?;
```

Our English dictionary can now be used as a [`Hyphenator`].

### Hyphenators

As the primary interface of this library, hyphenators take care of identifying
opportunities for hyphenation within individual words.

```ignore
let hyphenated = en_us.hyphenate("anfractuous");
```

The [`hyphenate`] method computes the indices of valid word breaks and wraps
them in a a small intermediate structure that can be further used to [iterate]
over word segments.

```ignore
let breaks = &hyphenated.breaks;
assert_eq!(breaks, &[2, 6, 8]);

let hyphenated_segments : Vec<&str>= hyphenated.iter().collect()
assert_eq!(hyphenated_segments, &["an-", "frac-", "tu-", "ous"]);
```

Both the [`Standard`] and [`Extended`] hyphenators are case-insensitive and
prioritize existing soft hyphens (U+00AD) over dictionary hyphenation.

```ignore
let word = "ribonuclease";
let word_shy = "ri\u{00ad}bo\u{00ad}nu\u{00ad}cle\u{00ad}ase";

let by_dictionary : Vec<&str> = en_us.hyphenate(word).into_iter().segments().collect();
let by_shy : Vec<&str> = en_us.hyphenate(word_shy).into_iter().segments().collect();

assert_eq!(by_dictionary, vec!["ri", "bonu", "cle", "ase"]);
assert_eq!(by_shy, vec!["ri", "\u{00ad}bo", "\u{00ad}nu", "\u{00ad}cle", "\u{00ad}ase"]);
assert_ne!(by_dictionary, by_shy);
```

## Identifying "words"

Knuth–Liang hyphenation operates at the level of individual words, but there
can be ambiguity as to what constitutes a *word*. All hyphenation dictionaries
handle the expected set of word-forming graphemes from their respective
alphabets, but some also accept punctuation marks such as hyphens and
apostrophes, and are thus capable of handling hyphen-joined compound words or
elisions. Even so, it's generally preferable to handle punctuation at the
level of segmentation, as it affords greater control over the final result
(such as where to break hyphen-joined compounds, or whether to set a leading
hyphen on new lines).

[`Hyphenator`]: hyphenator/trait.Hyphenator.html
[`Standard`]: struct.Standard.html
[`Language`]: enum.Language.html
[`Load`]: load/trait.Load.html
[`hyphenate`]: hyphenator/trait.Hyphenator#tymethod.hyphenate.html
[iterate]: iter/struct.Hyphenating.html
[`Extended`]: extended/struct.Extended.html
*/

extern crate fst;
extern crate bincode;
extern crate hyphenation_commons;

#[cfg(any(feature = "embed_all", feature = "embed_en-us"))] mod resources;
mod case_folding;
pub mod hyphenator;
pub mod extended;
pub mod iter;
pub mod load;
pub mod score;

pub use hyphenation_commons::Language;
pub use hyphenation_commons::dictionary::Standard;
pub use hyphenator::Hyphenator;
pub use iter::Iter;
pub use load::Load;
<commit_msg>Forbid unsafe<commit_after>/*! A library for the hyphenation of UTF-8 strings

## Usage

A typical import comprises the [`Hyphenator`] trait, the [`Standard`]
dictionary type, and the [`Language`] enum. This exposes the crate's core
functionality, as well as the set of available languages.

```no_run
extern crate hyphenation;

use hyphenation::{Hyphenator, Standard, Language};
```

To begin with, we must initiate the hyphenation dictionary for our working
language. Dictionaries come bundled with the `hyphenation` crate, but they
must still be loaded into memory. The most convenient way to do so is the
[`Load`] trait.

```ignore
use hyphenation::Load;

let path_to_dict = "/path/to/english-dictionary.bincode";
let en_us = Standard::from_path(Language::EnglishUS, path_to_dict) ?;
```

Our English dictionary can now be used as a [`Hyphenator`].

### Hyphenators

As the primary interface of this library, hyphenators take care of identifying
opportunities for hyphenation within individual words.

```ignore
let hyphenated = en_us.hyphenate("anfractuous");
```

The [`hyphenate`] method computes the indices of valid word breaks and wraps
them in a a small intermediate structure that can be further used to [iterate]
over word segments.

```ignore
let breaks = &hyphenated.breaks;
assert_eq!(breaks, &[2, 6, 8]);

let hyphenated_segments : Vec<&str>= hyphenated.iter().collect()
assert_eq!(hyphenated_segments, &["an-", "frac-", "tu-", "ous"]);
```

Both the [`Standard`] and [`Extended`] hyphenators are case-insensitive and
prioritize existing soft hyphens (U+00AD) over dictionary hyphenation.

```ignore
let word = "ribonuclease";
let word_shy = "ri\u{00ad}bo\u{00ad}nu\u{00ad}cle\u{00ad}ase";

let by_dictionary : Vec<&str> = en_us.hyphenate(word).into_iter().segments().collect();
let by_shy : Vec<&str> = en_us.hyphenate(word_shy).into_iter().segments().collect();

assert_eq!(by_dictionary, vec!["ri", "bonu", "cle", "ase"]);
assert_eq!(by_shy, vec!["ri", "\u{00ad}bo", "\u{00ad}nu", "\u{00ad}cle", "\u{00ad}ase"]);
assert_ne!(by_dictionary, by_shy);
```

## Identifying "words"

Knuth–Liang hyphenation operates at the level of individual words, but there
can be ambiguity as to what constitutes a *word*. All hyphenation dictionaries
handle the expected set of word-forming graphemes from their respective
alphabets, but some also accept punctuation marks such as hyphens and
apostrophes, and are thus capable of handling hyphen-joined compound words or
elisions. Even so, it's generally preferable to handle punctuation at the
level of segmentation, as it affords greater control over the final result
(such as where to break hyphen-joined compounds, or whether to set a leading
hyphen on new lines).

[`Hyphenator`]: hyphenator/trait.Hyphenator.html
[`Standard`]: struct.Standard.html
[`Language`]: enum.Language.html
[`Load`]: load/trait.Load.html
[`hyphenate`]: hyphenator/trait.Hyphenator#tymethod.hyphenate.html
[iterate]: iter/struct.Hyphenating.html
[`Extended`]: extended/struct.Extended.html
*/

#![forbid(unsafe_code)]

extern crate fst;
extern crate bincode;
extern crate hyphenation_commons;

#[cfg(any(feature = "embed_all", feature = "embed_en-us"))] mod resources;
mod case_folding;
pub mod hyphenator;
pub mod extended;
pub mod iter;
pub mod load;
pub mod score;

pub use hyphenation_commons::Language;
pub use hyphenation_commons::dictionary::Standard;
pub use hyphenator::Hyphenator;
pub use iter::Iter;
pub use load::Load;
<|endoftext|>


<commit_before>#![warn(missing_copy_implementations)]
#![warn(missing_debug_implementations)]
#![warn(trivial_casts)]
#![warn(trivial_numeric_casts)]
#![warn(unused_extern_crates)]
#![warn(unused_import_braces)]
#![warn(unused_qualifications)]
#![warn(unused_results)]

#![feature(plugin_registrar)]
#![feature(rustc_private)]
#![feature(quote)]

extern crate syntax;
extern crate rustc;

use syntax::ast::MetaWord;
use rustc::plugin::Registry;

mod expand;
mod convert;

struct Arg {
    override_builtins: bool,
}

impl Default for Arg {
    fn default() -> Arg {
        Arg { override_builtins: false }
    }
}

impl Arg {
    fn parse(reg: &mut Registry) -> Arg {
        let mut result = Arg::default();

        for arg in reg.args() {
            match arg.node {
                MetaWord(ref ns) => {
                    match &**ns {
                        "override_builtins" => {
                            result.override_builtins = true;
                        }
                        _ => {
                            reg.sess.span_err(arg.span, "invalid argument");
                        }
                    }
                }
                _ => {
                    reg.sess.span_err(arg.span, "invalid argument");
                }
            }
        }

        result
    }
}

#[plugin_registrar]
pub fn plugin_registrar(reg: &mut Registry) {
    let arg = Arg::parse(reg);

    if arg.override_builtins {
        reg.register_macro("assert", expand::expand_assert);
        reg.register_macro("assert_eq", expand::expand_assert_eq);
    }

    reg.register_macro("power_assert", expand::expand_assert);
    reg.register_macro("power_assert_eq", expand::expand_assert_eq);
}
<commit_msg>update to rustc 1.6.0-nightly (1727dee16 2015-11-26)<commit_after>#![warn(missing_copy_implementations)]
#![warn(missing_debug_implementations)]
#![warn(trivial_casts)]
#![warn(trivial_numeric_casts)]
#![warn(unused_extern_crates)]
#![warn(unused_import_braces)]
#![warn(unused_qualifications)]
#![warn(unused_results)]

#![feature(plugin_registrar)]
#![feature(rustc_private)]
#![feature(quote)]

extern crate syntax;
extern crate rustc_plugin;

use syntax::ast::MetaWord;
use rustc_plugin::Registry;

mod expand;
mod convert;

struct Arg {
    override_builtins: bool,
}

impl Default for Arg {
    fn default() -> Arg {
        Arg { override_builtins: false }
    }
}

impl Arg {
    fn parse(reg: &mut Registry) -> Arg {
        let mut result = Arg::default();

        for arg in reg.args() {
            match arg.node {
                MetaWord(ref ns) => {
                    match &**ns {
                        "override_builtins" => {
                            result.override_builtins = true;
                        }
                        _ => {
                            reg.sess.span_err(arg.span, "invalid argument");
                        }
                    }
                }
                _ => {
                    reg.sess.span_err(arg.span, "invalid argument");
                }
            }
        }

        result
    }
}

#[plugin_registrar]
pub fn plugin_registrar(reg: &mut Registry) {
    let arg = Arg::parse(reg);

    if arg.override_builtins {
        reg.register_macro("assert", expand::expand_assert);
        reg.register_macro("assert_eq", expand::expand_assert_eq);
    }

    reg.register_macro("power_assert", expand::expand_assert);
    reg.register_macro("power_assert_eq", expand::expand_assert_eq);
}
<|endoftext|>


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

//! A bare-metal library supplying functions rustc may lower code to
//!
//! This library is not intended for general use, and is superseded by a system
//! libc if one is available. In a freestanding context, however, common
//! functions such as memset, memcpy, etc are not implemented. This library
//! provides an implementation of these functions which are either required by
//! libcore or called by rustc implicitly.
//!
//! This library is never included by default, and must be manually included if
//! necessary. It is an error to include this library when also linking with
//! the system libc library.

#![no_std]

// This library defines the builtin functions, so it would be a shame for
// LLVM to optimize these function calls to themselves!
#![no_builtins]

#[cfg(test)] #[macro_use] extern crate std;

#[no_mangle]
pub unsafe extern fn memcpy(dest: *mut u8, src: *const u8,
                            n: usize) -> *mut u8 {
    let mut i = 0;
    while i < n {
        *dest.offset(i as isize) = *src.offset(i as isize);
        i += 1;
    }
    return dest;
}

#[no_mangle]
pub unsafe extern fn memmove(dest: *mut u8, src: *const u8,
                             n: usize) -> *mut u8 {
    if src < dest as *const u8 { // copy from end
        let mut i = n;
        while i != 0 {
            i -= 1;
            *dest.offset(i as isize) = *src.offset(i as isize);
        }
    } else { // copy from beginning
        let mut i = 0;
        while i < n {
            *dest.offset(i as isize) = *src.offset(i as isize);
            i += 1;
        }
    }
    return dest;
}

#[no_mangle]
pub unsafe extern fn memset(s: *mut u8, c: i32, n: usize) -> *mut u8 {
    let mut i = 0;
    while i < n {
        *s.offset(i as isize) = c as u8;
        i += 1;
    }
    return s;
}

#[no_mangle]
pub unsafe extern fn memcmp(s1: *const u8, s2: *const u8, n: usize) -> i32 {
    let mut i = 0;
    while i < n {
        let a = *s1.offset(i as isize);
        let b = *s2.offset(i as isize);
        if a != b {
            return a as i32 - b as i32
        }
        i += 1;
    }
    return 0;
}

#[cfg(test)]
mod test {
    use super::{memcmp, memset, memcpy, memmove};

    #[test]
    fn memcmp_single_byte_pointers() {
        unsafe {
            assert_eq!(memcmp(&0xFAu8, &0xFAu8, 1), 0x00);
            assert!(memcmp(&0xEFu8, &0xFEu8, 1) < 0x00);
        }
    }

    #[test]
    fn memcmp_strings() {
        {
            let (x, z) = ("Hello!", "Good Bye.");
            let l = x.len();
            unsafe {
                assert_eq!(memcmp(x.as_ptr(), x.as_ptr(), l), 0);
                assert!(memcmp(x.as_ptr(), z.as_ptr(), l) > 0);
                assert!(memcmp(z.as_ptr(), x.as_ptr(), l) < 0);
            }
        }
        {
            let (x, z) = ("hey!", "hey.");
            let l = x.len();
            unsafe {
                assert!(memcmp(x.as_ptr(), z.as_ptr(), l) < 0);
            }
        }
    }

    #[test]
    fn memset_single_byte_pointers() {
        let mut x: u8 = 0xFF;
        unsafe {
            memset(&mut x, 0xAA, 1);
            assert_eq!(x, 0xAA);
            memset(&mut x, 0x00, 1);
            assert_eq!(x, 0x00);
            x = 0x01;
            memset(&mut x, 0x12, 0);
            assert_eq!(x, 0x01);
        }
    }

    #[test]
    fn memset_array() {
        let mut buffer = [b'X';  100];
        unsafe {
            memset(buffer.as_mut_ptr(), b'#' as i32, buffer.len());
        }
        for byte in buffer.iter() { assert_eq!(*byte, b'#'); }
    }

    #[test]
    fn memcpy_and_memcmp_arrays() {
        let (src, mut dst) = ([b'X';  100], [b'Y';  100]);
        unsafe {
            assert!(memcmp(src.as_ptr(), dst.as_ptr(), 100) != 0);
            let _ = memcpy(dst.as_mut_ptr(), src.as_ptr(), 100);
            assert_eq!(memcmp(src.as_ptr(), dst.as_ptr(), 100), 0);
        }
    }

    #[test]
    fn memmove_overlapping() {
        {
            let mut buffer = [ b'0', b'1', b'2', b'3', b'4', b'5', b'6', b'7', b'8', b'9' ];
            unsafe {
                memmove(&mut buffer[4], &buffer[0], 6);
                let mut i = 0;
                for byte in b"0123012345".iter() {
                    assert_eq!(buffer[i], *byte);
                    i += 1;
                }
            }
        }
        {
            let mut buffer = [ b'0', b'1', b'2', b'3', b'4', b'5', b'6', b'7', b'8', b'9' ];
            unsafe {
                memmove(&mut buffer[0], &buffer[4], 6);
                let mut i = 0;
                for byte in b"4567896789".iter() {
                    assert_eq!(buffer[i], *byte);
                    i += 1;
                }
            }
        }
    }
}
<commit_msg>Remove unneeded extern crate std<commit_after>// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! A bare-metal library supplying functions rustc may lower code to
//!
//! This library is not intended for general use, and is superseded by a system
//! libc if one is available. In a freestanding context, however, common
//! functions such as memset, memcpy, etc are not implemented. This library
//! provides an implementation of these functions which are either required by
//! libcore or called by rustc implicitly.
//!
//! This library is never included by default, and must be manually included if
//! necessary. It is an error to include this library when also linking with
//! the system libc library.

#![no_std]

// This library defines the builtin functions, so it would be a shame for
// LLVM to optimize these function calls to themselves!
#![no_builtins]

#[no_mangle]
pub unsafe extern fn memcpy(dest: *mut u8, src: *const u8,
                            n: usize) -> *mut u8 {
    let mut i = 0;
    while i < n {
        *dest.offset(i as isize) = *src.offset(i as isize);
        i += 1;
    }
    return dest;
}

#[no_mangle]
pub unsafe extern fn memmove(dest: *mut u8, src: *const u8,
                             n: usize) -> *mut u8 {
    if src < dest as *const u8 { // copy from end
        let mut i = n;
        while i != 0 {
            i -= 1;
            *dest.offset(i as isize) = *src.offset(i as isize);
        }
    } else { // copy from beginning
        let mut i = 0;
        while i < n {
            *dest.offset(i as isize) = *src.offset(i as isize);
            i += 1;
        }
    }
    return dest;
}

#[no_mangle]
pub unsafe extern fn memset(s: *mut u8, c: i32, n: usize) -> *mut u8 {
    let mut i = 0;
    while i < n {
        *s.offset(i as isize) = c as u8;
        i += 1;
    }
    return s;
}

#[no_mangle]
pub unsafe extern fn memcmp(s1: *const u8, s2: *const u8, n: usize) -> i32 {
    let mut i = 0;
    while i < n {
        let a = *s1.offset(i as isize);
        let b = *s2.offset(i as isize);
        if a != b {
            return a as i32 - b as i32
        }
        i += 1;
    }
    return 0;
}

#[cfg(test)]
mod test {
    use super::{memcmp, memset, memcpy, memmove};

    #[test]
    fn memcmp_single_byte_pointers() {
        unsafe {
            assert_eq!(memcmp(&0xFAu8, &0xFAu8, 1), 0x00);
            assert!(memcmp(&0xEFu8, &0xFEu8, 1) < 0x00);
        }
    }

    #[test]
    fn memcmp_strings() {
        {
            let (x, z) = ("Hello!", "Good Bye.");
            let l = x.len();
            unsafe {
                assert_eq!(memcmp(x.as_ptr(), x.as_ptr(), l), 0);
                assert!(memcmp(x.as_ptr(), z.as_ptr(), l) > 0);
                assert!(memcmp(z.as_ptr(), x.as_ptr(), l) < 0);
            }
        }
        {
            let (x, z) = ("hey!", "hey.");
            let l = x.len();
            unsafe {
                assert!(memcmp(x.as_ptr(), z.as_ptr(), l) < 0);
            }
        }
    }

    #[test]
    fn memset_single_byte_pointers() {
        let mut x: u8 = 0xFF;
        unsafe {
            memset(&mut x, 0xAA, 1);
            assert_eq!(x, 0xAA);
            memset(&mut x, 0x00, 1);
            assert_eq!(x, 0x00);
            x = 0x01;
            memset(&mut x, 0x12, 0);
            assert_eq!(x, 0x01);
        }
    }

    #[test]
    fn memset_array() {
        let mut buffer = [b'X';  100];
        unsafe {
            memset(buffer.as_mut_ptr(), b'#' as i32, buffer.len());
        }
        for byte in buffer.iter() { assert_eq!(*byte, b'#'); }
    }

    #[test]
    fn memcpy_and_memcmp_arrays() {
        let (src, mut dst) = ([b'X';  100], [b'Y';  100]);
        unsafe {
            assert!(memcmp(src.as_ptr(), dst.as_ptr(), 100) != 0);
            let _ = memcpy(dst.as_mut_ptr(), src.as_ptr(), 100);
            assert_eq!(memcmp(src.as_ptr(), dst.as_ptr(), 100), 0);
        }
    }

    #[test]
    fn memmove_overlapping() {
        {
            let mut buffer = [ b'0', b'1', b'2', b'3', b'4', b'5', b'6', b'7', b'8', b'9' ];
            unsafe {
                memmove(&mut buffer[4], &buffer[0], 6);
                let mut i = 0;
                for byte in b"0123012345".iter() {
                    assert_eq!(buffer[i], *byte);
                    i += 1;
                }
            }
        }
        {
            let mut buffer = [ b'0', b'1', b'2', b'3', b'4', b'5', b'6', b'7', b'8', b'9' ];
            unsafe {
                memmove(&mut buffer[0], &buffer[4], 6);
                let mut i = 0;
                for byte in b"4567896789".iter() {
                    assert_eq!(buffer[i], *byte);
                    i += 1;
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>//! which
//!
//! A Rust equivalent of Unix command `which(1)`.
//! # Example:
//!
//! To find which rustc executable binary is using:
//!
//! ``` norun
//! use which::which;
//!
//! let result = which::which("rustc").unwrap();
//! assert_eq!(result, PathBuf::from("/usr/bin/rustc"));
//!
//! ```

extern crate libc;
#[cfg(test)]
extern crate tempdir;

use std::path::{Path, PathBuf};
use std::{env, fs};
use std::ascii::AsciiExt;
#[cfg(unix)]
use std::ffi::CString;
use std::ffi::OsStr;
#[cfg(unix)]
use std::os::unix::ffi::OsStrExt;

/// Like `Path::with_extension`, but don't replace an existing extension.
fn ensure_exe_extension<T: AsRef<Path>>(path: T) -> PathBuf {
    if env::consts::EXE_EXTENSION.is_empty() {
        // Nothing to do.
        path.as_ref().to_path_buf()
    } else {
        match path.as_ref()
            .extension()
            .and_then(|e| e.to_str())
            .map(|e| e.eq_ignore_ascii_case(env::consts::EXE_EXTENSION)) {
            // Already has the right extension.
            Some(true) => path.as_ref().to_path_buf(),
            _ => {
                // Append the extension.
                let mut s = path.as_ref().to_path_buf().into_os_string();
                s.push(".");
                s.push(env::consts::EXE_EXTENSION);
                PathBuf::from(s)
            }
        }
    }
}

/// Find a exectable binary's path by name.
///
/// If given an absolute path, returns it if the file exists and is executable.
///
/// If given a relative path, returns an absolute path to the file if
/// it exists and is executable.
///
/// If given a string without path separators, looks for a file named
/// `binary_name` at each directory in `$PATH` and if it finds an executable
/// file there, returns it.
///
/// # Example
///
/// ``` norun
/// use which::which;
/// use std::path::PathBuf;
///
/// let result = which::which("rustc").unwrap();
/// assert_eq!(result, PathBuf::from("/usr/bin/rustc"));
///
/// ```
pub fn which<T: AsRef<OsStr>>(binary_name: T) -> Result<PathBuf, &'static str> {
    env::current_dir()
        .or_else(|_| Err("Couldn't get current directory"))
        .and_then(|cwd| which_in(binary_name, env::var_os("PATH"), &cwd))
}

/// Find `binary_name` in the path list `paths`, using `cwd` to resolve relative paths.
pub fn which_in<T, U, V>(binary_name: T, paths: Option<U>, cwd: V) -> Result<PathBuf, &'static str>
    where T: AsRef<OsStr>,
          U: AsRef<OsStr>,
          V: AsRef<Path>
{
    let binary_checker = CompositeChecker::new()
        .add_checker(Box::new(ExistedChecker::new()))
        .add_checker(Box::new(ExecutableChecker::new()));

    let finder = Finder::new();

    finder.find(binary_name, paths, cwd, &binary_checker)
}

struct Finder;

impl Finder {
    fn new() -> Finder {
        Finder
    }

    fn find<T, U, V>(&self,
                     binary_name: T,
                     paths: Option<U>,
                     cwd: V,
                     binary_checker: &Checker)
                     -> Result<PathBuf, &'static str>
        where T: AsRef<OsStr>,
              U: AsRef<OsStr>,
              V: AsRef<Path>
    {

        let path = ensure_exe_extension(binary_name.as_ref());

        // Does it have a path separator?
        if path.components().count() > 1 {
            if path.is_absolute() {
                if binary_checker.is_valid(&path) {
                    // Already fine.
                    Ok(path)
                } else {
                    // Absolute path but it's not usable.
                    Err("Bad absolute path")
                }
            } else {
                // Try to make it absolute.
                let mut new_path = PathBuf::from(cwd.as_ref());
                new_path.push(path);
                let new_path = ensure_exe_extension(new_path);
                if binary_checker.is_valid(&new_path) {
                    Ok(new_path)
                } else {
                    // File doesn't exist or isn't executable.
                    Err("Bad relative path")
                }
            }
        } else {
            // No separator, look it up in `paths`.
            paths.and_then(|paths| {
                    env::split_paths(paths.as_ref())
                        .map(|p| ensure_exe_extension(p.join(binary_name.as_ref())))
                        .skip_while(|p| !(binary_checker.is_valid(&p)))
                        .next()
                })
                .ok_or("Cannot find binary path")
        }
    }
}

trait Checker {
    fn is_valid(&self, path: &Path) -> bool;
}

struct ExecutableChecker;

impl ExecutableChecker {
    fn new() -> ExecutableChecker {
        ExecutableChecker
    }
}

impl Checker for ExecutableChecker {
    #[cfg(unix)]
    fn is_valid(&self, path: &Path) -> bool {
        CString::new(path.as_os_str().as_bytes())
            .and_then(|c| Ok(unsafe { libc::access(c.as_ptr(), libc::X_OK) == 0 }))
            .unwrap_or(false)
    }

    #[cfg(not(unix))]
    fn is_valid(&self, _path: &Path) -> bool {
        true
    }
}

struct ExistedChecker;

impl ExistedChecker {
    fn new() -> ExistedChecker {
        ExistedChecker
    }
}

impl Checker for ExistedChecker {
    fn is_valid(&self, path: &Path) -> bool {
        fs::metadata(path)
            .map(|metadata| metadata.is_file())
            .unwrap_or(false)
    }
}

struct CompositeChecker {
    checkers: Vec<Box<Checker>>,
}

impl CompositeChecker {
    fn new() -> CompositeChecker {
        CompositeChecker { checkers: Vec::new() }
    }

    fn add_checker(mut self, checker: Box<Checker>) -> CompositeChecker {
        self.checkers.push(checker);
        self
    }
}

impl Checker for CompositeChecker {
    fn is_valid(&self, path: &Path) -> bool {
        self.checkers
            .iter()
            .all(|checker| checker.is_valid(path))
    }
}

#[test]
fn test_exe_extension() {
    let expected = PathBuf::from("foo").with_extension(env::consts::EXE_EXTENSION);
    assert_eq!(expected, ensure_exe_extension(PathBuf::from("foo")));
    let p = expected.clone();
    assert_eq!(expected, ensure_exe_extension(p));
}

#[test]
#[cfg(windows)]
fn test_exe_extension_existing_extension() {
    assert_eq!(PathBuf::from("foo.bar.exe"),
               ensure_exe_extension("foo.bar"));
}

#[test]
#[cfg(windows)]
fn test_exe_extension_existing_extension_uppercase() {
    assert_eq!(PathBuf::from("foo.EXE"), ensure_exe_extension("foo.EXE"));
}

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

    use std::env;
    use std::ffi::{OsStr, OsString};
    use std::fs;
    use std::io;
    use std::path::{Path, PathBuf};
    use tempdir::TempDir;

    struct TestFixture {
        /// Temp directory.
        pub tempdir: TempDir,
        /// $PATH
        pub paths: OsString,
        /// Binaries created in $PATH
        pub bins: Vec<PathBuf>,
    }

    const SUBDIRS: &'static [&'static str] = &["a", "b", "c"];
    const BIN_NAME: &'static str = "bin";

    #[cfg(unix)]
    fn mk_bin(dir: &Path, path: &str) -> io::Result<PathBuf> {
        use libc;
        use std::os::unix::fs::OpenOptionsExt;
        let bin = dir.join(path).with_extension(env::consts::EXE_EXTENSION);
        fs::OpenOptions::new()
            .write(true)
            .create(true)
            .mode(0o666 | (libc::S_IXUSR as u32))
            .open(&bin)
            .and_then(|_f| bin.canonicalize())
    }

    fn touch(dir: &Path, path: &str) -> io::Result<PathBuf> {
        let b = dir.join(path).with_extension(env::consts::EXE_EXTENSION);
        fs::File::create(&b).and_then(|_f| b.canonicalize())
    }

    #[cfg(not(unix))]
    fn mk_bin(dir: &Path, path: &str) -> io::Result<PathBuf> {
        touch(dir, path)
    }

    impl TestFixture {
        pub fn new() -> TestFixture {
            let tempdir = TempDir::new("which_tests").unwrap();
            let mut builder = fs::DirBuilder::new();
            builder.recursive(true);
            let mut paths = vec![];
            let mut bins = vec![];
            for d in SUBDIRS.iter() {
                let p = tempdir.path().join(d);
                builder.create(&p).unwrap();
                bins.push(mk_bin(&p, &BIN_NAME).unwrap());
                paths.push(p);
            }
            TestFixture {
                tempdir: tempdir,
                paths: env::join_paths(paths).unwrap(),
                bins: bins,
            }
        }

        #[allow(dead_code)]
        pub fn touch(&self, path: &str) -> io::Result<PathBuf> {
            touch(self.tempdir.path(), &path)
        }

        pub fn mk_bin(&self, path: &str) -> io::Result<PathBuf> {
            mk_bin(self.tempdir.path(), &path)
        }
    }

    fn _which<T: AsRef<OsStr>>(f: &TestFixture, path: T) -> Result<PathBuf, &'static str> {
        which_in(path, Some(f.paths.clone()), f.tempdir.path())
    }

    #[test]
    #[cfg(unix)]
    fn it_works() {
        use std::process::Command;
        let result = which("rustc");
        assert!(result.is_ok());

        let which_result = Command::new("which")
            .arg("rustc")
            .output();

        assert_eq!(String::from(result.unwrap().to_str().unwrap()),
                   String::from_utf8(which_result.unwrap().stdout).unwrap().trim());
    }

    #[test]
    fn test_which() {
        let f = TestFixture::new();
        assert_eq!(_which(&f, &BIN_NAME).unwrap().canonicalize().unwrap(),
                   f.bins[0])
    }

    #[test]
    fn test_which_extension() {
        let f = TestFixture::new();
        let b = Path::new(&BIN_NAME).with_extension(env::consts::EXE_EXTENSION);
        assert_eq!(_which(&f, &b).unwrap().canonicalize().unwrap(), f.bins[0])
    }

    #[test]
    fn test_which_not_found() {
        let f = TestFixture::new();
        assert!(_which(&f, "a").is_err());
    }

    #[test]
    fn test_which_second() {
        let f = TestFixture::new();
        let b = f.mk_bin("b/another").unwrap();
        assert_eq!(_which(&f, "another").unwrap().canonicalize().unwrap(), b);
    }

    #[test]
    fn test_which_absolute() {
        let f = TestFixture::new();
        assert_eq!(_which(&f, &f.bins[1]).unwrap().canonicalize().unwrap(),
                   f.bins[1].canonicalize().unwrap());
    }

    #[test]
    #[cfg(windows)]
    fn test_which_absolute_path_case() {
        // Test that an absolute path with an uppercase extension
        // is accepted.
        let f = TestFixture::new();
        let p = f.bins[1].with_extension("EXE");
        assert_eq!(_which(&f, &p).unwrap().canonicalize().unwrap(),
                   f.bins[1].canonicalize().unwrap());
    }

    #[test]
    fn test_which_absolute_extension() {
        let f = TestFixture::new();
        // Don't append EXE_EXTENSION here.
        let b = f.bins[1].parent().unwrap().join(&BIN_NAME);
        assert_eq!(_which(&f, &b).unwrap().canonicalize().unwrap(),
                   f.bins[1].canonicalize().unwrap());
    }

    #[test]
    fn test_which_relative() {
        let f = TestFixture::new();
        assert_eq!(_which(&f, "b/bin").unwrap().canonicalize().unwrap(),
                   f.bins[1].canonicalize().unwrap());
    }

    #[test]
    fn test_which_relative_extension() {
        // test_which_relative tests a relative path without an extension,
        // so test a relative path with an extension here.
        let f = TestFixture::new();
        let b = Path::new("b/bin").with_extension(env::consts::EXE_EXTENSION);
        assert_eq!(_which(&f, &b).unwrap().canonicalize().unwrap(),
                   f.bins[1].canonicalize().unwrap());
    }

    #[test]
    #[cfg(windows)]
    fn test_which_relative_extension_case() {
        // Test that a relative path with an uppercase extension
        // is accepted.
        let f = TestFixture::new();
        let b = Path::new("b/bin").with_extension("EXE");
        assert_eq!(_which(&f, &b).unwrap().canonicalize().unwrap(),
                   f.bins[1].canonicalize().unwrap());
    }

    #[test]
    fn test_which_relative_leading_dot() {
        let f = TestFixture::new();
        assert_eq!(_which(&f, "./b/bin").unwrap().canonicalize().unwrap(),
                   f.bins[1].canonicalize().unwrap());
    }

    #[test]
    #[cfg(unix)]
    fn test_which_non_executable() {
        // Shouldn't return non-executable files.
        let f = TestFixture::new();
        f.touch("b/another").unwrap();
        assert!(_which(&f, "another").is_err());
    }

    #[test]
    #[cfg(unix)]
    fn test_which_absolute_non_executable() {
        // Shouldn't return non-executable files, even if given an absolute path.
        let f = TestFixture::new();
        let b = f.touch("b/another").unwrap();
        assert!(_which(&f, &b).is_err());
    }

    #[test]
    #[cfg(unix)]
    fn test_which_relative_non_executable() {
        // Shouldn't return non-executable files.
        let f = TestFixture::new();
        f.touch("b/another").unwrap();
        assert!(_which(&f, "b/another").is_err());
    }
}
<commit_msg>fix AsciiExt unuse warning in newer versions of Rust<commit_after>//! which
//!
//! A Rust equivalent of Unix command `which(1)`.
//! # Example:
//!
//! To find which rustc executable binary is using:
//!
//! ``` norun
//! use which::which;
//!
//! let result = which::which("rustc").unwrap();
//! assert_eq!(result, PathBuf::from("/usr/bin/rustc"));
//!
//! ```

extern crate libc;
#[cfg(test)]
extern crate tempdir;

use std::path::{Path, PathBuf};
use std::{env, fs};

// Remove the `AsciiExt` will make `which-rs` build failed in older versions of Rust.
// Please Keep it here though we don't need it in the latest Rust version.
#[allow(unused)]
use std::ascii::AsciiExt;

#[cfg(unix)]
use std::ffi::CString;
use std::ffi::OsStr;
#[cfg(unix)]
use std::os::unix::ffi::OsStrExt;

/// Like `Path::with_extension`, but don't replace an existing extension.
fn ensure_exe_extension<T: AsRef<Path>>(path: T) -> PathBuf {
    if env::consts::EXE_EXTENSION.is_empty() {
        // Nothing to do.
        path.as_ref().to_path_buf()
    } else {
        match path.as_ref()
            .extension()
            .and_then(|e| e.to_str())
            .map(|e| e.eq_ignore_ascii_case(env::consts::EXE_EXTENSION)) {
            // Already has the right extension.
            Some(true) => path.as_ref().to_path_buf(),
            _ => {
                // Append the extension.
                let mut s = path.as_ref().to_path_buf().into_os_string();
                s.push(".");
                s.push(env::consts::EXE_EXTENSION);
                PathBuf::from(s)
            }
        }
    }
}

/// Find a exectable binary's path by name.
///
/// If given an absolute path, returns it if the file exists and is executable.
///
/// If given a relative path, returns an absolute path to the file if
/// it exists and is executable.
///
/// If given a string without path separators, looks for a file named
/// `binary_name` at each directory in `$PATH` and if it finds an executable
/// file there, returns it.
///
/// # Example
///
/// ``` norun
/// use which::which;
/// use std::path::PathBuf;
///
/// let result = which::which("rustc").unwrap();
/// assert_eq!(result, PathBuf::from("/usr/bin/rustc"));
///
/// ```
pub fn which<T: AsRef<OsStr>>(binary_name: T) -> Result<PathBuf, &'static str> {
    env::current_dir()
        .or_else(|_| Err("Couldn't get current directory"))
        .and_then(|cwd| which_in(binary_name, env::var_os("PATH"), &cwd))
}

/// Find `binary_name` in the path list `paths`, using `cwd` to resolve relative paths.
pub fn which_in<T, U, V>(binary_name: T, paths: Option<U>, cwd: V) -> Result<PathBuf, &'static str>
    where T: AsRef<OsStr>,
          U: AsRef<OsStr>,
          V: AsRef<Path>
{
    let binary_checker = CompositeChecker::new()
        .add_checker(Box::new(ExistedChecker::new()))
        .add_checker(Box::new(ExecutableChecker::new()));

    let finder = Finder::new();

    finder.find(binary_name, paths, cwd, &binary_checker)
}

struct Finder;

impl Finder {
    fn new() -> Finder {
        Finder
    }

    fn find<T, U, V>(&self,
                     binary_name: T,
                     paths: Option<U>,
                     cwd: V,
                     binary_checker: &Checker)
                     -> Result<PathBuf, &'static str>
        where T: AsRef<OsStr>,
              U: AsRef<OsStr>,
              V: AsRef<Path>
    {

        let path = ensure_exe_extension(binary_name.as_ref());

        // Does it have a path separator?
        if path.components().count() > 1 {
            if path.is_absolute() {
                if binary_checker.is_valid(&path) {
                    // Already fine.
                    Ok(path)
                } else {
                    // Absolute path but it's not usable.
                    Err("Bad absolute path")
                }
            } else {
                // Try to make it absolute.
                let mut new_path = PathBuf::from(cwd.as_ref());
                new_path.push(path);
                let new_path = ensure_exe_extension(new_path);
                if binary_checker.is_valid(&new_path) {
                    Ok(new_path)
                } else {
                    // File doesn't exist or isn't executable.
                    Err("Bad relative path")
                }
            }
        } else {
            // No separator, look it up in `paths`.
            paths.and_then(|paths| {
                    env::split_paths(paths.as_ref())
                        .map(|p| ensure_exe_extension(p.join(binary_name.as_ref())))
                        .skip_while(|p| !(binary_checker.is_valid(&p)))
                        .next()
                })
                .ok_or("Cannot find binary path")
        }
    }
}

trait Checker {
    fn is_valid(&self, path: &Path) -> bool;
}

struct ExecutableChecker;

impl ExecutableChecker {
    fn new() -> ExecutableChecker {
        ExecutableChecker
    }
}

impl Checker for ExecutableChecker {
    #[cfg(unix)]
    fn is_valid(&self, path: &Path) -> bool {
        CString::new(path.as_os_str().as_bytes())
            .and_then(|c| Ok(unsafe { libc::access(c.as_ptr(), libc::X_OK) == 0 }))
            .unwrap_or(false)
    }

    #[cfg(not(unix))]
    fn is_valid(&self, _path: &Path) -> bool {
        true
    }
}

struct ExistedChecker;

impl ExistedChecker {
    fn new() -> ExistedChecker {
        ExistedChecker
    }
}

impl Checker for ExistedChecker {
    fn is_valid(&self, path: &Path) -> bool {
        fs::metadata(path)
            .map(|metadata| metadata.is_file())
            .unwrap_or(false)
    }
}

struct CompositeChecker {
    checkers: Vec<Box<Checker>>,
}

impl CompositeChecker {
    fn new() -> CompositeChecker {
        CompositeChecker { checkers: Vec::new() }
    }

    fn add_checker(mut self, checker: Box<Checker>) -> CompositeChecker {
        self.checkers.push(checker);
        self
    }
}

impl Checker for CompositeChecker {
    fn is_valid(&self, path: &Path) -> bool {
        self.checkers
            .iter()
            .all(|checker| checker.is_valid(path))
    }
}

#[test]
fn test_exe_extension() {
    let expected = PathBuf::from("foo").with_extension(env::consts::EXE_EXTENSION);
    assert_eq!(expected, ensure_exe_extension(PathBuf::from("foo")));
    let p = expected.clone();
    assert_eq!(expected, ensure_exe_extension(p));
}

#[test]
#[cfg(windows)]
fn test_exe_extension_existing_extension() {
    assert_eq!(PathBuf::from("foo.bar.exe"),
               ensure_exe_extension("foo.bar"));
}

#[test]
#[cfg(windows)]
fn test_exe_extension_existing_extension_uppercase() {
    assert_eq!(PathBuf::from("foo.EXE"), ensure_exe_extension("foo.EXE"));
}

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

    use std::env;
    use std::ffi::{OsStr, OsString};
    use std::fs;
    use std::io;
    use std::path::{Path, PathBuf};
    use tempdir::TempDir;

    struct TestFixture {
        /// Temp directory.
        pub tempdir: TempDir,
        /// $PATH
        pub paths: OsString,
        /// Binaries created in $PATH
        pub bins: Vec<PathBuf>,
    }

    const SUBDIRS: &'static [&'static str] = &["a", "b", "c"];
    const BIN_NAME: &'static str = "bin";

    #[cfg(unix)]
    fn mk_bin(dir: &Path, path: &str) -> io::Result<PathBuf> {
        use libc;
        use std::os::unix::fs::OpenOptionsExt;
        let bin = dir.join(path).with_extension(env::consts::EXE_EXTENSION);
        fs::OpenOptions::new()
            .write(true)
            .create(true)
            .mode(0o666 | (libc::S_IXUSR as u32))
            .open(&bin)
            .and_then(|_f| bin.canonicalize())
    }

    fn touch(dir: &Path, path: &str) -> io::Result<PathBuf> {
        let b = dir.join(path).with_extension(env::consts::EXE_EXTENSION);
        fs::File::create(&b).and_then(|_f| b.canonicalize())
    }

    #[cfg(not(unix))]
    fn mk_bin(dir: &Path, path: &str) -> io::Result<PathBuf> {
        touch(dir, path)
    }

    impl TestFixture {
        pub fn new() -> TestFixture {
            let tempdir = TempDir::new("which_tests").unwrap();
            let mut builder = fs::DirBuilder::new();
            builder.recursive(true);
            let mut paths = vec![];
            let mut bins = vec![];
            for d in SUBDIRS.iter() {
                let p = tempdir.path().join(d);
                builder.create(&p).unwrap();
                bins.push(mk_bin(&p, &BIN_NAME).unwrap());
                paths.push(p);
            }
            TestFixture {
                tempdir: tempdir,
                paths: env::join_paths(paths).unwrap(),
                bins: bins,
            }
        }

        #[allow(dead_code)]
        pub fn touch(&self, path: &str) -> io::Result<PathBuf> {
            touch(self.tempdir.path(), &path)
        }

        pub fn mk_bin(&self, path: &str) -> io::Result<PathBuf> {
            mk_bin(self.tempdir.path(), &path)
        }
    }

    fn _which<T: AsRef<OsStr>>(f: &TestFixture, path: T) -> Result<PathBuf, &'static str> {
        which_in(path, Some(f.paths.clone()), f.tempdir.path())
    }

    #[test]
    #[cfg(unix)]
    fn it_works() {
        use std::process::Command;
        let result = which("rustc");
        assert!(result.is_ok());

        let which_result = Command::new("which")
            .arg("rustc")
            .output();

        assert_eq!(String::from(result.unwrap().to_str().unwrap()),
                   String::from_utf8(which_result.unwrap().stdout).unwrap().trim());
    }

    #[test]
    fn test_which() {
        let f = TestFixture::new();
        assert_eq!(_which(&f, &BIN_NAME).unwrap().canonicalize().unwrap(),
                   f.bins[0])
    }

    #[test]
    fn test_which_extension() {
        let f = TestFixture::new();
        let b = Path::new(&BIN_NAME).with_extension(env::consts::EXE_EXTENSION);
        assert_eq!(_which(&f, &b).unwrap().canonicalize().unwrap(), f.bins[0])
    }

    #[test]
    fn test_which_not_found() {
        let f = TestFixture::new();
        assert!(_which(&f, "a").is_err());
    }

    #[test]
    fn test_which_second() {
        let f = TestFixture::new();
        let b = f.mk_bin("b/another").unwrap();
        assert_eq!(_which(&f, "another").unwrap().canonicalize().unwrap(), b);
    }

    #[test]
    fn test_which_absolute() {
        let f = TestFixture::new();
        assert_eq!(_which(&f, &f.bins[1]).unwrap().canonicalize().unwrap(),
                   f.bins[1].canonicalize().unwrap());
    }

    #[test]
    #[cfg(windows)]
    fn test_which_absolute_path_case() {
        // Test that an absolute path with an uppercase extension
        // is accepted.
        let f = TestFixture::new();
        let p = f.bins[1].with_extension("EXE");
        assert_eq!(_which(&f, &p).unwrap().canonicalize().unwrap(),
                   f.bins[1].canonicalize().unwrap());
    }

    #[test]
    fn test_which_absolute_extension() {
        let f = TestFixture::new();
        // Don't append EXE_EXTENSION here.
        let b = f.bins[1].parent().unwrap().join(&BIN_NAME);
        assert_eq!(_which(&f, &b).unwrap().canonicalize().unwrap(),
                   f.bins[1].canonicalize().unwrap());
    }

    #[test]
    fn test_which_relative() {
        let f = TestFixture::new();
        assert_eq!(_which(&f, "b/bin").unwrap().canonicalize().unwrap(),
                   f.bins[1].canonicalize().unwrap());
    }

    #[test]
    fn test_which_relative_extension() {
        // test_which_relative tests a relative path without an extension,
        // so test a relative path with an extension here.
        let f = TestFixture::new();
        let b = Path::new("b/bin").with_extension(env::consts::EXE_EXTENSION);
        assert_eq!(_which(&f, &b).unwrap().canonicalize().unwrap(),
                   f.bins[1].canonicalize().unwrap());
    }

    #[test]
    #[cfg(windows)]
    fn test_which_relative_extension_case() {
        // Test that a relative path with an uppercase extension
        // is accepted.
        let f = TestFixture::new();
        let b = Path::new("b/bin").with_extension("EXE");
        assert_eq!(_which(&f, &b).unwrap().canonicalize().unwrap(),
                   f.bins[1].canonicalize().unwrap());
    }

    #[test]
    fn test_which_relative_leading_dot() {
        let f = TestFixture::new();
        assert_eq!(_which(&f, "./b/bin").unwrap().canonicalize().unwrap(),
                   f.bins[1].canonicalize().unwrap());
    }

    #[test]
    #[cfg(unix)]
    fn test_which_non_executable() {
        // Shouldn't return non-executable files.
        let f = TestFixture::new();
        f.touch("b/another").unwrap();
        assert!(_which(&f, "another").is_err());
    }

    #[test]
    #[cfg(unix)]
    fn test_which_absolute_non_executable() {
        // Shouldn't return non-executable files, even if given an absolute path.
        let f = TestFixture::new();
        let b = f.touch("b/another").unwrap();
        assert!(_which(&f, &b).is_err());
    }

    #[test]
    #[cfg(unix)]
    fn test_which_relative_non_executable() {
        // Shouldn't return non-executable files.
        let f = TestFixture::new();
        f.touch("b/another").unwrap();
        assert!(_which(&f, "b/another").is_err());
    }
}
<|endoftext|>