<commit_before>use iron::{Request, Response, Url, Handler, IronResult, Set};
use iron::response::modifiers::{Status, Body, Redirect};
use iron::status;
use mount::OriginalUrl;
use requested_path::RequestedPath;

/// The static file-serving `Handler`.
///
/// This handler serves files from a single filesystem path, which may be absolute or relative.
/// Incoming requests are mapped onto the filesystem by appending their URL path to the handler's
/// root path. If the filesystem path corresponds to a regular file, the handler will attempt to
/// serve it. Otherwise, if the path corresponds to a directory containing an `index.html`,
/// the handler will attempt to serve that instead.
///
/// ## Errors
///
/// If the path doesn't match any real object in the filesystem, the handler will return
/// a Response with `status::NotFound`. If an IO error occurs whilst attempting to serve
/// a file, `FileError(IoError)` will be returned.
#[deriving(Clone)]
pub struct Static {
    /// The path this handler is serving files from.
    pub root_path: Path
}

impl Static {
    /// Create a new instance of `Static` with a given root path.
    ///
    /// If `Path::new("")` is given, files will be served from the current directory.
    pub fn new(root_path: Path) -> Static {
        Static { root_path: root_path }
    }
}

impl Handler for Static {
    fn call(&self, req: &mut Request) -> IronResult<Response> {
        let requested_path = RequestedPath::new(&self.root_path, req);

        // If the URL ends in a slash, serve the file directly.
        // Otherwise, redirect to the directory equivalent of the URL.
        if requested_path.should_redirect(req) {
            // Perform an HTTP 301 Redirect.
            let mut redirect_path = match req.extensions.find::<OriginalUrl, Url>() {
                Some(original_url) => original_url,
                None => &req.url
            }.clone();

            // Append the trailing slash
            //
            // rust-url automatically turns an empty string in the last
            // slot in the path into a trailing slash.
            redirect_path.path.push("".into_string());

            return Ok(Response::new().set(Status(status::MovedPermanently))
                          .set(Body(format!("Redirecting to {}", redirect_path)))
                          .set(Redirect(redirect_path)));
        }

        match requested_path.get_file() {
            Some(path) =>
                Ok(Response::new()
                       .set(Status(status::Ok))
                       // Won't panic because we know the file exists from get_file
                       .set(Body(path))),
            None =>
                // If no file is found, return a 404 response.
                Ok(Response::new().set(Status(status::NotFound)).set(Body("File not found")))
        }
    }
}
<commit_msg>(fix) Fix for typemap changes.<commit_after>use iron::{Request, Response, Url, Handler, IronResult, Set};
use iron::response::modifiers::{Status, Body, Redirect};
use iron::status;
use mount::OriginalUrl;
use requested_path::RequestedPath;

/// The static file-serving `Handler`.
///
/// This handler serves files from a single filesystem path, which may be absolute or relative.
/// Incoming requests are mapped onto the filesystem by appending their URL path to the handler's
/// root path. If the filesystem path corresponds to a regular file, the handler will attempt to
/// serve it. Otherwise, if the path corresponds to a directory containing an `index.html`,
/// the handler will attempt to serve that instead.
///
/// ## Errors
///
/// If the path doesn't match any real object in the filesystem, the handler will return
/// a Response with `status::NotFound`. If an IO error occurs whilst attempting to serve
/// a file, `FileError(IoError)` will be returned.
#[deriving(Clone)]
pub struct Static {
    /// The path this handler is serving files from.
    pub root_path: Path
}

impl Static {
    /// Create a new instance of `Static` with a given root path.
    ///
    /// If `Path::new("")` is given, files will be served from the current directory.
    pub fn new(root_path: Path) -> Static {
        Static { root_path: root_path }
    }
}

impl Handler for Static {
    fn call(&self, req: &mut Request) -> IronResult<Response> {
        let requested_path = RequestedPath::new(&self.root_path, req);

        // If the URL ends in a slash, serve the file directly.
        // Otherwise, redirect to the directory equivalent of the URL.
        if requested_path.should_redirect(req) {
            // Perform an HTTP 301 Redirect.
            let mut redirect_path = match req.extensions.get::<OriginalUrl, Url>() {
                Some(original_url) => original_url,
                None => &req.url
            }.clone();

            // Append the trailing slash
            //
            // rust-url automatically turns an empty string in the last
            // slot in the path into a trailing slash.
            redirect_path.path.push("".into_string());

            return Ok(Response::new().set(Status(status::MovedPermanently))
                          .set(Body(format!("Redirecting to {}", redirect_path)))
                          .set(Redirect(redirect_path)));
        }

        match requested_path.get_file() {
            Some(path) =>
                Ok(Response::new()
                       .set(Status(status::Ok))
                       // Won't panic because we know the file exists from get_file
                       .set(Body(path))),
            None =>
                // If no file is found, return a 404 response.
                Ok(Response::new().set(Status(status::NotFound)).set(Body("File not found")))
        }
    }
}
<|endoftext|>


<commit_before>// Copyright 2014 The Gfx-rs Developers.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use std::comm;
use std::comm::DuplexStream;
use std::kinds::marker;

use server;
use Platform;

pub enum Call {}
pub enum Cast {}
pub type Request = server::Request<Call, Cast>;

pub enum Reply {}

pub struct Client {
    stream: DuplexStream<Request, Reply>,
}

impl Client {
    fn call(&self, msg: Call) -> Reply {
        self.stream.send(server::Call(msg));
        self.stream.recv()
    }

    fn cast(&self, msg: Cast) {
        self.stream.send(server::Cast(msg));
    }

    // TODO: public functions
}

pub struct Server<P> {
    no_send: marker::NoSend,
    no_share: marker::NoShare,
    stream: DuplexStream<Reply, Request>,
    platform: P,
}

impl<Api, P: Platform<Api>> Server<P> {
    /// Update the platform. The client must manually update this on the main
    /// thread.
    pub fn update(&self) {
        // Get updates from the renderer and pass on results
        loop {
            match self.stream.try_recv() {
                Ok(_) => self.stream.send(unimplemented!()),
                Err(_) => break,
            }
        }

        self.platform.swap_buffers();
    }
}

#[deriving(Show)]
pub enum InitError {}

pub fn init<Api, P: Platform<Api>>(platform: P, _: super::Options)
        -> Result<(Client, Server<P>), InitError> {
    let (client_stream, server_stream) = comm::duplex();

    let client = Client {
        stream: client_stream,
    };
    let server = Server {
        no_send: marker::NoSend,
        no_share: marker::NoShare,
        stream: server_stream,
        platform: platform,
    };

    Ok((client, server))
}
<commit_msg>fail! when attempting to call device::Server::update after the render task has closed<commit_after>// Copyright 2014 The Gfx-rs Developers.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use std::comm;
use std::comm::DuplexStream;
use std::kinds::marker;

use server;
use Platform;

pub enum Call {}
pub enum Cast {}
pub type Request = server::Request<Call, Cast>;

pub enum Reply {}

pub struct Client {
    stream: DuplexStream<Request, Reply>,
}

impl Client {
    fn call(&self, msg: Call) -> Reply {
        self.stream.send(server::Call(msg));
        self.stream.recv()
    }

    fn cast(&self, msg: Cast) {
        self.stream.send(server::Cast(msg));
    }

    // TODO: public functions
}

pub struct Server<P> {
    no_send: marker::NoSend,
    no_share: marker::NoShare,
    stream: DuplexStream<Reply, Request>,
    platform: P,
}

impl<Api, P: Platform<Api>> Server<P> {
    /// Update the platform. The client must manually update this on the main
    /// thread.
    pub fn update(&self) {
        // Get updates from the renderer and pass on results
        loop {
            match self.stream.try_recv() {
                Ok(_) => self.stream.send(unimplemented!()),
                Err(comm::Empty) => break,
                Err(comm::Disconnected) => fail!("Render task has closed."),
            }
        }

        self.platform.swap_buffers();
    }
}

#[deriving(Show)]
pub enum InitError {}

pub fn init<Api, P: Platform<Api>>(platform: P, _: super::Options)
        -> Result<(Client, Server<P>), InitError> {
    let (client_stream, server_stream) = comm::duplex();

    let client = Client {
        stream: client_stream,
    };
    let server = Server {
        no_send: marker::NoSend,
        no_share: marker::NoShare,
        stream: server_stream,
        platform: platform,
    };

    Ok((client, server))
}
<|endoftext|>


<commit_before>use libc::c_void;

use parse_code;
use std::io::{self, Write};
use zstd_sys;

struct EncoderContext {
    s: *mut zstd_sys::ZSTD_CStream,
}

impl Default for EncoderContext {
    fn default() -> Self {
        EncoderContext { s: unsafe { zstd_sys::ZSTD_createCStream() } }
    }
}

impl Drop for EncoderContext {
    fn drop(&mut self) {
        let code = unsafe { zstd_sys::ZSTD_freeCStream(self.s) };
        parse_code(code).unwrap();
    }
}

#[derive(PartialEq)]
enum EncoderState {
    Accepting,
    // Finished just makes sure writes are no longer accepted.
    Finished,
    StreamEnd,
    // The "stream ended and flushed" state corresponds to the object being
    // destroyed.
}

/// An encoder that compress and forward data to another writer.
///
/// This allows to compress a stream of data
/// (good for files or heavy network stream).
///
/// Don't forget to call `finish()` before dropping it!
///
/// Note: The zstd library has its own internal input buffer (~128kb).
pub struct Encoder<W: Write> {
    // output writer (compressed data)
    writer: W,
    // output buffer
    buffer: Vec<u8>,
    // offset in the output buffer
    offset: usize,

    // compression context
    context: EncoderContext,
    state: EncoderState,
}

/// A wrapper around an `Encoder<W>` that finishes the stream on drop.
pub struct AutoFinishEncoder<W: Write> {
    // We wrap this in an option to take it during drop.
    encoder: Option<Encoder<W>>,
    // TODO: make this a FnOnce once it works in a Box
    on_finish: Option<Box<FnMut(io::Result<W>)>>,
}

impl<W: Write> AutoFinishEncoder<W> {
    fn new<F: 'static + FnMut(io::Result<W>)>(encoder: Encoder<W>,
                                              on_finish: F)
                                              -> Self {
        AutoFinishEncoder {
            encoder: Some(encoder),
            on_finish: Some(Box::new(on_finish)),
        }
    }

    /// Acquires a reference to the underlying writer.
    pub fn get_ref(&self) -> &W {
        self.encoder
            .as_ref()
            .unwrap()
            .get_ref()
    }

    /// Acquires a mutable reference to the underlying writer.
    ///
    /// Note that mutation of the writer may result in surprising results if
    /// this encoder is continued to be used.
    pub fn get_mut(&mut self) -> &mut W {
        self.encoder
            .as_mut()
            .unwrap()
            .get_mut()
    }
}

impl<W: Write> Drop for AutoFinishEncoder<W> {
    fn drop(&mut self) {
        let result = self.encoder
            .take()
            .unwrap()
            .finish();
        if let Some(mut on_finish) = self.on_finish.take() {
            on_finish(result);
        }
    }
}

impl<W: Write> Write for AutoFinishEncoder<W> {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        self.encoder
            .as_mut()
            .unwrap()
            .write(buf)
    }

    fn flush(&mut self) -> io::Result<()> {
        self.encoder
            .as_mut()
            .unwrap()
            .flush()
    }
}

impl<W: Write> Encoder<W> {
    /// Creates a new encoder.
    ///
    /// `level`: compression level (1-21)
    pub fn new(writer: W, level: i32) -> io::Result<Self> {
        Self::with_dictionary(writer, level, &[])
    }

    /// Creates a new encoder, using an existing dictionary.
    ///
    /// (Provides better compression ratio for small files,
    /// but requires the dictionary to be present during decompression.)
    pub fn with_dictionary(writer: W, level: i32, dictionary: &[u8])
                           -> io::Result<Self> {
        let context = EncoderContext::default();

        // Initialize the stream with an existing dictionary
        parse_code(unsafe {
            zstd_sys::ZSTD_initCStream_usingDict(context.s,
                                           dictionary.as_ptr() as *const c_void,
                                           dictionary.len(),
                                           level)
        })?;

        Encoder::with_context(writer, context)
    }

    /// Returns a wrapper around `self` that will finish the stream on drop.
    ///
    /// # Panic
    ///
    /// Panics on drop if an error happens when finishing the stream.
    pub fn auto_finish(self) -> AutoFinishEncoder<W> {
        self.on_finish(|result| { result.unwrap(); })
    }

    /// Returns an encoder that will finish the stream on drop.
    ///
    /// Calls the given callback with the result from `finish()`.
    pub fn on_finish<F: 'static + FnMut(io::Result<W>)>
        (self, f: F)
         -> AutoFinishEncoder<W> {
        AutoFinishEncoder::new(self, f)
    }

    fn with_context(writer: W, context: EncoderContext) -> io::Result<Self> {
        // This is the output buffer size,
        // for compressed data we get from zstd.
        let buffer_size = unsafe { zstd_sys::ZSTD_CStreamOutSize() };

        Ok(Encoder {
               writer: writer,
               buffer: Vec::with_capacity(buffer_size),
               offset: 0,
               context: context,
               state: EncoderState::Accepting,
           })
    }

    /// Acquires a reference to the underlying writer.
    pub fn get_ref(&self) -> &W {
        &self.writer
    }

    /// Acquires a mutable reference to the underlying writer.
    ///
    /// Note that mutation of the writer may result in surprising results if
    /// this encoder is continued to be used.
    pub fn get_mut(&mut self) -> &mut W {
        &mut self.writer
    }

    /// Finishes the stream. You *need* to call this after writing your stuff.
    ///
    /// This returns the inner writer in case you need it.
    ///
    /// To get back `self` in case an error happened, use `try_finish`.
    ///
    /// **Note**: If you don't want (or can't) call `finish()` manually after writing your data,
    /// consider using `auto_finish()` to get an `AutoFinishEncoder`.
    pub fn finish(mut self) -> io::Result<W> {
        self.do_finish()?;
        // Return the writer, because why not
        Ok(self.writer)
    }

    /// Attempts to finish the stream. You *need* to call this after writing your stuff.
    ///
    /// This returns the inner writer if the finish was successful, or the
    /// object plus an error if it wasn't.
    ///
    /// `write` on this object will panic after `try_finish` has been called,
    /// even if it fails.
    pub fn try_finish(mut self) -> Result<W, (Self, io::Error)> {
        match self.do_finish() {
            Ok(()) => Ok(self.writer),
            Err(e) => Err((self, e))
        }
    }

    fn do_finish(&mut self) -> io::Result<()> {
        if self.state == EncoderState::Accepting {
            // Write any data pending in `self.buffer`.
            self.write_from_offset()?;
            self.state = EncoderState::Finished;
        }

        if self.state == EncoderState::Finished {
            // First, closes the stream.
            let mut buffer = zstd_sys::ZSTD_outBuffer {
                dst: self.buffer.as_mut_ptr() as *mut c_void,
                size: self.buffer.capacity(),
                pos: 0,
            };
            let remaining = parse_code(unsafe {
                zstd_sys::ZSTD_endStream(self.context.s,
                                   &mut buffer as *mut zstd_sys::ZSTD_outBuffer)
            })?;
            unsafe {
                self.buffer.set_len(buffer.pos);
            }
            if remaining != 0 {
                // Need to flush?
                panic!("Need to flush, but I'm lazy.");
            }
            self.offset = 0;
            self.state = EncoderState::StreamEnd;
        }

        self.write_from_offset()?;

        Ok(())
    }

    /// Return a recommendation for the size of data to write at once.
    pub fn recommended_input_size() -> usize {
        unsafe { zstd_sys::ZSTD_CStreamInSize() }
    }

    /// write_all, except keep track of partial writes for non-blocking IO.
    fn write_from_offset(&mut self) -> io::Result<()> {
        while self.offset < self.buffer.len() {
            match self.writer.write(&self.buffer[self.offset..]) {
                Ok(n) => self.offset += n,
                Err(ref e) if e.kind() == io::ErrorKind::Interrupted => {},
                Err(e) => return Err(e),
            }
        }
        Ok(())
    }
}

impl<W: Write> Write for Encoder<W> {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        if self.state != EncoderState::Accepting {
            panic!("write called after try_finish attempted");
        }

        // Write any data pending in `self.buffer`.
        self.write_from_offset()?;

        // If we get to here, `self.buffer` can safely be discarded.

        let mut in_buffer = zstd_sys::ZSTD_inBuffer {
            src: buf.as_ptr() as *const c_void,
            size: buf.len(),
            pos: 0,
        };

        let mut out_buffer = zstd_sys::ZSTD_outBuffer {
            dst: self.buffer.as_mut_ptr() as *mut c_void,
            size: self.buffer.capacity(),
            pos: 0,
        };

        unsafe {
            // Time to fill our input buffer
            let code =
                zstd_sys::ZSTD_compressStream(self.context.s,
                                              &mut out_buffer as
                                              *mut zstd_sys::ZSTD_outBuffer,
                                              &mut in_buffer as
                                              *mut zstd_sys::ZSTD_inBuffer);
            // Note: this may very well be empty,
            // if it doesn't exceed zstd's own buffer
            self.buffer.set_len(out_buffer.pos);

            // Do we care about the hint?
            let _ = parse_code(code)?;
        }

        // This is the first time he sees this buffer.
        // Remember his delicate touch.
        self.offset = 0;
        self.write_from_offset()?;

        Ok(in_buffer.pos)
    }

    fn flush(&mut self) -> io::Result<()> {
        if self.state == EncoderState::Accepting {
            self.write_from_offset()?;

            let mut buffer = zstd_sys::ZSTD_outBuffer {
                dst: self.buffer.as_mut_ptr() as *mut c_void,
                size: self.buffer.capacity(),
                pos: 0,
            };
            unsafe {
                let code =
                    zstd_sys::ZSTD_flushStream(self.context.s,
                                               &mut buffer as
                                               *mut zstd_sys::ZSTD_outBuffer);
                self.buffer.set_len(buffer.pos);
                let _ = parse_code(code)?;
            }
            self.offset = 0;
        }

        self.write_from_offset()?;
        Ok(())
    }
}

#[cfg(test)]
mod tests {
    use stream::decode_all;
    use stream::tests::WritePartial;
    use super::Encoder;

    /// Test that flush after a partial write works successfully without
    /// corrupting the frame. This test is in this module because it checks
    /// internal implementation details.
    #[test]
    fn test_partial_write_flush() {
        use std::io::Write;

        let (input, mut z) = setup_partial_write();

        // flush shouldn't corrupt the stream
        z.flush().unwrap();

        let buf = z.finish().unwrap().into_inner();
        assert_eq!(&decode_all(&buf[..]).unwrap(), &input);
    }

    /// Test that finish after a partial write works successfully without
    /// corrupting the frame. This test is in this module because it checks
    /// internal implementation details.
    #[test]
    fn test_partial_write_finish() {
        let (input, z) = setup_partial_write();

        // finish shouldn't corrupt the stream
        let buf = z.finish().unwrap().into_inner();
        assert_eq!(&decode_all(&buf[..]).unwrap(), &input);
    }

    fn setup_partial_write() -> (Vec<u8>, Encoder<WritePartial>) {
        use std::io::Write;

        let mut buf = WritePartial::new();
        buf.accept(Some(1));
        let mut z = Encoder::new(buf, 1).unwrap();

        // Fill in enough data to make sure the buffer gets written out.
        let input = "b".repeat(128 * 1024).into_bytes();
        z.write(&input).unwrap();

        // At this point, the internal buffer in z should have some data.
        assert_ne!(z.offset, z.buffer.len());

        (input, z)
    }
}
<commit_msg>encoder: do not write compressed buffer immediately<commit_after>use libc::c_void;

use parse_code;
use std::io::{self, Write};
use zstd_sys;

struct EncoderContext {
    s: *mut zstd_sys::ZSTD_CStream,
}

impl Default for EncoderContext {
    fn default() -> Self {
        EncoderContext { s: unsafe { zstd_sys::ZSTD_createCStream() } }
    }
}

impl Drop for EncoderContext {
    fn drop(&mut self) {
        let code = unsafe { zstd_sys::ZSTD_freeCStream(self.s) };
        parse_code(code).unwrap();
    }
}

#[derive(PartialEq)]
enum EncoderState {
    Accepting,
    // Finished just makes sure writes are no longer accepted.
    Finished,
    StreamEnd,
    // The "stream ended and flushed" state corresponds to the object being
    // destroyed.
}

/// An encoder that compress and forward data to another writer.
///
/// This allows to compress a stream of data
/// (good for files or heavy network stream).
///
/// Don't forget to call `finish()` before dropping it!
///
/// Note: The zstd library has its own internal input buffer (~128kb).
pub struct Encoder<W: Write> {
    // output writer (compressed data)
    writer: W,
    // output buffer
    buffer: Vec<u8>,
    // offset in the output buffer
    offset: usize,

    // compression context
    context: EncoderContext,
    state: EncoderState,
}

/// A wrapper around an `Encoder<W>` that finishes the stream on drop.
pub struct AutoFinishEncoder<W: Write> {
    // We wrap this in an option to take it during drop.
    encoder: Option<Encoder<W>>,
    // TODO: make this a FnOnce once it works in a Box
    on_finish: Option<Box<FnMut(io::Result<W>)>>,
}

impl<W: Write> AutoFinishEncoder<W> {
    fn new<F: 'static + FnMut(io::Result<W>)>(encoder: Encoder<W>,
                                              on_finish: F)
                                              -> Self {
        AutoFinishEncoder {
            encoder: Some(encoder),
            on_finish: Some(Box::new(on_finish)),
        }
    }

    /// Acquires a reference to the underlying writer.
    pub fn get_ref(&self) -> &W {
        self.encoder
            .as_ref()
            .unwrap()
            .get_ref()
    }

    /// Acquires a mutable reference to the underlying writer.
    ///
    /// Note that mutation of the writer may result in surprising results if
    /// this encoder is continued to be used.
    pub fn get_mut(&mut self) -> &mut W {
        self.encoder
            .as_mut()
            .unwrap()
            .get_mut()
    }
}

impl<W: Write> Drop for AutoFinishEncoder<W> {
    fn drop(&mut self) {
        let result = self.encoder
            .take()
            .unwrap()
            .finish();
        if let Some(mut on_finish) = self.on_finish.take() {
            on_finish(result);
        }
    }
}

impl<W: Write> Write for AutoFinishEncoder<W> {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        self.encoder
            .as_mut()
            .unwrap()
            .write(buf)
    }

    fn flush(&mut self) -> io::Result<()> {
        self.encoder
            .as_mut()
            .unwrap()
            .flush()
    }
}

impl<W: Write> Encoder<W> {
    /// Creates a new encoder.
    ///
    /// `level`: compression level (1-21)
    pub fn new(writer: W, level: i32) -> io::Result<Self> {
        Self::with_dictionary(writer, level, &[])
    }

    /// Creates a new encoder, using an existing dictionary.
    ///
    /// (Provides better compression ratio for small files,
    /// but requires the dictionary to be present during decompression.)
    pub fn with_dictionary(writer: W, level: i32, dictionary: &[u8])
                           -> io::Result<Self> {
        let context = EncoderContext::default();

        // Initialize the stream with an existing dictionary
        parse_code(unsafe {
            zstd_sys::ZSTD_initCStream_usingDict(context.s,
                                           dictionary.as_ptr() as *const c_void,
                                           dictionary.len(),
                                           level)
        })?;

        Encoder::with_context(writer, context)
    }

    /// Returns a wrapper around `self` that will finish the stream on drop.
    ///
    /// # Panic
    ///
    /// Panics on drop if an error happens when finishing the stream.
    pub fn auto_finish(self) -> AutoFinishEncoder<W> {
        self.on_finish(|result| { result.unwrap(); })
    }

    /// Returns an encoder that will finish the stream on drop.
    ///
    /// Calls the given callback with the result from `finish()`.
    pub fn on_finish<F: 'static + FnMut(io::Result<W>)>
        (self, f: F)
         -> AutoFinishEncoder<W> {
        AutoFinishEncoder::new(self, f)
    }

    fn with_context(writer: W, context: EncoderContext) -> io::Result<Self> {
        // This is the output buffer size,
        // for compressed data we get from zstd.
        let buffer_size = unsafe { zstd_sys::ZSTD_CStreamOutSize() };

        Ok(Encoder {
               writer: writer,
               buffer: Vec::with_capacity(buffer_size),
               offset: 0,
               context: context,
               state: EncoderState::Accepting,
           })
    }

    /// Acquires a reference to the underlying writer.
    pub fn get_ref(&self) -> &W {
        &self.writer
    }

    /// Acquires a mutable reference to the underlying writer.
    ///
    /// Note that mutation of the writer may result in surprising results if
    /// this encoder is continued to be used.
    pub fn get_mut(&mut self) -> &mut W {
        &mut self.writer
    }

    /// Finishes the stream. You *need* to call this after writing your stuff.
    ///
    /// This returns the inner writer in case you need it.
    ///
    /// To get back `self` in case an error happened, use `try_finish`.
    ///
    /// **Note**: If you don't want (or can't) call `finish()` manually after writing your data,
    /// consider using `auto_finish()` to get an `AutoFinishEncoder`.
    pub fn finish(mut self) -> io::Result<W> {
        self.do_finish()?;
        // Return the writer, because why not
        Ok(self.writer)
    }

    /// Attempts to finish the stream. You *need* to call this after writing your stuff.
    ///
    /// This returns the inner writer if the finish was successful, or the
    /// object plus an error if it wasn't.
    ///
    /// `write` on this object will panic after `try_finish` has been called,
    /// even if it fails.
    pub fn try_finish(mut self) -> Result<W, (Self, io::Error)> {
        match self.do_finish() {
            Ok(()) => Ok(self.writer),
            Err(e) => Err((self, e))
        }
    }

    fn do_finish(&mut self) -> io::Result<()> {
        if self.state == EncoderState::Accepting {
            // Write any data pending in `self.buffer`.
            self.write_from_offset()?;
            self.state = EncoderState::Finished;
        }

        if self.state == EncoderState::Finished {
            // First, closes the stream.
            let mut buffer = zstd_sys::ZSTD_outBuffer {
                dst: self.buffer.as_mut_ptr() as *mut c_void,
                size: self.buffer.capacity(),
                pos: 0,
            };
            let remaining = parse_code(unsafe {
                zstd_sys::ZSTD_endStream(self.context.s,
                                   &mut buffer as *mut zstd_sys::ZSTD_outBuffer)
            })?;
            unsafe {
                self.buffer.set_len(buffer.pos);
            }
            if remaining != 0 {
                // Need to flush?
                panic!("Need to flush, but I'm lazy.");
            }
            self.offset = 0;
            self.state = EncoderState::StreamEnd;
        }

        self.write_from_offset()?;

        Ok(())
    }

    /// Return a recommendation for the size of data to write at once.
    pub fn recommended_input_size() -> usize {
        unsafe { zstd_sys::ZSTD_CStreamInSize() }
    }

    /// write_all, except keep track of partial writes for non-blocking IO.
    fn write_from_offset(&mut self) -> io::Result<()> {
        while self.offset < self.buffer.len() {
            match self.writer.write(&self.buffer[self.offset..]) {
                Ok(n) => self.offset += n,
                Err(ref e) if e.kind() == io::ErrorKind::Interrupted => {},
                Err(e) => return Err(e),
            }
        }
        Ok(())
    }
}

impl<W: Write> Write for Encoder<W> {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        if self.state != EncoderState::Accepting {
            panic!("write called after try_finish attempted");
        }

        // Write any data pending in `self.buffer`.
        self.write_from_offset()?;

        // If we get to here, `self.buffer` can safely be discarded.

        let mut in_buffer = zstd_sys::ZSTD_inBuffer {
            src: buf.as_ptr() as *const c_void,
            size: buf.len(),
            pos: 0,
        };

        let mut out_buffer = zstd_sys::ZSTD_outBuffer {
            dst: self.buffer.as_mut_ptr() as *mut c_void,
            size: self.buffer.capacity(),
            pos: 0,
        };

        unsafe {
            // Time to fill our input buffer
            let code =
                zstd_sys::ZSTD_compressStream(self.context.s,
                                              &mut out_buffer as
                                              *mut zstd_sys::ZSTD_outBuffer,
                                              &mut in_buffer as
                                              *mut zstd_sys::ZSTD_inBuffer);
            // Note: this may very well be empty,
            // if it doesn't exceed zstd's own buffer
            self.buffer.set_len(out_buffer.pos);

            // Do we care about the hint?
            let _ = parse_code(code)?;
        }

        // We have a fresh buffer ahead of us.
        self.offset = 0;

        // But we won't touch it now - too many things could go wrong!
        // We consumed input data, let's report it now before it's too late.

        Ok(in_buffer.pos)
    }

    fn flush(&mut self) -> io::Result<()> {
        if self.state == EncoderState::Accepting {
            self.write_from_offset()?;

            let mut buffer = zstd_sys::ZSTD_outBuffer {
                dst: self.buffer.as_mut_ptr() as *mut c_void,
                size: self.buffer.capacity(),
                pos: 0,
            };
            unsafe {
                let code =
                    zstd_sys::ZSTD_flushStream(self.context.s,
                                               &mut buffer as
                                               *mut zstd_sys::ZSTD_outBuffer);
                self.buffer.set_len(buffer.pos);
                let _ = parse_code(code)?;
            }
            self.offset = 0;
        }

        self.write_from_offset()?;
        Ok(())
    }
}

#[cfg(test)]
mod tests {
    use stream::decode_all;
    use stream::tests::WritePartial;
    use super::Encoder;

    /// Test that flush after a partial write works successfully without
    /// corrupting the frame. This test is in this module because it checks
    /// internal implementation details.
    #[test]
    fn test_partial_write_flush() {
        use std::io::Write;

        let (input, mut z) = setup_partial_write();

        // flush shouldn't corrupt the stream
        z.flush().unwrap();

        let buf = z.finish().unwrap().into_inner();
        assert_eq!(&decode_all(&buf[..]).unwrap(), &input);
    }

    /// Test that finish after a partial write works successfully without
    /// corrupting the frame. This test is in this module because it checks
    /// internal implementation details.
    #[test]
    fn test_partial_write_finish() {
        let (input, z) = setup_partial_write();

        // finish shouldn't corrupt the stream
        let buf = z.finish().unwrap().into_inner();
        assert_eq!(&decode_all(&buf[..]).unwrap(), &input);
    }

    fn setup_partial_write() -> (Vec<u8>, Encoder<WritePartial>) {
        use std::io::Write;

        let mut buf = WritePartial::new();
        buf.accept(Some(1));
        let mut z = Encoder::new(buf, 1).unwrap();

        // Fill in enough data to make sure the buffer gets written out.
        let input = "b".repeat(128 * 1024).into_bytes();
        z.write(&input).unwrap();

        // At this point, the internal buffer in z should have some data.
        assert_ne!(z.offset, z.buffer.len());

        (input, z)
    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2017-2018 Rene van der Meer
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.

#![allow(dead_code)]

use std::fmt;
use std::thread;
use std::time::{Duration, Instant};

use crate::gpio::epoll::{epoll_event, Epoll, EventFd, EPOLLERR, EPOLLET, EPOLLIN, EPOLLPRI};
use crate::gpio::ioctl;
use crate::gpio::{Error, Level, Result, Trigger};

#[derive(Debug)]
struct Interrupt {
    pin: u8,
    trigger: Trigger,
    cdev_fd: i32,
    event_fd: i32,
}

impl Interrupt {
    fn new(fd: i32, pin: u8, trigger: Trigger) -> Result<Interrupt> {
        let chip_info = ioctl::ChipInfo::new(fd)?;

        assert_pin!(u32::from(pin), chip_info.lines);

        let event_request = ioctl::EventRequest::new(fd, pin, trigger)?;

        Ok(Interrupt {
            pin,
            trigger,
            cdev_fd: fd,
            event_fd: event_request.fd,
        })
    }

    fn trigger(&self) -> Trigger {
        self.trigger
    }

    fn fd(&self) -> i32 {
        self.event_fd
    }

    fn pin(&self) -> u8 {
        self.pin
    }

    fn set_trigger(&mut self, trigger: Trigger) -> Result<()> {
        self.trigger = trigger;

        self.reset()
    }

    // This might block if there are no events waiting
    fn event(&mut self) -> Result<Option<ioctl::Event>> {
        ioctl::get_event(self.event_fd)
    }

    fn reset(&mut self) -> Result<()> {
        if self.event_fd > -1 {
            ioctl::close(self.event_fd);
            self.event_fd = -1;
        }

        let event_request = ioctl::EventRequest::new(self.cdev_fd, self.pin, self.trigger)?;
        self.event_fd = event_request.fd;

        Ok(())
    }

    fn level(&mut self) -> Result<Level> {
        ioctl::get_level(self.cdev_fd, self.pin)
    }
}

impl Drop for Interrupt {
    fn drop(&mut self) {
        if self.event_fd > -1 {
            ioctl::close(self.event_fd);
        }
    }
}

#[derive(Debug)]
struct TriggerStatus {
    interrupt: Option<Interrupt>,
    triggered: bool,
    level: Level,
}

pub struct EventLoop {
    poll: Epoll,
    events: Vec<epoll_event>,
    trigger_status: Vec<TriggerStatus>,
    cdev_fd: i32,
}

impl fmt::Debug for EventLoop {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_struct("EventLoop")
            .field("poll", &self.poll)
            .field("events", &format_args!("{{ .. }}"))
            .field("trigger_status", &format_args!("{{ .. }}"))
            .field("cdev_fd", &self.cdev_fd)
            .finish()
    }
}

impl EventLoop {
    pub fn new(cdev_fd: i32, capacity: usize) -> Result<EventLoop> {
        let mut trigger_status = Vec::with_capacity(capacity);

        // Initialize trigger_status while circumventing the Copy/Clone requirement
        for _ in 0..trigger_status.capacity() {
            trigger_status.push(TriggerStatus {
                interrupt: None,
                triggered: false,
                level: Level::Low,
            });
        }

        Ok(EventLoop {
            poll: Epoll::new()?,
            events: vec![epoll_event { events: 0, u64: 0 }; capacity],
            trigger_status,
            cdev_fd,
        })
    }

    pub fn poll(
        &mut self,
        pins: &[u8],
        reset: bool,
        timeout: Option<Duration>,
    ) -> Result<Option<(u8, Level)>> {
        for pin in pins {
            assert_pin!(*pin as usize, self.trigger_status.capacity());

            // Did we cache any trigger events during the previous poll?
            if self.trigger_status[*pin as usize].triggered {
                self.trigger_status[*pin as usize].triggered = false;

                if !reset {
                    return Ok(Some((*pin, self.trigger_status[*pin as usize].level)));
                }
            }

            // Reset any pending trigger events
            if let Some(ref mut interrupt) = self.trigger_status[*pin as usize].interrupt {
                if reset {
                    self.poll.delete(interrupt.fd())?;
                    interrupt.reset()?;
                    self.poll.add(
                        interrupt.fd(),
                        u64::from(interrupt.pin()),
                        EPOLLIN | EPOLLPRI,
                    )?;
                }
            }
        }

        // Loop until we get any of the events we're waiting for, or a timeout occurs
        let now = Instant::now();
        loop {
            let num_events = self.poll.wait(&mut self.events, timeout)?;

            // No events means a timeout occurred
            if num_events == 0 {
                return Ok(None);
            }

            for event in &self.events[0..num_events] {
                let pin = event.u64 as usize;
                if pin < self.trigger_status.capacity() {
                    self.trigger_status[pin].triggered = true;
                    self.trigger_status[pin].level =
                        if let Some(ref mut interrupt) = self.trigger_status[pin].interrupt {
                            if let Some(trigger_event) = interrupt.event()? {
                                match trigger_event.trigger {
                                    Trigger::RisingEdge => Level::High,
                                    _ => Level::Low,
                                }
                            } else {
                                interrupt.level()?
                            }
                        } else {
                            Level::Low
                        };
                }
            }

            // Were any interrupts triggered? If so, return one. The rest
            // will be saved for the next poll.
            for pin in pins {
                if self.trigger_status[*pin as usize].triggered {
                    self.trigger_status[*pin as usize].triggered = false;
                    return Ok(Some((*pin, self.trigger_status[*pin as usize].level)));
                }
            }

            // It's possible a pin we're not waiting for continuously triggers
            // an interrupt, causing repeated loops with calls to poll() using a
            // reset timeout value. Make sure we haven't been looping longer than
            // the requested timeout.
            if let Some(t) = timeout {
                if now.elapsed() > t {
                    return Ok(None);
                }
            }
        }
    }

    pub fn set_interrupt(&mut self, pin: u8, trigger: Trigger) -> Result<()> {
        self.trigger_status[pin as usize].triggered = false;

        // Interrupt already exists. We just need to change the trigger.
        if let Some(ref mut interrupt) = self.trigger_status[pin as usize].interrupt {
            if interrupt.trigger != trigger {
                // This requires a new event request, so the fd might change
                self.poll.delete(interrupt.fd())?;
                interrupt.set_trigger(trigger)?;
                self.poll
                    .add(interrupt.fd(), u64::from(pin), EPOLLIN | EPOLLPRI)?;
            }

            return Ok(());
        }

        // Register a new interrupt
        let interrupt = Interrupt::new(self.cdev_fd, pin, trigger)?;
        self.poll
            .add(interrupt.fd(), u64::from(pin), EPOLLIN | EPOLLPRI)?;
        self.trigger_status[pin as usize].interrupt = Some(interrupt);

        Ok(())
    }

    pub fn clear_interrupt(&mut self, pin: u8) -> Result<()> {
        self.trigger_status[pin as usize].triggered = false;

        if let Some(interrupt) = self.trigger_status[pin as usize].interrupt.take() {
            self.poll.delete(interrupt.fd())?;
        }

        Ok(())
    }
}

#[derive(Debug)]
pub struct AsyncInterrupt {
    poll_thread: Option<thread::JoinHandle<Result<()>>>,
    tx: EventFd,
}

impl AsyncInterrupt {
    pub fn new<C>(fd: i32, pin: u8, trigger: Trigger, mut callback: C) -> Result<AsyncInterrupt>
    where
        C: FnMut(Level) + Send + 'static,
    {
        let tx = EventFd::new()?;
        let rx = tx.fd();

        let poll_thread = thread::spawn(move || -> Result<()> {
            let poll = Epoll::new()?;

            // rx becomes readable when the main thread calls notify()
            poll.add(rx, rx as u64, EPOLLERR | EPOLLET | EPOLLIN)?;

            let mut interrupt = Interrupt::new(fd, pin, trigger)?;
            poll.add(interrupt.fd(), interrupt.fd() as u64, EPOLLIN | EPOLLPRI)?;

            let mut events = [epoll_event { events: 0, u64: 0 }; 2];
            loop {
                let num_events = poll.wait(&mut events, None)?;
                if num_events > 0 {
                    for event in &events[0..num_events] {
                        let fd = event.u64 as i32;
                        if fd == rx {
                            return Ok(()); // The main thread asked us to stop
                        } else if fd == interrupt.fd() {
                            let level = if let Some(trigger_event) = interrupt.event()? {
                                match trigger_event.trigger {
                                    Trigger::RisingEdge => Level::High,
                                    _ => Level::Low,
                                }
                            } else {
                                interrupt.level()?
                            };

                            callback(level);
                        }
                    }
                }
            }
        });

        Ok(AsyncInterrupt {
            poll_thread: Some(poll_thread),
            tx,
        })
    }

    pub fn stop(&mut self) -> Result<()> {
        self.tx.notify()?;

        if let Some(poll_thread) = self.poll_thread.take() {
            match poll_thread.join() {
                Ok(r) => return r,
                Err(_) => return Err(Error::ThreadPanic),
            }
        }

        Ok(())
    }
}
<commit_msg>Remove unnecessary check in event loop.<commit_after>// Copyright (c) 2017-2018 Rene van der Meer
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.

#![allow(dead_code)]

use std::fmt;
use std::thread;
use std::time::{Duration, Instant};

use crate::gpio::epoll::{epoll_event, Epoll, EventFd, EPOLLERR, EPOLLET, EPOLLIN, EPOLLPRI};
use crate::gpio::ioctl;
use crate::gpio::{Error, Level, Result, Trigger};

#[derive(Debug)]
struct Interrupt {
    pin: u8,
    trigger: Trigger,
    cdev_fd: i32,
    event_fd: i32,
}

impl Interrupt {
    fn new(fd: i32, pin: u8, trigger: Trigger) -> Result<Interrupt> {
        let chip_info = ioctl::ChipInfo::new(fd)?;

        assert_pin!(u32::from(pin), chip_info.lines);

        let event_request = ioctl::EventRequest::new(fd, pin, trigger)?;

        Ok(Interrupt {
            pin,
            trigger,
            cdev_fd: fd,
            event_fd: event_request.fd,
        })
    }

    fn trigger(&self) -> Trigger {
        self.trigger
    }

    fn fd(&self) -> i32 {
        self.event_fd
    }

    fn pin(&self) -> u8 {
        self.pin
    }

    fn set_trigger(&mut self, trigger: Trigger) -> Result<()> {
        self.trigger = trigger;

        self.reset()
    }

    // This might block if there are no events waiting
    fn event(&mut self) -> Result<Option<ioctl::Event>> {
        ioctl::get_event(self.event_fd)
    }

    fn reset(&mut self) -> Result<()> {
        if self.event_fd > -1 {
            ioctl::close(self.event_fd);
            self.event_fd = -1;
        }

        let event_request = ioctl::EventRequest::new(self.cdev_fd, self.pin, self.trigger)?;
        self.event_fd = event_request.fd;

        Ok(())
    }

    fn level(&mut self) -> Result<Level> {
        ioctl::get_level(self.cdev_fd, self.pin)
    }
}

impl Drop for Interrupt {
    fn drop(&mut self) {
        if self.event_fd > -1 {
            ioctl::close(self.event_fd);
        }
    }
}

#[derive(Debug)]
struct TriggerStatus {
    interrupt: Option<Interrupt>,
    triggered: bool,
    level: Level,
}

pub struct EventLoop {
    poll: Epoll,
    events: Vec<epoll_event>,
    trigger_status: Vec<TriggerStatus>,
    cdev_fd: i32,
}

impl fmt::Debug for EventLoop {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_struct("EventLoop")
            .field("poll", &self.poll)
            .field("events", &format_args!("{{ .. }}"))
            .field("trigger_status", &format_args!("{{ .. }}"))
            .field("cdev_fd", &self.cdev_fd)
            .finish()
    }
}

impl EventLoop {
    pub fn new(cdev_fd: i32, capacity: usize) -> Result<EventLoop> {
        let mut trigger_status = Vec::with_capacity(capacity);

        // Initialize trigger_status while circumventing the Copy/Clone requirement
        for _ in 0..trigger_status.capacity() {
            trigger_status.push(TriggerStatus {
                interrupt: None,
                triggered: false,
                level: Level::Low,
            });
        }

        Ok(EventLoop {
            poll: Epoll::new()?,
            events: vec![epoll_event { events: 0, u64: 0 }; capacity],
            trigger_status,
            cdev_fd,
        })
    }

    pub fn poll(
        &mut self,
        pins: &[u8],
        reset: bool,
        timeout: Option<Duration>,
    ) -> Result<Option<(u8, Level)>> {
        for pin in pins {
            // Did we cache any trigger events during the previous poll?
            if self.trigger_status[*pin as usize].triggered {
                self.trigger_status[*pin as usize].triggered = false;

                if !reset {
                    return Ok(Some((*pin, self.trigger_status[*pin as usize].level)));
                }
            }

            // Reset any pending trigger events
            if let Some(ref mut interrupt) = self.trigger_status[*pin as usize].interrupt {
                if reset {
                    self.poll.delete(interrupt.fd())?;
                    interrupt.reset()?;
                    self.poll.add(
                        interrupt.fd(),
                        u64::from(interrupt.pin()),
                        EPOLLIN | EPOLLPRI,
                    )?;
                }
            }
        }

        // Loop until we get any of the events we're waiting for, or a timeout occurs
        let now = Instant::now();
        loop {
            let num_events = self.poll.wait(&mut self.events, timeout)?;

            // No events means a timeout occurred
            if num_events == 0 {
                return Ok(None);
            }

            for event in &self.events[0..num_events] {
                let pin = event.u64 as usize;

                let ref mut trigger_status = self.trigger_status[pin];

                trigger_status.triggered = true;
                trigger_status.level =
                    if let Some(ref mut interrupt) = trigger_status.interrupt {
                        if let Some(trigger_event) = interrupt.event()? {
                            match trigger_event.trigger {
                                Trigger::RisingEdge => Level::High,
                                _ => Level::Low,
                            }
                        } else {
                            interrupt.level()?
                        }
                    } else {
                        Level::Low
                    };
            }

            // Were any interrupts triggered? If so, return one. The rest
            // will be saved for the next poll.
            for pin in pins {
                let ref mut trigger_status = self.trigger_status[*pin as usize];

                if trigger_status.triggered {
                    trigger_status.triggered = false;
                    return Ok(Some((*pin, trigger_status.level)));
                }
            }

            // It's possible a pin we're not waiting for continuously triggers
            // an interrupt, causing repeated loops with calls to poll() using a
            // reset timeout value. Make sure we haven't been looping longer than
            // the requested timeout.
            if let Some(t) = timeout {
                if now.elapsed() > t {
                    return Ok(None);
                }
            }
        }
    }

    pub fn set_interrupt(&mut self, pin: u8, trigger: Trigger) -> Result<()> {
        let ref mut trigger_status = self.trigger_status[pin as usize];

        trigger_status.triggered = false;

        // Interrupt already exists. We just need to change the trigger.
        if let Some(ref mut interrupt) = trigger_status.interrupt {
            if interrupt.trigger != trigger {
                // This requires a new event request, so the fd might change
                self.poll.delete(interrupt.fd())?;
                interrupt.set_trigger(trigger)?;
                self.poll
                    .add(interrupt.fd(), u64::from(pin), EPOLLIN | EPOLLPRI)?;
            }

            return Ok(());
        }

        // Register a new interrupt
        let interrupt = Interrupt::new(self.cdev_fd, pin, trigger)?;
        self.poll
            .add(interrupt.fd(), u64::from(pin), EPOLLIN | EPOLLPRI)?;
        trigger_status.interrupt = Some(interrupt);

        Ok(())
    }

    pub fn clear_interrupt(&mut self, pin: u8) -> Result<()> {
        let ref mut trigger_status = self.trigger_status[pin as usize];

        trigger_status.triggered = false;

        if let Some(interrupt) = trigger_status.interrupt.take() {
            self.poll.delete(interrupt.fd())?;
        }

        Ok(())
    }
}

#[derive(Debug)]
pub struct AsyncInterrupt {
    poll_thread: Option<thread::JoinHandle<Result<()>>>,
    tx: EventFd,
}

impl AsyncInterrupt {
    pub fn new<C>(fd: i32, pin: u8, trigger: Trigger, mut callback: C) -> Result<AsyncInterrupt>
    where
        C: FnMut(Level) + Send + 'static,
    {
        let tx = EventFd::new()?;
        let rx = tx.fd();

        let poll_thread = thread::spawn(move || -> Result<()> {
            let poll = Epoll::new()?;

            // rx becomes readable when the main thread calls notify()
            poll.add(rx, rx as u64, EPOLLERR | EPOLLET | EPOLLIN)?;

            let mut interrupt = Interrupt::new(fd, pin, trigger)?;
            poll.add(interrupt.fd(), interrupt.fd() as u64, EPOLLIN | EPOLLPRI)?;

            let mut events = [epoll_event { events: 0, u64: 0 }; 2];
            loop {
                let num_events = poll.wait(&mut events, None)?;
                if num_events > 0 {
                    for event in &events[0..num_events] {
                        let fd = event.u64 as i32;
                        if fd == rx {
                            return Ok(()); // The main thread asked us to stop
                        } else if fd == interrupt.fd() {
                            let level = if let Some(trigger_event) = interrupt.event()? {
                                match trigger_event.trigger {
                                    Trigger::RisingEdge => Level::High,
                                    _ => Level::Low,
                                }
                            } else {
                                interrupt.level()?
                            };

                            callback(level);
                        }
                    }
                }
            }
        });

        Ok(AsyncInterrupt {
            poll_thread: Some(poll_thread),
            tx,
        })
    }

    pub fn stop(&mut self) -> Result<()> {
        self.tx.notify()?;

        if let Some(poll_thread) = self.poll_thread.take() {
            match poll_thread.join() {
                Ok(r) => return r,
                Err(_) => return Err(Error::ThreadPanic),
            }
        }

        Ok(())
    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2017-2018 Rene van der Meer
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.

use std::fs::File;
use std::io;
use std::io::{Read, Seek, SeekFrom};
use std::os::unix::io::AsRawFd;
use std::result;
use std::sync::mpsc::TryRecvError;
use std::thread;
use std::time::Duration;

use mio::event::Evented;
use mio::unix::{EventedFd, UnixReady};
use mio::{Events, Poll, PollOpt, Ready, Token};
use mio_extras::channel;

use gpio::sysfs;

pub use gpio::sysfs::Direction;
pub use gpio::{Level, Trigger};

quick_error! {
    #[derive(Debug)]
/// Errors that can occur while working with interrupts.
    pub enum Error {
/// Synchronous interrupt isn't initialized.
        NotInitialized { description("not initialized") }
/// Time out.
        TimeOut { description("interrupt polling timed out while waiting for a trigger") }
/// IO error.
        Io(err: io::Error) { description(err.description()) from() }
/// Sysfs error.
        Sysfs(err: sysfs::Error) { description(err.description()) from() }
/// IO error while communicating with the interrupt polling thread.
        SendIo(err: io::Error) { description(err.description()) }
/// Disconnected while sending a control message to the interrupt polling thread.
        SendDisconnected { description("receiving half of the channel has disconnected") }
/// Interrupt polling thread panicked.
        ThreadPanic { description("interrupt polling thread panicked") }
    }
}

impl<T> From<channel::SendError<T>> for Error {
    fn from(err: channel::SendError<T>) -> Error {
        match err {
            channel::SendError::Io(e) => Error::SendIo(e),
            channel::SendError::Disconnected(_) => Error::SendDisconnected,
        }
    }
}

/// Result type returned from methods that can have `rppal::gpio::interrupt::Error`s.
pub type Result<T> = result::Result<T, Error>;

const TOKEN_RX: usize = 0;
const TOKEN_PIN: usize = 1;

struct Interrupt {
    pin: u8,
    trigger: Trigger,
    sysfs_value: File,
}

impl Interrupt {
    fn new(pin: u8, trigger: Trigger) -> Result<Interrupt> {
        // Export the GPIO pin so we can configure it through sysfs, set its mode to
        // input, and set the trigger type.
        sysfs::export(pin)?;
        sysfs::set_direction(pin, Direction::In)?;
        sysfs::set_edge(pin, trigger)?;

        Ok(Interrupt {
            pin,
            trigger,
            sysfs_value: sysfs::open_value(pin)?,
        })
    }

    fn trigger(&self) -> Trigger {
        self.trigger
    }

    fn set_trigger(&mut self, trigger: Trigger) -> Result<()> {
        self.trigger = trigger;
        sysfs::set_edge(self.pin, trigger)?;

        Ok(())
    }

    fn level(&mut self) -> Result<Level> {
        let mut buffer = [0; 1];
        self.sysfs_value.read_exact(&mut buffer)?;
        self.sysfs_value.seek(SeekFrom::Start(0))?;

        match &buffer {
            b"0" => Ok(Level::Low),
            _ => Ok(Level::High),
        }
    }
}

impl Drop for Interrupt {
    fn drop(&mut self) {
        sysfs::unexport(self.pin).ok();
    }
}

impl Evented for Interrupt {
    fn register(
        &self,
        poll: &Poll,
        token: Token,
        interest: Ready,
        opts: PollOpt,
    ) -> io::Result<()> {
        EventedFd(&self.sysfs_value.as_raw_fd()).register(poll, token, interest, opts)
    }

    fn reregister(
        &self,
        poll: &Poll,
        token: Token,
        interest: Ready,
        opts: PollOpt,
    ) -> io::Result<()> {
        EventedFd(&self.sysfs_value.as_raw_fd()).reregister(poll, token, interest, opts)
    }

    fn deregister(&self, poll: &Poll) -> io::Result<()> {
        EventedFd(&self.sysfs_value.as_raw_fd()).deregister(poll)
    }
}

struct TriggerStatus {
    interrupt: Option<Interrupt>,
    triggered: bool,
    level: Level,
}

pub struct EventLoop {
    poll: Poll,
    events: Events,
    trigger_status: Vec<TriggerStatus>,
}

impl EventLoop {
    pub fn new(capacity: usize) -> Result<EventLoop> {
        let mut trigger_status = Vec::with_capacity(capacity);

        // Initialize trigger_status while circumventing the Copy/Clone requirement
        for _ in 0..trigger_status.capacity() {
            trigger_status.push(TriggerStatus {
                interrupt: None,
                triggered: false,
                level: Level::Low,
            });
        }

        Ok(EventLoop {
            poll: Poll::new()?,
            events: Events::with_capacity(capacity),
            trigger_status,
        })
    }

    pub fn poll(
        &mut self,
        pins: &[u8],
        reset: bool,
        timeout: Option<Duration>,
    ) -> Result<(u8, Level)> {
        // Has any of the pins we're polling already been triggered?
        for pin in pins {
            if *pin as usize >= self.trigger_status.capacity() {
                return Err(Error::NotInitialized);
            }

            if self.trigger_status[*pin as usize].triggered {
                self.trigger_status[*pin as usize].triggered = false;

                // Only return if we're not ignoring the stored trigger events
                if !reset {
                    return Ok((*pin, self.trigger_status[*pin as usize].level));
                }
            }
        }

        // Loop until we get any of the events we're waiting for, or a timeout occurs
        loop {
            self.poll.poll(&mut self.events, timeout)?;

            // No events means a timeout occurred
            if self.events.is_empty() {
                return Err(Error::TimeOut);
            }

            for event in &self.events {
                if event.token().0 < self.trigger_status.capacity()
                    && event.readiness().is_readable()
                    && UnixReady::from(event.readiness()).is_error()
                {
                    self.trigger_status[event.token().0].triggered = true;
                    self.trigger_status[event.token().0].level = if let Some(ref mut interrupt) =
                        self.trigger_status[event.token().0].interrupt
                    {
                        interrupt.level()?
                    } else {
                        Level::Low
                    };
                }
            }

            // Were any interrupts triggered? If so, return one. The rest
            // will be saved for the next poll.
            for pin in pins {
                if self.trigger_status[*pin as usize].triggered {
                    self.trigger_status[*pin as usize].triggered = false;
                    return Ok((*pin, self.trigger_status[*pin as usize].level));
                }
            }

            // TODO: If there's a timeout set, reduce it here
        }
    }

    pub fn set_interrupt(&mut self, pin: u8, trigger: Trigger) -> Result<()> {
        self.trigger_status[pin as usize].triggered = false;

        // Interrupt already exists. We just need to change the trigger.
        if let Some(ref mut interrupt) = self.trigger_status[pin as usize].interrupt {
            if interrupt.trigger != trigger {
                interrupt.set_trigger(trigger)?;
            }

            return Ok(());
        }

        // Register a new interrupt
        let mut base = Interrupt::new(pin, trigger)?;

        base.level()?;
        self.poll.register(
            &base,
            Token(pin as usize),
            Ready::readable() | UnixReady::error(),
            PollOpt::edge(),
        )?;

        self.trigger_status[pin as usize].interrupt = Some(base);

        Ok(())
    }

    pub fn clear_interrupt(&mut self, pin: u8) -> Result<()> {
        self.trigger_status[pin as usize].triggered = false;

        if let Some(interrupt) = self.trigger_status[pin as usize].interrupt.take() {
            self.poll.deregister(&interrupt)?;
        }

        Ok(())
    }
}

enum ControlMsg {
    Stop,
}

pub struct AsyncInterrupt {
    pin: u8,
    poll_thread: Option<thread::JoinHandle<Result<()>>>,
    tx: channel::Sender<ControlMsg>,
}

impl AsyncInterrupt {
    pub fn new<C>(pin: u8, trigger: Trigger, mut callback: C) -> Result<AsyncInterrupt>
    where
        C: FnMut(Level) + Send + 'static,
    {
        let (tx, rx) = channel::channel();

        let poll_thread = thread::spawn(move || -> Result<()> {
            let poll = Poll::new()?;
            let mut events = Events::with_capacity(2);

            poll.register(&rx, Token(TOKEN_RX), Ready::readable(), PollOpt::edge())?;

            let mut base = Interrupt::new(pin, trigger)?;
            base.level()?;
            poll.register(
                &base,
                Token(TOKEN_PIN),
                Ready::readable() | UnixReady::error(),
                PollOpt::edge(),
            )?;

            loop {
                poll.poll(&mut events, None)?;

                for event in &events {
                    if event.token() == Token(TOKEN_RX) {
                        match rx.try_recv() {
                            Ok(ControlMsg::Stop) => {
                                return Ok(());
                            }
                            Err(TryRecvError::Disconnected) => {
                                return Ok(());
                            }
                            Err(TryRecvError::Empty) => {
                                break;
                            }
                        }
                    } else if event.token() == Token(TOKEN_PIN) && event.readiness().is_readable()
                        && UnixReady::from(event.readiness()).is_error()
                    {
                        let interrupt_value = base.level()?;

                        callback(interrupt_value);
                    }
                }
            }
        });

        Ok(AsyncInterrupt {
            pin,
            poll_thread: Some(poll_thread),
            tx,
        })
    }

    pub fn stop(&mut self) -> Result<()> {
        self.tx.send(ControlMsg::Stop)?;

        if let Some(poll_thread) = self.poll_thread.take() {
            match poll_thread.join() {
                Ok(r) => return r,
                Err(_) => return Err(Error::ThreadPanic),
            }
        }

        Ok(())
    }
}

impl Drop for AsyncInterrupt {
    fn drop(&mut self) {
        // Unexport the pin here, because we can't rely on the thread
        // living long enough to unexport it.
        sysfs::unexport(self.pin).ok();
    }
}
<commit_msg>Reset pending trigger events for sync interrupts<commit_after>// Copyright (c) 2017-2018 Rene van der Meer
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.

use std::fs::File;
use std::io;
use std::io::{Read, Seek, SeekFrom};
use std::os::unix::io::AsRawFd;
use std::result;
use std::sync::mpsc::TryRecvError;
use std::thread;
use std::time::Duration;

use mio::event::Evented;
use mio::unix::{EventedFd, UnixReady};
use mio::{Events, Poll, PollOpt, Ready, Token};
use mio_extras::channel;

use gpio::sysfs;

pub use gpio::sysfs::Direction;
pub use gpio::{Level, Trigger};

quick_error! {
    #[derive(Debug)]
/// Errors that can occur while working with interrupts.
    pub enum Error {
/// Synchronous interrupt isn't initialized.
        NotInitialized { description("not initialized") }
/// Time out.
        TimeOut { description("interrupt polling timed out while waiting for a trigger") }
/// IO error.
        Io(err: io::Error) { description(err.description()) from() }
/// Sysfs error.
        Sysfs(err: sysfs::Error) { description(err.description()) from() }
/// IO error while communicating with the interrupt polling thread.
        SendIo(err: io::Error) { description(err.description()) }
/// Disconnected while sending a control message to the interrupt polling thread.
        SendDisconnected { description("receiving half of the channel has disconnected") }
/// Interrupt polling thread panicked.
        ThreadPanic { description("interrupt polling thread panicked") }
    }
}

impl<T> From<channel::SendError<T>> for Error {
    fn from(err: channel::SendError<T>) -> Error {
        match err {
            channel::SendError::Io(e) => Error::SendIo(e),
            channel::SendError::Disconnected(_) => Error::SendDisconnected,
        }
    }
}

/// Result type returned from methods that can have `rppal::gpio::interrupt::Error`s.
pub type Result<T> = result::Result<T, Error>;

const TOKEN_RX: usize = 0;
const TOKEN_PIN: usize = 1;

struct Interrupt {
    pin: u8,
    trigger: Trigger,
    sysfs_value: File,
}

impl Interrupt {
    fn new(pin: u8, trigger: Trigger) -> Result<Interrupt> {
        // Export the GPIO pin so we can configure it through sysfs, set its mode to
        // input, and set the trigger type.
        sysfs::export(pin)?;
        sysfs::set_direction(pin, Direction::In)?;
        sysfs::set_edge(pin, trigger)?;

        Ok(Interrupt {
            pin,
            trigger,
            sysfs_value: sysfs::open_value(pin)?,
        })
    }

    fn trigger(&self) -> Trigger {
        self.trigger
    }

    fn set_trigger(&mut self, trigger: Trigger) -> Result<()> {
        self.trigger = trigger;
        sysfs::set_edge(self.pin, trigger)?;

        Ok(())
    }

    fn level(&mut self) -> Result<Level> {
        let mut buffer = [0; 1];
        self.sysfs_value.read_exact(&mut buffer)?;
        self.sysfs_value.seek(SeekFrom::Start(0))?;

        match &buffer {
            b"0" => Ok(Level::Low),
            _ => Ok(Level::High),
        }
    }
}

impl Drop for Interrupt {
    fn drop(&mut self) {
        sysfs::unexport(self.pin).ok();
    }
}

impl Evented for Interrupt {
    fn register(
        &self,
        poll: &Poll,
        token: Token,
        interest: Ready,
        opts: PollOpt,
    ) -> io::Result<()> {
        EventedFd(&self.sysfs_value.as_raw_fd()).register(poll, token, interest, opts)
    }

    fn reregister(
        &self,
        poll: &Poll,
        token: Token,
        interest: Ready,
        opts: PollOpt,
    ) -> io::Result<()> {
        EventedFd(&self.sysfs_value.as_raw_fd()).reregister(poll, token, interest, opts)
    }

    fn deregister(&self, poll: &Poll) -> io::Result<()> {
        EventedFd(&self.sysfs_value.as_raw_fd()).deregister(poll)
    }
}

struct TriggerStatus {
    interrupt: Option<Interrupt>,
    triggered: bool,
    level: Level,
}

pub struct EventLoop {
    poll: Poll,
    events: Events,
    trigger_status: Vec<TriggerStatus>,
}

impl EventLoop {
    pub fn new(capacity: usize) -> Result<EventLoop> {
        let mut trigger_status = Vec::with_capacity(capacity);

        // Initialize trigger_status while circumventing the Copy/Clone requirement
        for _ in 0..trigger_status.capacity() {
            trigger_status.push(TriggerStatus {
                interrupt: None,
                triggered: false,
                level: Level::Low,
            });
        }

        Ok(EventLoop {
            poll: Poll::new()?,
            events: Events::with_capacity(capacity),
            trigger_status,
        })
    }

    pub fn poll(
        &mut self,
        pins: &[u8],
        reset: bool,
        timeout: Option<Duration>,
    ) -> Result<(u8, Level)> {
        for pin in pins {
            if *pin as usize >= self.trigger_status.capacity() {
                return Err(Error::NotInitialized);
            }

            // Did we cache any triggers during the previous poll?
            if self.trigger_status[*pin as usize].triggered {
                self.trigger_status[*pin as usize].triggered = false;

                if !reset {
                    return Ok((*pin, self.trigger_status[*pin as usize].level));
                }
            }

            // Read the logic level to reset any pending trigger events
            if let Some(ref mut interrupt) = self.trigger_status[*pin as usize].interrupt {
                if reset {
                    interrupt.level()?;
                }
            }
        }

        // Loop until we get any of the events we're waiting for, or a timeout occurs
        loop {
            self.poll.poll(&mut self.events, timeout)?;

            // No events means a timeout occurred
            if self.events.is_empty() {
                return Err(Error::TimeOut);
            }

            for event in &self.events {
                if event.token().0 < self.trigger_status.capacity()
                    && event.readiness().is_readable()
                    && UnixReady::from(event.readiness()).is_error()
                {
                    self.trigger_status[event.token().0].triggered = true;
                    self.trigger_status[event.token().0].level = if let Some(ref mut interrupt) =
                        self.trigger_status[event.token().0].interrupt
                    {
                        interrupt.level()?
                    } else {
                        Level::Low
                    };
                }
            }

            // Were any interrupts triggered? If so, return one. The rest
            // will be saved for the next poll.
            for pin in pins {
                if self.trigger_status[*pin as usize].triggered {
                    self.trigger_status[*pin as usize].triggered = false;
                    return Ok((*pin, self.trigger_status[*pin as usize].level));
                }
            }

            // TODO: If there's a timeout set, reduce it here
        }
    }

    pub fn set_interrupt(&mut self, pin: u8, trigger: Trigger) -> Result<()> {
        self.trigger_status[pin as usize].triggered = false;

        // Interrupt already exists. We just need to change the trigger.
        if let Some(ref mut interrupt) = self.trigger_status[pin as usize].interrupt {
            if interrupt.trigger != trigger {
                interrupt.set_trigger(trigger)?;
            }

            return Ok(());
        }

        // Register a new interrupt
        let mut base = Interrupt::new(pin, trigger)?;

        base.level()?;
        self.poll.register(
            &base,
            Token(pin as usize),
            Ready::readable() | UnixReady::error(),
            PollOpt::edge(),
        )?;

        self.trigger_status[pin as usize].interrupt = Some(base);

        Ok(())
    }

    pub fn clear_interrupt(&mut self, pin: u8) -> Result<()> {
        self.trigger_status[pin as usize].triggered = false;

        if let Some(interrupt) = self.trigger_status[pin as usize].interrupt.take() {
            self.poll.deregister(&interrupt)?;
        }

        Ok(())
    }
}

enum ControlMsg {
    Stop,
}

pub struct AsyncInterrupt {
    pin: u8,
    poll_thread: Option<thread::JoinHandle<Result<()>>>,
    tx: channel::Sender<ControlMsg>,
}

impl AsyncInterrupt {
    pub fn new<C>(pin: u8, trigger: Trigger, mut callback: C) -> Result<AsyncInterrupt>
    where
        C: FnMut(Level) + Send + 'static,
    {
        let (tx, rx) = channel::channel();

        let poll_thread = thread::spawn(move || -> Result<()> {
            let poll = Poll::new()?;
            let mut events = Events::with_capacity(2);

            poll.register(&rx, Token(TOKEN_RX), Ready::readable(), PollOpt::edge())?;

            let mut base = Interrupt::new(pin, trigger)?;
            base.level()?;
            poll.register(
                &base,
                Token(TOKEN_PIN),
                Ready::readable() | UnixReady::error(),
                PollOpt::edge(),
            )?;

            loop {
                poll.poll(&mut events, None)?;

                for event in &events {
                    if event.token() == Token(TOKEN_RX) {
                        match rx.try_recv() {
                            Ok(ControlMsg::Stop) => {
                                return Ok(());
                            }
                            Err(TryRecvError::Disconnected) => {
                                return Ok(());
                            }
                            Err(TryRecvError::Empty) => {
                                break;
                            }
                        }
                    } else if event.token() == Token(TOKEN_PIN) && event.readiness().is_readable()
                        && UnixReady::from(event.readiness()).is_error()
                    {
                        let interrupt_value = base.level()?;

                        callback(interrupt_value);
                    }
                }
            }
        });

        Ok(AsyncInterrupt {
            pin,
            poll_thread: Some(poll_thread),
            tx,
        })
    }

    pub fn stop(&mut self) -> Result<()> {
        self.tx.send(ControlMsg::Stop)?;

        if let Some(poll_thread) = self.poll_thread.take() {
            match poll_thread.join() {
                Ok(r) => return r,
                Err(_) => return Err(Error::ThreadPanic),
            }
        }

        Ok(())
    }
}

impl Drop for AsyncInterrupt {
    fn drop(&mut self) {
        // Unexport the pin here, because we can't rely on the thread
        // living long enough to unexport it.
        sysfs::unexport(self.pin).ok();
    }
}
<|endoftext|>


<commit_before>#![warn(rust_2018_idioms)] // while we're getting used to 2018
#![allow(clippy::all)]

use cargo::core::shell::Shell;
use cargo::util::toml::StringOrVec;
use cargo::util::CliError;
use cargo::util::{self, closest_msg, command_prelude, CargoResult, CliResult, Config};
use cargo_util::{ProcessBuilder, ProcessError};
use std::collections::BTreeMap;
use std::env;
use std::fs;
use std::path::{Path, PathBuf};

mod cli;
mod commands;

use crate::command_prelude::*;

fn main() {
    #[cfg(feature = "pretty-env-logger")]
    pretty_env_logger::init_custom_env("CARGO_LOG");
    #[cfg(not(feature = "pretty-env-logger"))]
    env_logger::init_from_env("CARGO_LOG");

    let mut config = match Config::default() {
        Ok(cfg) => cfg,
        Err(e) => {
            let mut shell = Shell::new();
            cargo::exit_with_error(e.into(), &mut shell)
        }
    };

    let result = match cargo::ops::fix_maybe_exec_rustc(&config) {
        Ok(true) => Ok(()),
        Ok(false) => {
            let _token = cargo::util::job::setup();
            cli::main(&mut config)
        }
        Err(e) => Err(CliError::from(e)),
    };

    match result {
        Err(e) => cargo::exit_with_error(e, &mut *config.shell()),
        Ok(()) => {}
    }
}

/// Table for defining the aliases which come builtin in `Cargo`.
/// The contents are structured as: `(alias, aliased_command, description)`.
const BUILTIN_ALIASES: [(&str, &str, &str); 5] = [
    ("b", "build", "alias: build"),
    ("c", "check", "alias: check"),
    ("d", "doc", "alias: doc"),
    ("r", "run", "alias: run"),
    ("t", "test", "alias: test"),
];

/// Function which contains the list of all of the builtin aliases and it's
/// corresponding execs represented as &str.
fn builtin_aliases_execs(cmd: &str) -> Option<&(&str, &str, &str)> {
    BUILTIN_ALIASES.iter().find(|alias| alias.0 == cmd)
}

fn aliased_command(config: &Config, command: &str) -> CargoResult<Option<Vec<String>>> {
    let alias_name = format!("alias.{}", command);
    let user_alias = match config.get_string(&alias_name) {
        Ok(Some(record)) => Some(
            record
                .val
                .split_whitespace()
                .map(|s| s.to_string())
                .collect(),
        ),
        Ok(None) => None,
        Err(_) => config.get::<Option<Vec<String>>>(&alias_name)?,
    };

    let result = user_alias.or_else(|| {
        builtin_aliases_execs(command).map(|command_str| vec![command_str.1.to_string()])
    });
    Ok(result)
}

/// List all runnable commands
fn list_commands(config: &Config) -> BTreeMap<String, CommandInfo> {
    let prefix = "cargo-";
    let suffix = env::consts::EXE_SUFFIX;
    let mut commands = BTreeMap::new();
    for dir in search_directories(config) {
        let entries = match fs::read_dir(dir) {
            Ok(entries) => entries,
            _ => continue,
        };
        for entry in entries.filter_map(|e| e.ok()) {
            let path = entry.path();
            let filename = match path.file_name().and_then(|s| s.to_str()) {
                Some(filename) => filename,
                _ => continue,
            };
            if !filename.starts_with(prefix) || !filename.ends_with(suffix) {
                continue;
            }
            if is_executable(entry.path()) {
                let end = filename.len() - suffix.len();
                commands.insert(
                    filename[prefix.len()..end].to_string(),
                    CommandInfo::External { path: path.clone() },
                );
            }
        }
    }

    for cmd in commands::builtin() {
        commands.insert(
            cmd.get_name().to_string(),
            CommandInfo::BuiltIn {
                about: cmd.get_about().map(|s| s.to_string()),
            },
        );
    }

    // Add the builtin_aliases and them descriptions to the
    // `commands` `BTreeMap`.
    for command in &BUILTIN_ALIASES {
        commands.insert(
            command.0.to_string(),
            CommandInfo::BuiltIn {
                about: Some(command.2.to_string()),
            },
        );
    }

    // Add the user-defined aliases
    if let Ok(aliases) = config.get::<BTreeMap<String, StringOrVec>>("alias") {
        for (name, target) in aliases.iter() {
            commands.insert(
                name.to_string(),
                CommandInfo::Alias {
                    target: target.clone(),
                },
            );
        }
    }

    // `help` is special, so it needs to be inserted separately.
    commands.insert(
        "help".to_string(),
        CommandInfo::BuiltIn {
            about: Some("Displays help for a cargo subcommand".to_string()),
        },
    );

    commands
}

fn find_external_subcommand(config: &Config, cmd: &str) -> Option<PathBuf> {
    let command_exe = format!("cargo-{}{}", cmd, env::consts::EXE_SUFFIX);
    search_directories(config)
        .iter()
        .map(|dir| dir.join(&command_exe))
        .find(|file| is_executable(file))
}

fn execute_external_subcommand(config: &Config, cmd: &str, args: &[&str]) -> CliResult {
    let path = find_external_subcommand(config, cmd);
    let command = match path {
        Some(command) => command,
        None => {
            let err = if cmd.starts_with('+') {
                anyhow::format_err!("no such subcommand: `{}`\n\n\tCargo does not handle `+toolchain` directives.\n\tDid you mean to run `cargo` through `rustup` instead?", cmd)
            } else {
                let suggestions = list_commands(config);
                let did_you_mean = closest_msg(cmd, suggestions.keys(), |c| c);

                if did_you_mean.is_empty() {
                    anyhow::format_err!("no such subcommand: `{}`\n\n\tView all installed commands with `cargo --list`", cmd)
                } else {
                    anyhow::format_err!("no such subcommand: `{}`{}\n\tView all installed commands with `cargo --list`", cmd, did_you_mean)
                }
            };

            return Err(CliError::new(err, 101));
        }
    };

    let cargo_exe = config.cargo_exe()?;
    let err = match ProcessBuilder::new(&command)
        .env(cargo::CARGO_ENV, cargo_exe)
        .args(args)
        .exec_replace()
    {
        Ok(()) => return Ok(()),
        Err(e) => e,
    };

    if let Some(perr) = err.downcast_ref::<ProcessError>() {
        if let Some(code) = perr.code {
            return Err(CliError::code(code));
        }
    }
    Err(CliError::new(err, 101))
}

#[cfg(unix)]
fn is_executable<P: AsRef<Path>>(path: P) -> bool {
    use std::os::unix::prelude::*;
    fs::metadata(path)
        .map(|metadata| metadata.is_file() && metadata.permissions().mode() & 0o111 != 0)
        .unwrap_or(false)
}
#[cfg(windows)]
fn is_executable<P: AsRef<Path>>(path: P) -> bool {
    path.as_ref().is_file()
}

fn search_directories(config: &Config) -> Vec<PathBuf> {
    let mut dirs = vec![config.home().clone().into_path_unlocked().join("bin")];
    if let Some(val) = env::var_os("PATH") {
        dirs.extend(env::split_paths(&val));
    }
    dirs
}

fn init_git_transports(config: &Config) {
    // Only use a custom transport if any HTTP options are specified,
    // such as proxies or custom certificate authorities. The custom
    // transport, however, is not as well battle-tested.

    match cargo::ops::needs_custom_http_transport(config) {
        Ok(true) => {}
        _ => return,
    }

    let handle = match cargo::ops::http_handle(config) {
        Ok(handle) => handle,
        Err(..) => return,
    };

    // The unsafety of the registration function derives from two aspects:
    //
    // 1. This call must be synchronized with all other registration calls as
    //    well as construction of new transports.
    // 2. The argument is leaked.
    //
    // We're clear on point (1) because this is only called at the start of this
    // binary (we know what the state of the world looks like) and we're mostly
    // clear on point (2) because we'd only free it after everything is done
    // anyway
    unsafe {
        git2_curl::register(handle);
    }
}
<commit_msg>improve formatting<commit_after>#![warn(rust_2018_idioms)] // while we're getting used to 2018
#![allow(clippy::all)]

use cargo::core::shell::Shell;
use cargo::util::toml::StringOrVec;
use cargo::util::CliError;
use cargo::util::{self, closest_msg, command_prelude, CargoResult, CliResult, Config};
use cargo_util::{ProcessBuilder, ProcessError};
use std::collections::BTreeMap;
use std::env;
use std::fs;
use std::path::{Path, PathBuf};

mod cli;
mod commands;

use crate::command_prelude::*;

fn main() {
    #[cfg(feature = "pretty-env-logger")]
    pretty_env_logger::init_custom_env("CARGO_LOG");
    #[cfg(not(feature = "pretty-env-logger"))]
    env_logger::init_from_env("CARGO_LOG");

    let mut config = match Config::default() {
        Ok(cfg) => cfg,
        Err(e) => {
            let mut shell = Shell::new();
            cargo::exit_with_error(e.into(), &mut shell)
        }
    };

    let result = match cargo::ops::fix_maybe_exec_rustc(&config) {
        Ok(true) => Ok(()),
        Ok(false) => {
            let _token = cargo::util::job::setup();
            cli::main(&mut config)
        }
        Err(e) => Err(CliError::from(e)),
    };

    match result {
        Err(e) => cargo::exit_with_error(e, &mut *config.shell()),
        Ok(()) => {}
    }
}

/// Table for defining the aliases which come builtin in `Cargo`.
/// The contents are structured as: `(alias, aliased_command, description)`.
const BUILTIN_ALIASES: [(&str, &str, &str); 5] = [
    ("b", "build", "alias: build"),
    ("c", "check", "alias: check"),
    ("d", "doc", "alias: doc"),
    ("r", "run", "alias: run"),
    ("t", "test", "alias: test"),
];

/// Function which contains the list of all of the builtin aliases and it's
/// corresponding execs represented as &str.
fn builtin_aliases_execs(cmd: &str) -> Option<&(&str, &str, &str)> {
    BUILTIN_ALIASES.iter().find(|alias| alias.0 == cmd)
}

fn aliased_command(config: &Config, command: &str) -> CargoResult<Option<Vec<String>>> {
    let alias_name = format!("alias.{}", command);
    let user_alias = match config.get_string(&alias_name) {
        Ok(Some(record)) => Some(
            record
                .val
                .split_whitespace()
                .map(|s| s.to_string())
                .collect(),
        ),
        Ok(None) => None,
        Err(_) => config.get::<Option<Vec<String>>>(&alias_name)?,
    };

    let result = user_alias.or_else(|| {
        builtin_aliases_execs(command).map(|command_str| vec![command_str.1.to_string()])
    });
    Ok(result)
}

/// List all runnable commands
fn list_commands(config: &Config) -> BTreeMap<String, CommandInfo> {
    let prefix = "cargo-";
    let suffix = env::consts::EXE_SUFFIX;
    let mut commands = BTreeMap::new();
    for dir in search_directories(config) {
        let entries = match fs::read_dir(dir) {
            Ok(entries) => entries,
            _ => continue,
        };
        for entry in entries.filter_map(|e| e.ok()) {
            let path = entry.path();
            let filename = match path.file_name().and_then(|s| s.to_str()) {
                Some(filename) => filename,
                _ => continue,
            };
            if !filename.starts_with(prefix) || !filename.ends_with(suffix) {
                continue;
            }
            if is_executable(entry.path()) {
                let end = filename.len() - suffix.len();
                commands.insert(
                    filename[prefix.len()..end].to_string(),
                    CommandInfo::External { path: path.clone() },
                );
            }
        }
    }

    for cmd in commands::builtin() {
        commands.insert(
            cmd.get_name().to_string(),
            CommandInfo::BuiltIn {
                about: cmd.get_about().map(|s| s.to_string()),
            },
        );
    }

    // Add the builtin_aliases and them descriptions to the
    // `commands` `BTreeMap`.
    for command in &BUILTIN_ALIASES {
        commands.insert(
            command.0.to_string(),
            CommandInfo::BuiltIn {
                about: Some(command.2.to_string()),
            },
        );
    }

    // Add the user-defined aliases
    if let Ok(aliases) = config.get::<BTreeMap<String, StringOrVec>>("alias") {
        for (name, target) in aliases.iter() {
            commands.insert(
                name.to_string(),
                CommandInfo::Alias {
                    target: target.clone(),
                },
            );
        }
    }

    // `help` is special, so it needs to be inserted separately.
    commands.insert(
        "help".to_string(),
        CommandInfo::BuiltIn {
            about: Some("Displays help for a cargo subcommand".to_string()),
        },
    );

    commands
}

fn find_external_subcommand(config: &Config, cmd: &str) -> Option<PathBuf> {
    let command_exe = format!("cargo-{}{}", cmd, env::consts::EXE_SUFFIX);
    search_directories(config)
        .iter()
        .map(|dir| dir.join(&command_exe))
        .find(|file| is_executable(file))
}

fn execute_external_subcommand(config: &Config, cmd: &str, args: &[&str]) -> CliResult {
    let path = find_external_subcommand(config, cmd);
    let command = match path {
        Some(command) => command,
        None => {
            let err = if cmd.starts_with('+') {
                anyhow::format_err!(
                    "no such subcommand: `{}`\n\n\t\
                    Cargo does not handle `+toolchain` directives.\n\t\
                    Did you mean to run `cargo` through `rustup` instead?",
                    cmd
                )
            } else {
                let suggestions = list_commands(config);
                let did_you_mean = closest_msg(cmd, suggestions.keys(), |c| c);

                anyhow::format_err!(
                    "no such subcommand: `{}`{}\n\n\t\
                    View all installed commands with `cargo --list`",
                    cmd,
                    did_you_mean
                )
            };

            return Err(CliError::new(err, 101));
        }
    };

    let cargo_exe = config.cargo_exe()?;
    let err = match ProcessBuilder::new(&command)
        .env(cargo::CARGO_ENV, cargo_exe)
        .args(args)
        .exec_replace()
    {
        Ok(()) => return Ok(()),
        Err(e) => e,
    };

    if let Some(perr) = err.downcast_ref::<ProcessError>() {
        if let Some(code) = perr.code {
            return Err(CliError::code(code));
        }
    }
    Err(CliError::new(err, 101))
}

#[cfg(unix)]
fn is_executable<P: AsRef<Path>>(path: P) -> bool {
    use std::os::unix::prelude::*;
    fs::metadata(path)
        .map(|metadata| metadata.is_file() && metadata.permissions().mode() & 0o111 != 0)
        .unwrap_or(false)
}
#[cfg(windows)]
fn is_executable<P: AsRef<Path>>(path: P) -> bool {
    path.as_ref().is_file()
}

fn search_directories(config: &Config) -> Vec<PathBuf> {
    let mut dirs = vec![config.home().clone().into_path_unlocked().join("bin")];
    if let Some(val) = env::var_os("PATH") {
        dirs.extend(env::split_paths(&val));
    }
    dirs
}

fn init_git_transports(config: &Config) {
    // Only use a custom transport if any HTTP options are specified,
    // such as proxies or custom certificate authorities. The custom
    // transport, however, is not as well battle-tested.

    match cargo::ops::needs_custom_http_transport(config) {
        Ok(true) => {}
        _ => return,
    }

    let handle = match cargo::ops::http_handle(config) {
        Ok(handle) => handle,
        Err(..) => return,
    };

    // The unsafety of the registration function derives from two aspects:
    //
    // 1. This call must be synchronized with all other registration calls as
    //    well as construction of new transports.
    // 2. The argument is leaked.
    //
    // We're clear on point (1) because this is only called at the start of this
    // binary (we know what the state of the world looks like) and we're mostly
    // clear on point (2) because we'd only free it after everything is done
    // anyway
    unsafe {
        git2_curl::register(handle);
    }
}
<|endoftext|>