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

//! Terminal formatting library.
//!
//! This crate provides the `Terminal` trait, which abstracts over an [ANSI
//! Terminal][ansi] to provide color printing, among other things. There are two
//! implementations, the `TerminfoTerminal`, which uses control characters from
//! a [terminfo][ti] database, and `WinConsole`, which uses the [Win32 Console
//! API][win].
//!
//! # Usage
//!
//! This crates is [on crates.io](https://crates.io/crates/term) and can be
//! used by adding `rand` to your dependencies in your project's `Cargo.toml`.
//!
//! ```toml
//! [dependencies]
//!
//! term = "*"
//! ```
//!
//! and this to your crate root:
//!
//! ```rust
//! extern crate term;
//! ```
//!
//! # Examples
//!
//! ```no_run
//! extern crate term;
//! use std::io::prelude::*;
//!
//! fn main() {
//!     let mut t = term::stdout().unwrap();
//!
//!     t.fg(term::color::GREEN).unwrap();
//!     (write!(t, "hello, ")).unwrap();
//!
//!     t.fg(term::color::RED).unwrap();
//!     (writeln!(t, "world!")).unwrap();
//!
//!     assert!(t.reset().unwrap());
//! }
//! ```
//!
//! [ansi]: https://en.wikipedia.org/wiki/ANSI_escape_code
//! [win]: http://msdn.microsoft.com/en-us/library/windows/desktop/ms682010%28v=vs.85%29.aspx
//! [ti]: https://en.wikipedia.org/wiki/Terminfo

#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
       html_favicon_url = "http://www.rust-lang.org/favicon.ico",
       html_root_url = "http://doc.rust-lang.org/nightly/",
       html_playground_url = "http://play.rust-lang.org/")]
#![deny(missing_docs)]
#![cfg_attr(test, deny(warnings))]

use std::io::prelude::*;

pub use terminfo::TerminfoTerminal;
#[cfg(windows)]
pub use win::WinConsole;

use std::io::{self, Stdout, Stderr};

pub mod terminfo;

#[cfg(windows)]
mod win;

/// Alias for stderr terminals.
pub type StdoutTerminal = Terminal<Output=Stdout> + Send;
/// Alias for stderr terminals.
pub type StderrTerminal = Terminal<Output=Stderr> + Send;

#[cfg(not(windows))]
/// Return a Terminal wrapping stdout, or None if a terminal couldn't be
/// opened.
pub fn stdout() -> Option<Box<StdoutTerminal>> {
    TerminfoTerminal::new(io::stdout()).map(|t| {
        Box::new(t) as Box<StdoutTerminal>
    })
}

#[cfg(windows)]
/// Return a Terminal wrapping stdout, or None if a terminal couldn't be
/// opened.
pub fn stdout() -> Option<Box<StdoutTerminal>> {
    TerminfoTerminal::new(io::stdout()).map(|t| {
        Box::new(t) as Box<StdoutTerminal>
    }).or_else(|| WinConsole::new(io::stdout()).ok().map(|t| {
        Box::new(t) as Box<StdoutTerminal>
    }))
}

#[cfg(not(windows))]
/// Return a Terminal wrapping stderr, or None if a terminal couldn't be
/// opened.
pub fn stderr() -> Option<Box<StderrTerminal>> {
    TerminfoTerminal::new(io::stderr()).map(|t| {
        Box::new(t) as Box<StderrTerminal>
    })
}

#[cfg(windows)]
/// Return a Terminal wrapping stderr, or None if a terminal couldn't be
/// opened.
pub fn stderr() -> Option<Box<StderrTerminal>> {
    TerminfoTerminal::new(io::stderr()).map(|t| {
        Box::new(t) as Box<StderrTerminal>
    }).or_else(|| WinConsole::new(io::stderr()).ok().map(|t| {
        Box::new(t) as Box<StderrTerminal>
    }))
}

/// Terminal color definitions
pub mod color {
    /// Number for a terminal color
    pub type Color = u16;

    pub const BLACK:   Color = 0;
    pub const RED:     Color = 1;
    pub const GREEN:   Color = 2;
    pub const YELLOW:  Color = 3;
    pub const BLUE:    Color = 4;
    pub const MAGENTA: Color = 5;
    pub const CYAN:    Color = 6;
    pub const WHITE:   Color = 7;

    pub const BRIGHT_BLACK:   Color = 8;
    pub const BRIGHT_RED:     Color = 9;
    pub const BRIGHT_GREEN:   Color = 10;
    pub const BRIGHT_YELLOW:  Color = 11;
    pub const BRIGHT_BLUE:    Color = 12;
    pub const BRIGHT_MAGENTA: Color = 13;
    pub const BRIGHT_CYAN:    Color = 14;
    pub const BRIGHT_WHITE:   Color = 15;
}

/// Terminal attributes for use with term.attr().
///
/// Most attributes can only be turned on and must be turned off with term.reset().
/// The ones that can be turned off explicitly take a boolean value.
/// Color is also represented as an attribute for convenience.
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
pub enum Attr {
    /// Bold (or possibly bright) mode
    Bold,
    /// Dim mode, also called faint or half-bright. Often not supported
    Dim,
    /// Italics mode. Often not supported
    Italic(bool),
    /// Underline mode
    Underline(bool),
    /// Blink mode
    Blink,
    /// Standout mode. Often implemented as Reverse, sometimes coupled with Bold
    Standout(bool),
    /// Reverse mode, inverts the foreground and background colors
    Reverse,
    /// Secure mode, also called invis mode. Hides the printed text
    Secure,
    /// Convenience attribute to set the foreground color
    ForegroundColor(color::Color),
    /// Convenience attribute to set the background color
    BackgroundColor(color::Color)
}

/// A terminal with similar capabilities to an ANSI Terminal
/// (foreground/background colors etc).
pub trait Terminal: Write {
    /// The terminal's output writer type.
    type Output: Write;

    /// Sets the foreground color to the given color.
    ///
    /// If the color is a bright color, but the terminal only supports 8 colors,
    /// the corresponding normal color will be used instead.
    ///
    /// Returns `Ok(true)` if the color was set, `Ok(false)` otherwise, and `Err(e)`
    /// if there was an I/O error.
    fn fg(&mut self, color: color::Color) -> io::Result<bool>;

    /// Sets the background color to the given color.
    ///
    /// If the color is a bright color, but the terminal only supports 8 colors,
    /// the corresponding normal color will be used instead.
    ///
    /// Returns `Ok(true)` if the color was set, `Ok(false)` otherwise, and `Err(e)`
    /// if there was an I/O error.
    fn bg(&mut self, color: color::Color) -> io::Result<bool>;

    /// Sets the given terminal attribute, if supported.  Returns `Ok(true)`
    /// if the attribute was supported, `Ok(false)` otherwise, and `Err(e)` if
    /// there was an I/O error.
    fn attr(&mut self, attr: Attr) -> io::Result<bool>;

    /// Returns whether the given terminal attribute is supported.
    fn supports_attr(&self, attr: Attr) -> bool;

    /// Resets all terminal attributes and color to the default.
    ///
    /// Returns `Ok(true)` if the terminal was reset, `Ok(false)` otherwise, and `Err(e)` if there
    /// was an I/O error.
    fn reset(&mut self) -> io::Result<bool>;

    /// Moves the cursor up one line.
    ///
    /// Returns `Ok(true)` if the cursor was moved, `Ok(false)` otherwise, and `Err(e)`
    /// if there was an I/O error.
    fn cursor_up(&mut self) -> io::Result<bool>;

    /// Deletes the text from the cursor location to the end of the line.
    ///
    /// Returns `Ok(true)` if the text was deleted, `Ok(false)` otherwise, and `Err(e)`
    /// if there was an I/O error.
    fn delete_line(&mut self) -> io::Result<bool>;

    /// Moves the cursor to the left edge of the current line.
    ///
    /// Returns `Ok(true)` if the text was deleted, `Ok(false)` otherwise, and `Err(e)`
    /// if there was an I/O error.
    fn carriage_return(&mut self) -> io::Result<bool>;

    /// Gets an immutable reference to the stream inside
    fn get_ref<'a>(&'a self) -> &'a Self::Output;

    /// Gets a mutable reference to the stream inside
    fn get_mut<'a>(&'a mut self) -> &'a mut Self::Output;
}

/// A terminal which can be unwrapped.
pub trait UnwrappableTerminal: Terminal {
    /// Returns the contained stream, destroying the `Terminal`
    fn unwrap(self) -> Self::Output;
}
<commit_msg>Don't use `"*"`<commit_after>// Copyright 2013-2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Terminal formatting library.
//!
//! This crate provides the `Terminal` trait, which abstracts over an [ANSI
//! Terminal][ansi] to provide color printing, among other things. There are two
//! implementations, the `TerminfoTerminal`, which uses control characters from
//! a [terminfo][ti] database, and `WinConsole`, which uses the [Win32 Console
//! API][win].
//!
//! # Usage
//!
//! This crates is [on crates.io](https://crates.io/crates/term) and can be
//! used by adding `rand` to your dependencies in your project's `Cargo.toml`.
//!
//! ```toml
//! [dependencies]
//!
//! term = "0.2"
//! ```
//!
//! and this to your crate root:
//!
//! ```rust
//! extern crate term;
//! ```
//!
//! # Examples
//!
//! ```no_run
//! extern crate term;
//! use std::io::prelude::*;
//!
//! fn main() {
//!     let mut t = term::stdout().unwrap();
//!
//!     t.fg(term::color::GREEN).unwrap();
//!     (write!(t, "hello, ")).unwrap();
//!
//!     t.fg(term::color::RED).unwrap();
//!     (writeln!(t, "world!")).unwrap();
//!
//!     assert!(t.reset().unwrap());
//! }
//! ```
//!
//! [ansi]: https://en.wikipedia.org/wiki/ANSI_escape_code
//! [win]: http://msdn.microsoft.com/en-us/library/windows/desktop/ms682010%28v=vs.85%29.aspx
//! [ti]: https://en.wikipedia.org/wiki/Terminfo

#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
       html_favicon_url = "http://www.rust-lang.org/favicon.ico",
       html_root_url = "http://doc.rust-lang.org/nightly/",
       html_playground_url = "http://play.rust-lang.org/")]
#![deny(missing_docs)]
#![cfg_attr(test, deny(warnings))]

use std::io::prelude::*;

pub use terminfo::TerminfoTerminal;
#[cfg(windows)]
pub use win::WinConsole;

use std::io::{self, Stdout, Stderr};

pub mod terminfo;

#[cfg(windows)]
mod win;

/// Alias for stderr terminals.
pub type StdoutTerminal = Terminal<Output=Stdout> + Send;
/// Alias for stderr terminals.
pub type StderrTerminal = Terminal<Output=Stderr> + Send;

#[cfg(not(windows))]
/// Return a Terminal wrapping stdout, or None if a terminal couldn't be
/// opened.
pub fn stdout() -> Option<Box<StdoutTerminal>> {
    TerminfoTerminal::new(io::stdout()).map(|t| {
        Box::new(t) as Box<StdoutTerminal>
    })
}

#[cfg(windows)]
/// Return a Terminal wrapping stdout, or None if a terminal couldn't be
/// opened.
pub fn stdout() -> Option<Box<StdoutTerminal>> {
    TerminfoTerminal::new(io::stdout()).map(|t| {
        Box::new(t) as Box<StdoutTerminal>
    }).or_else(|| WinConsole::new(io::stdout()).ok().map(|t| {
        Box::new(t) as Box<StdoutTerminal>
    }))
}

#[cfg(not(windows))]
/// Return a Terminal wrapping stderr, or None if a terminal couldn't be
/// opened.
pub fn stderr() -> Option<Box<StderrTerminal>> {
    TerminfoTerminal::new(io::stderr()).map(|t| {
        Box::new(t) as Box<StderrTerminal>
    })
}

#[cfg(windows)]
/// Return a Terminal wrapping stderr, or None if a terminal couldn't be
/// opened.
pub fn stderr() -> Option<Box<StderrTerminal>> {
    TerminfoTerminal::new(io::stderr()).map(|t| {
        Box::new(t) as Box<StderrTerminal>
    }).or_else(|| WinConsole::new(io::stderr()).ok().map(|t| {
        Box::new(t) as Box<StderrTerminal>
    }))
}

/// Terminal color definitions
pub mod color {
    /// Number for a terminal color
    pub type Color = u16;

    pub const BLACK:   Color = 0;
    pub const RED:     Color = 1;
    pub const GREEN:   Color = 2;
    pub const YELLOW:  Color = 3;
    pub const BLUE:    Color = 4;
    pub const MAGENTA: Color = 5;
    pub const CYAN:    Color = 6;
    pub const WHITE:   Color = 7;

    pub const BRIGHT_BLACK:   Color = 8;
    pub const BRIGHT_RED:     Color = 9;
    pub const BRIGHT_GREEN:   Color = 10;
    pub const BRIGHT_YELLOW:  Color = 11;
    pub const BRIGHT_BLUE:    Color = 12;
    pub const BRIGHT_MAGENTA: Color = 13;
    pub const BRIGHT_CYAN:    Color = 14;
    pub const BRIGHT_WHITE:   Color = 15;
}

/// Terminal attributes for use with term.attr().
///
/// Most attributes can only be turned on and must be turned off with term.reset().
/// The ones that can be turned off explicitly take a boolean value.
/// Color is also represented as an attribute for convenience.
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
pub enum Attr {
    /// Bold (or possibly bright) mode
    Bold,
    /// Dim mode, also called faint or half-bright. Often not supported
    Dim,
    /// Italics mode. Often not supported
    Italic(bool),
    /// Underline mode
    Underline(bool),
    /// Blink mode
    Blink,
    /// Standout mode. Often implemented as Reverse, sometimes coupled with Bold
    Standout(bool),
    /// Reverse mode, inverts the foreground and background colors
    Reverse,
    /// Secure mode, also called invis mode. Hides the printed text
    Secure,
    /// Convenience attribute to set the foreground color
    ForegroundColor(color::Color),
    /// Convenience attribute to set the background color
    BackgroundColor(color::Color)
}

/// A terminal with similar capabilities to an ANSI Terminal
/// (foreground/background colors etc).
pub trait Terminal: Write {
    /// The terminal's output writer type.
    type Output: Write;

    /// Sets the foreground color to the given color.
    ///
    /// If the color is a bright color, but the terminal only supports 8 colors,
    /// the corresponding normal color will be used instead.
    ///
    /// Returns `Ok(true)` if the color was set, `Ok(false)` otherwise, and `Err(e)`
    /// if there was an I/O error.
    fn fg(&mut self, color: color::Color) -> io::Result<bool>;

    /// Sets the background color to the given color.
    ///
    /// If the color is a bright color, but the terminal only supports 8 colors,
    /// the corresponding normal color will be used instead.
    ///
    /// Returns `Ok(true)` if the color was set, `Ok(false)` otherwise, and `Err(e)`
    /// if there was an I/O error.
    fn bg(&mut self, color: color::Color) -> io::Result<bool>;

    /// Sets the given terminal attribute, if supported.  Returns `Ok(true)`
    /// if the attribute was supported, `Ok(false)` otherwise, and `Err(e)` if
    /// there was an I/O error.
    fn attr(&mut self, attr: Attr) -> io::Result<bool>;

    /// Returns whether the given terminal attribute is supported.
    fn supports_attr(&self, attr: Attr) -> bool;

    /// Resets all terminal attributes and color to the default.
    ///
    /// Returns `Ok(true)` if the terminal was reset, `Ok(false)` otherwise, and `Err(e)` if there
    /// was an I/O error.
    fn reset(&mut self) -> io::Result<bool>;

    /// Moves the cursor up one line.
    ///
    /// Returns `Ok(true)` if the cursor was moved, `Ok(false)` otherwise, and `Err(e)`
    /// if there was an I/O error.
    fn cursor_up(&mut self) -> io::Result<bool>;

    /// Deletes the text from the cursor location to the end of the line.
    ///
    /// Returns `Ok(true)` if the text was deleted, `Ok(false)` otherwise, and `Err(e)`
    /// if there was an I/O error.
    fn delete_line(&mut self) -> io::Result<bool>;

    /// Moves the cursor to the left edge of the current line.
    ///
    /// Returns `Ok(true)` if the text was deleted, `Ok(false)` otherwise, and `Err(e)`
    /// if there was an I/O error.
    fn carriage_return(&mut self) -> io::Result<bool>;

    /// Gets an immutable reference to the stream inside
    fn get_ref<'a>(&'a self) -> &'a Self::Output;

    /// Gets a mutable reference to the stream inside
    fn get_mut<'a>(&'a mut self) -> &'a mut Self::Output;
}

/// A terminal which can be unwrapped.
pub trait UnwrappableTerminal: Terminal {
    /// Returns the contained stream, destroying the `Terminal`
    fn unwrap(self) -> Self::Output;
}
<|endoftext|>


<commit_before>#![feature(unboxed_closures)]

// Map a vector/list based on a mapping function
// @param map_fn: Mapping function
// @param vect: The vector to map
// @returns: A mapped vector
pub fn map<F, A, B> (mut map_fn: F, vect: Vec<A>) -> Vec<B>
    where F: FnMut(A) -> B,
    A: Clone {
    let mut list = vec![];

    for v in vect {
        let mut value = map_fn(v.clone());
        list.push(value);
    }

    list
}

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

    #[test]
    fn map_simple_list() {
        let list = vec![1, 2, 3];
        let expected_list = vec![2, 3, 4];
        assert_eq!(map(plus_one, list), expected_list);
    }

    #[test]
    fn map_empty_list() {
        let list = vec![];
        let expected_list = vec![];
        assert_eq!(map(plus_one, list), expected_list);
    }

    fn plus_one(n: i32) -> i32 {
        match n {
            x if x > 0 => n + 1,
            _ => 1
        }
    }
}<commit_msg>Add code comments<commit_after>#![feature(unboxed_closures)]
#![crate_name = "sknife"]

/// Maps a vector/list based on a mapping function
///
/// # Arguments
///
/// * `map_fn` - A mapping function to apply to the list
/// * `vect` - A vector to apply the map to
///
/// # Example
///
/// ```
/// use sknife::map;
/// let list = vec![1, 2, 3];
/// let plus_one = |x| x + 1;
/// map(plus_one, list);
///
/// ```
///
/// # Result
/// ```
/// vec![2, 3, 4];
/// ```
pub fn map<F, A, B> (mut map_fn: F, vect: Vec<A>) -> Vec<B>
    where F: FnMut(A) -> B,
    A: Clone {
    let mut list = vec![];

    for v in vect {
        let value = map_fn(v.clone());
        list.push(value);
    }

    list
}

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

    #[test]
    fn map_simple_list() {
        let list = vec![1, 2, 3];
        let expected_list = vec![2, 3, 4];
        assert_eq!(map(plus_one, list), expected_list);
    }

    #[test]
    fn map_empty_list() {
        let list = vec![];
        let expected_list = vec![];
        assert_eq!(map(plus_one, list), expected_list);
    }

    fn plus_one(n: i32) -> i32 {
        match n {
            x if x > 0 => n + 1,
            _ => 1
        }
    }
}<|endoftext|>


<commit_before>// Copyright (c) 2016-2018 Scott Lamb <slamb@slamb.org>
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE.txt or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT.txt or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Helpers for serving HTTP GET and HEAD responses with [hyper](https://crates.io/crates/hyper)
//! 0.11.x and [tokio](https://crates.io/crates/tokio). A future version is likely to switch to
//! the interface of the [http](http://crates.io/crates/http) crate.
//!
//! This crate supplies two ways to respond to HTTP GET and HEAD requests:
//!
//! *   the `serve` function can be used to serve an `Entity`, a trait representing reusable,
//!     byte-rangeable HTTP entities. `Entity` must be able to produce exactly the same data on
//!     every call, know its size in advance, and be able to produce portions of the data on demand.
//! *   the `streaming_body` function can be used to add a body to an otherwise-complete response.
//!     If a body is needed, it returns a `BodyWriter` (which implements `std::io::Writer`). The
//!     caller should produce the complete body or call `BodyWriter::abort`, causing the HTTP
//!     stream to terminate abruptly.
//!
//! # Why two ways?
//!
//! They have pros and cons. This chart shows some of them:
//!
//!

//!
servestreaming_body

//!
automatic byte range servingyesno (always sends full body)

//!
backpressureyesno

//!
conditional GETyesunimplemented (always sends body)

//!
sends first byte before length knownnoyes

//!
automatic gzip content encodingnoyes

//!

//!
//! Use `serve` when:
//!
//! *   metadata (length, etag, etc) and byte ranges can be regenerated cheaply and consistently
//!     via a lazy `Entity`.
//! *   data can be fully buffered in memory or on disk and reused many times. You may want to
//!     create a pair of buffers for gzipped (for user-agents which specify `Accept-Encoding:
//!     gzip`) vs raw.
//!
//! Consider `streaming_body` if data would be fully buffered each time a response is sent.
//!
//! Once you return a `hyper::server::Response` to hyper, your only way to signal error to the
//! client is to abruptly close the HTTP connection while sending the body. If you want the ability
//! to return a well-formatted error to the client while producing body bytes, you must buffer the
//! entire body in-memory before returning anything to hyper.
//!
//! If you are buffering a response in memory, `serve` requires copying the bytes (when using
//! `Data = Vec<u8>` or similar) or atomic reference-counting (with `Data = Arc<Vec<u8>>` or
//! similar). `streaming_body` doesn't need to keep its own copy for potential future use; it may
//! be cheaper because it can simply hand ownership of the existing `Vec<u8>`s to hyper.
//!
//! # Why the weird type bounds? Why not use `hyper::Body` and `hyper::Chunk` for everything?
//!
//! `hyper::Chunk` is fine in most cases. There are times when it's desirable to have more flexible
//! ownership provided by a type such as `reffers::ARefs<'static, [u8]>`. One is `mmap`-based
//! file serving: a `hyper::Chunk` would require copying the data in each chunk. An implementation
//! with `ARefs` could instead `mmap` and `mlock` the data on another thread and provide chunks
//! which `munmap` when dropped.
//!
//! `hyper::Body` unfortunately can't be used with either `serve` or `streaming_body`; they need a
//! `Box<::futures::stream::Stream<Self::Chunk, ::hyper::Error> + Send + 'static>` or something
//! that can be constructed from that type.

extern crate bytes;
extern crate flate2;
extern crate futures;
extern crate futures_cpupool;
extern crate http;
extern crate httpdate;
extern crate hyper;
extern crate mime;
extern crate smallvec;
extern crate time;
extern crate unicase;

use bytes::Buf;
use futures::Stream;
use http::header::{self, HeaderMap, HeaderValue};
use std::ops::Range;
use std::time::SystemTime;

/// Returns a HeaderValue for the given formatted data.
/// Caller must make two guarantees:
///    * The data fits within `max_len`.
///    * The data are ASCII.
macro_rules! fmt_ascii_val {
    ($max_len:expr, $fmt:expr, $($arg:tt)+) => {{
        let mut buf = ::bytes::BytesMut::with_capacity($max_len);
        use std::fmt::Write;
        write!(buf, $fmt, $($arg)*).expect("fmt_val fits within provided max len");
        unsafe {
            ::http::header::HeaderValue::from_shared_unchecked(buf.freeze())
        }
    }}
}

mod chunker;
mod etag;
mod file;
mod gzip;
mod range;
mod serving;

pub use file::ChunkedReadFile;
pub use gzip::BodyWriter;
pub use serving::serve;

/// A reusable, read-only, byte-rangeable HTTP entity for GET and HEAD serving.
/// Must return exactly the same data on every call.
pub trait Entity: 'static + Send {
    type Error: Send;

    /// The type of a data chunk.
    ///
    /// Commonly `::hyper::Chunk` but may be something more exotic.
    type Data: 'static + Send + Buf + From<Vec<u8>> + From<&'static [u8]>;

    /// Returns the length of the entity's body in bytes.
    fn len(&self) -> u64;

    /// Returns true iff the entity's body has length 0.
    fn is_empty(&self) -> bool {
        self.len() == 0
    }

    /// Gets the body bytes indicated by `range`.
    fn get_range(
        &self,
        range: Range<u64>,
    ) -> Box<Stream<Item = Self::Data, Error = Self::Error> + Send>;

    /// Adds entity headers such as `Content-Type` to the supplied `Headers` object.
    /// In particular, these headers are the "other representation header fields" described by [RFC
    /// 7233 section 4.1](https://tools.ietf.org/html/rfc7233#section-4.1); they should exclude
    /// `Content-Range`, `Date`, `Cache-Control`, `ETag`, `Expires`, `Content-Location`, and `Vary`.
    ///
    /// This function will be called only when that section says that headers such as
    /// `Content-Type` should be included in the response.
    fn add_headers(&self, &mut HeaderMap);

    /// Returns an etag for this entity, if available.
    /// Implementations are encouraged to provide a strong etag. [RFC 7232 section
    /// 2.1](https://tools.ietf.org/html/rfc7232#section-2.1) notes that only strong etags
    /// are usable for sub-range retrieval.
    fn etag(&self) -> Option<HeaderValue>;

    /// Returns the last modified time of this entity, if available.
    /// Note that `serve` may serve an earlier `Last-Modified:` date than the one returned here if
    /// this time is in the future, as required by [RFC 7232 section
    /// 2.2.1](https://tools.ietf.org/html/rfc7232#section-2.2.1).
    fn last_modified(&self) -> Option<SystemTime>;
}

/// Returns iff it's preferable to use `Content-Encoding: gzip` when responding to the given
/// request, rather than no content coding.
///
/// Use via `should_gzip(req.headers().get())`.
///
/// Follows the rules of [RFC 7231 section
/// 5.3.4](https://tools.ietf.org/html/rfc7231#section-5.3.4).
pub fn should_gzip(headers: &HeaderMap) -> bool {
    let v = match headers.get(header::ACCEPT_ENCODING) {
        None => return false,
        Some(v) => v,
    };
    let (mut gzip_q, mut identity_q, mut star_q) = (None, None, None);
    let parts = match v.to_str() {
        Ok(s) => s.split(','),
        Err(_) => return false,
    };
    for qi in parts {
        // Parse.
        let qi = qi.trim();
        let mut parts = qi.rsplitn(2, ';').map(|p| p.trim());
        let last_part = parts
            .next()
            .expect("rsplitn should return at least one part");
        let coding;
        let quality;
        match parts.next() {
            None => {
                coding = last_part;
                quality = 1.0f32;
            }
            Some(c) => {
                if !last_part.starts_with("q=") {
                    return false; // unparseable.
                }
                let q = &last_part[2..];
                match q.parse::<f32>() {
                    Ok(q) if 0f32 <= q && q <= 1f32 => {
                        coding = c;
                        quality = q;
                    }
                    Ok(_q) => return false, // unparseable.
                    Err(_) => return false, // unparseable.
                };
            }
        }

        if coding == "gzip" {
            gzip_q = Some(quality);
        } else if coding == "identity" {
            identity_q = Some(quality);
        } else if coding == "*" {
            star_q = Some(quality);
        }
    }

    let gzip_q = gzip_q.or(star_q).unwrap_or(0.0f32);

    // "If the representation has no content-coding, then it is
    // acceptable by default unless specifically excluded by the
    // Accept-Encoding field stating either "identity;q=0" or "*;q=0"
    // without a more specific entry for "identity"."
    let identity_q = identity_q.or(star_q).unwrap_or(0.001f32);

    gzip_q > 0.0f32 && gzip_q >= identity_q
}

pub struct StreamingBodyBuilder {
    chunk_size: usize,
    gzip_level: u32,
    body_needed: bool,
}

/// Adds a streaming body to the given request if a body is needed.
///
/// Currently the body is added for non-HEAD requests. In the future, this may also follow
/// conditional GET rules, omitting the body and stripping out entity headers from the response as
/// desired.
pub fn streaming_body<T>(req: &http::Request<T>) -> StreamingBodyBuilder {
    StreamingBodyBuilder {
        chunk_size: 4096,
        gzip_level: match should_gzip(req.headers()) {
            true => 6,
            false => 0,
        },
        body_needed: *req.method() != http::method::Method::HEAD,
    }
}

impl StreamingBodyBuilder {
    pub fn with_chunk_size(self, chunk_size: usize) -> Self {
        StreamingBodyBuilder { chunk_size, ..self }
    }

    pub fn with_gzip_level(self, level: u32) -> Self {
        StreamingBodyBuilder {
            gzip_level: if self.gzip_level == 0 { 0 } else { level },
            ..self
        }
    }

    pub fn build
(self) -> (http::Response
, Option<BodyWriter<D, E>>)
    where
        D: From<Vec<u8>> + Send,
        E: Send,
        P: From<Box<Stream<Item = D, Error = E> + Send>>,
    {
        let (w, stream) = chunker::BodyWriter::with_chunk_size(self.chunk_size);
        let mut resp = http::Response::new(stream.into());
        resp.headers_mut()
            .append(header::VARY, HeaderValue::from_static("accept-encoding"));

        if self.gzip_level > 0 {
            resp.headers_mut()
                .append(header::CONTENT_ENCODING, HeaderValue::from_static("gzip"));
        }

        if !self.body_needed {
            return (resp, None);
        }

        let w = match self.gzip_level > 0 {
            true => BodyWriter::gzipped(w, flate2::Compression::new(self.gzip_level)),
            false => BodyWriter::raw(w),
        };

        (resp, Some(w))
    }
}

#[cfg(test)]
mod tests {
    use http::header::HeaderValue;
    use http::{self, header};

    fn ae_hdrs(value: &'static str) -> http::HeaderMap {
        let mut h = http::HeaderMap::new();
        h.insert(header::ACCEPT_ENCODING, HeaderValue::from_static(value));
        h
    }

    #[test]
    fn should_gzip() {
        // "A request without an Accept-Encoding header field implies that the
        // user agent has no preferences regarding content-codings. Although
        // this allows the server to use any content-coding in a response, it
        // does not imply that the user agent will be able to correctly process
        // all encodings." Identity seems safer; don't gzip.
        assert!(!super::should_gzip(&header::HeaderMap::new()));

        // "If the representation's content-coding is one of the
        // content-codings listed in the Accept-Encoding field, then it is
        // acceptable unless it is accompanied by a qvalue of 0.  (As
        // defined in Section 5.3.1, a qvalue of 0 means "not acceptable".)"
        assert!(super::should_gzip(&ae_hdrs("gzip")));
        assert!(super::should_gzip(&ae_hdrs("gzip;q=0.001")));
        assert!(!super::should_gzip(&ae_hdrs("gzip;q=0")));

        // "An Accept-Encoding header field with a combined field-value that is
        // empty implies that the user agent does not want any content-coding in
        // response."
        assert!(!super::should_gzip(&ae_hdrs("")));

        // "The asterisk "*" symbol in an Accept-Encoding field
        // matches any available content-coding not explicitly listed in the
        // header field."
        assert!(super::should_gzip(&ae_hdrs("*")));
        assert!(!super::should_gzip(&ae_hdrs("gzip;q=0, *")));
        assert!(super::should_gzip(&ae_hdrs("identity=q=0, *")));

        // "If multiple content-codings are acceptable, then the acceptable
        // content-coding with the highest non-zero qvalue is preferred."
        assert!(super::should_gzip(&ae_hdrs("identity;q=0.5, gzip;q=1.0")));
        assert!(!super::should_gzip(&ae_hdrs("identity;q=1.0, gzip;q=0.5")));

        // "If an Accept-Encoding header field is present in a request
        // and none of the available representations for the response have a
        // content-coding that is listed as acceptable, the origin server SHOULD
        // send a response without any content-coding."
        assert!(!super::should_gzip(&ae_hdrs("*;q=0")));
    }
}
<commit_msg>fix some docs obsoleted by hyper 0.12.x<commit_after>// Copyright (c) 2016-2018 Scott Lamb <slamb@slamb.org>
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE.txt or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT.txt or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Helpers for serving HTTP GET and HEAD responses with [hyper](https://crates.io/crates/hyper)
//! 0.11.x and [tokio](https://crates.io/crates/tokio). A future version is likely to switch to
//! the interface of the [http](http://crates.io/crates/http) crate.
//!
//! This crate supplies two ways to respond to HTTP GET and HEAD requests:
//!
//! *   the `serve` function can be used to serve an `Entity`, a trait representing reusable,
//!     byte-rangeable HTTP entities. `Entity` must be able to produce exactly the same data on
//!     every call, know its size in advance, and be able to produce portions of the data on demand.
//! *   the `streaming_body` function can be used to add a body to an otherwise-complete response.
//!     If a body is needed, it returns a `BodyWriter` (which implements `std::io::Writer`). The
//!     caller should produce the complete body or call `BodyWriter::abort`, causing the HTTP
//!     stream to terminate abruptly.
//!
//! # Why two ways?
//!
//! They have pros and cons. This chart shows some of them:
//!
//!

//!
servestreaming_body

//!
automatic byte range servingyesno (always sends full body)

//!
backpressureyesno

//!
conditional GETyesunimplemented (always sends body)

//!
sends first byte before length knownnoyes

//!
automatic gzip content encodingnoyes

//!

//!
//! Use `serve` when:
//!
//! *   metadata (length, etag, etc) and byte ranges can be regenerated cheaply and consistently
//!     via a lazy `Entity`.
//! *   data can be fully buffered in memory or on disk and reused many times. You may want to
//!     create a pair of buffers for gzipped (for user-agents which specify `Accept-Encoding:
//!     gzip`) vs raw.
//!
//! Consider `streaming_body` if data would be fully buffered each time a response is sent.
//!
//! Once you return a `hyper::server::Response` to hyper, your only way to signal error to the
//! client is to abruptly close the HTTP connection while sending the body. If you want the ability
//! to return a well-formatted error to the client while producing body bytes, you must buffer the
//! entire body in-memory before returning anything to hyper.
//!
//! If you are buffering a response in memory, `serve` requires copying the bytes (when using
//! `Data = Vec<u8>` or similar) or atomic reference-counting (with `Data = Arc<Vec<u8>>` or
//! similar). `streaming_body` doesn't need to keep its own copy for potential future use; it may
//! be cheaper because it can simply hand ownership of the existing `Vec<u8>`s to hyper.
//!
//! # Why the weird type bounds? Why not use `hyper::Body` and `hyper::Chunk` for everything?
//!
//! These bounds are compatible with `hyper::Body` and `hyper::Chunk`, and most callers will use
//! those types. There are times when it's desirable to have more flexible ownership provided by a
//! type such as `reffers::ARefs<'static, [u8]>`. One is `mmap`-based file serving: a
//! `hyper::Chunk` would require copying the data in each chunk. An implementation with `ARefs`
//! could instead `mmap` and `mlock` the data on another thread and provide chunks which `munmap`
//! when dropped. In these cases, the caller can supply an alternate implementation of the
//! `hyper::Payload` trait which uses a different `Data` type than `hyper::Chunk`.

extern crate bytes;
extern crate flate2;
extern crate futures;
extern crate futures_cpupool;
extern crate http;
extern crate httpdate;
extern crate hyper;
extern crate mime;
extern crate smallvec;
extern crate time;
extern crate unicase;

use bytes::Buf;
use futures::Stream;
use http::header::{self, HeaderMap, HeaderValue};
use std::ops::Range;
use std::time::SystemTime;

/// Returns a HeaderValue for the given formatted data.
/// Caller must make two guarantees:
///    * The data fits within `max_len`.
///    * The data are ASCII.
macro_rules! fmt_ascii_val {
    ($max_len:expr, $fmt:expr, $($arg:tt)+) => {{
        let mut buf = ::bytes::BytesMut::with_capacity($max_len);
        use std::fmt::Write;
        write!(buf, $fmt, $($arg)*).expect("fmt_val fits within provided max len");
        unsafe {
            ::http::header::HeaderValue::from_shared_unchecked(buf.freeze())
        }
    }}
}

mod chunker;
mod etag;
mod file;
mod gzip;
mod range;
mod serving;

pub use file::ChunkedReadFile;
pub use gzip::BodyWriter;
pub use serving::serve;

/// A reusable, read-only, byte-rangeable HTTP entity for GET and HEAD serving.
/// Must return exactly the same data on every call.
pub trait Entity: 'static + Send {
    type Error: Send;

    /// The type of a data chunk.
    ///
    /// Commonly `::hyper::Chunk` but may be something more exotic.
    type Data: 'static + Send + Buf + From<Vec<u8>> + From<&'static [u8]>;

    /// Returns the length of the entity's body in bytes.
    fn len(&self) -> u64;

    /// Returns true iff the entity's body has length 0.
    fn is_empty(&self) -> bool {
        self.len() == 0
    }

    /// Gets the body bytes indicated by `range`.
    fn get_range(
        &self,
        range: Range<u64>,
    ) -> Box<Stream<Item = Self::Data, Error = Self::Error> + Send>;

    /// Adds entity headers such as `Content-Type` to the supplied `Headers` object.
    /// In particular, these headers are the "other representation header fields" described by [RFC
    /// 7233 section 4.1](https://tools.ietf.org/html/rfc7233#section-4.1); they should exclude
    /// `Content-Range`, `Date`, `Cache-Control`, `ETag`, `Expires`, `Content-Location`, and `Vary`.
    ///
    /// This function will be called only when that section says that headers such as
    /// `Content-Type` should be included in the response.
    fn add_headers(&self, &mut HeaderMap);

    /// Returns an etag for this entity, if available.
    /// Implementations are encouraged to provide a strong etag. [RFC 7232 section
    /// 2.1](https://tools.ietf.org/html/rfc7232#section-2.1) notes that only strong etags
    /// are usable for sub-range retrieval.
    fn etag(&self) -> Option<HeaderValue>;

    /// Returns the last modified time of this entity, if available.
    /// Note that `serve` may serve an earlier `Last-Modified:` date than the one returned here if
    /// this time is in the future, as required by [RFC 7232 section
    /// 2.2.1](https://tools.ietf.org/html/rfc7232#section-2.2.1).
    fn last_modified(&self) -> Option<SystemTime>;
}

/// Returns iff it's preferable to use `Content-Encoding: gzip` when responding to the given
/// request, rather than no content coding.
///
/// Use via `should_gzip(req.headers().get())`.
///
/// Follows the rules of [RFC 7231 section
/// 5.3.4](https://tools.ietf.org/html/rfc7231#section-5.3.4).
pub fn should_gzip(headers: &HeaderMap) -> bool {
    let v = match headers.get(header::ACCEPT_ENCODING) {
        None => return false,
        Some(v) => v,
    };
    let (mut gzip_q, mut identity_q, mut star_q) = (None, None, None);
    let parts = match v.to_str() {
        Ok(s) => s.split(','),
        Err(_) => return false,
    };
    for qi in parts {
        // Parse.
        let qi = qi.trim();
        let mut parts = qi.rsplitn(2, ';').map(|p| p.trim());
        let last_part = parts
            .next()
            .expect("rsplitn should return at least one part");
        let coding;
        let quality;
        match parts.next() {
            None => {
                coding = last_part;
                quality = 1.0f32;
            }
            Some(c) => {
                if !last_part.starts_with("q=") {
                    return false; // unparseable.
                }
                let q = &last_part[2..];
                match q.parse::<f32>() {
                    Ok(q) if 0f32 <= q && q <= 1f32 => {
                        coding = c;
                        quality = q;
                    }
                    Ok(_q) => return false, // unparseable.
                    Err(_) => return false, // unparseable.
                };
            }
        }

        if coding == "gzip" {
            gzip_q = Some(quality);
        } else if coding == "identity" {
            identity_q = Some(quality);
        } else if coding == "*" {
            star_q = Some(quality);
        }
    }

    let gzip_q = gzip_q.or(star_q).unwrap_or(0.0f32);

    // "If the representation has no content-coding, then it is
    // acceptable by default unless specifically excluded by the
    // Accept-Encoding field stating either "identity;q=0" or "*;q=0"
    // without a more specific entry for "identity"."
    let identity_q = identity_q.or(star_q).unwrap_or(0.001f32);

    gzip_q > 0.0f32 && gzip_q >= identity_q
}

pub struct StreamingBodyBuilder {
    chunk_size: usize,
    gzip_level: u32,
    body_needed: bool,
}

/// Adds a streaming body to the given request if a body is needed.
///
/// Currently the body is added for non-HEAD requests. In the future, this may also follow
/// conditional GET rules, omitting the body and stripping out entity headers from the response as
/// desired.
pub fn streaming_body<T>(req: &http::Request<T>) -> StreamingBodyBuilder {
    StreamingBodyBuilder {
        chunk_size: 4096,
        gzip_level: match should_gzip(req.headers()) {
            true => 6,
            false => 0,
        },
        body_needed: *req.method() != http::method::Method::HEAD,
    }
}

impl StreamingBodyBuilder {
    pub fn with_chunk_size(self, chunk_size: usize) -> Self {
        StreamingBodyBuilder { chunk_size, ..self }
    }

    pub fn with_gzip_level(self, level: u32) -> Self {
        StreamingBodyBuilder {
            gzip_level: if self.gzip_level == 0 { 0 } else { level },
            ..self
        }
    }

    pub fn build
(self) -> (http::Response
, Option<BodyWriter<D, E>>)
    where
        D: From<Vec<u8>> + Send,
        E: Send,
        P: From<Box<Stream<Item = D, Error = E> + Send>>,
    {
        let (w, stream) = chunker::BodyWriter::with_chunk_size(self.chunk_size);
        let mut resp = http::Response::new(stream.into());
        resp.headers_mut()
            .append(header::VARY, HeaderValue::from_static("accept-encoding"));

        if self.gzip_level > 0 {
            resp.headers_mut()
                .append(header::CONTENT_ENCODING, HeaderValue::from_static("gzip"));
        }

        if !self.body_needed {
            return (resp, None);
        }

        let w = match self.gzip_level > 0 {
            true => BodyWriter::gzipped(w, flate2::Compression::new(self.gzip_level)),
            false => BodyWriter::raw(w),
        };

        (resp, Some(w))
    }
}

#[cfg(test)]
mod tests {
    use http::header::HeaderValue;
    use http::{self, header};

    fn ae_hdrs(value: &'static str) -> http::HeaderMap {
        let mut h = http::HeaderMap::new();
        h.insert(header::ACCEPT_ENCODING, HeaderValue::from_static(value));
        h
    }

    #[test]
    fn should_gzip() {
        // "A request without an Accept-Encoding header field implies that the
        // user agent has no preferences regarding content-codings. Although
        // this allows the server to use any content-coding in a response, it
        // does not imply that the user agent will be able to correctly process
        // all encodings." Identity seems safer; don't gzip.
        assert!(!super::should_gzip(&header::HeaderMap::new()));

        // "If the representation's content-coding is one of the
        // content-codings listed in the Accept-Encoding field, then it is
        // acceptable unless it is accompanied by a qvalue of 0.  (As
        // defined in Section 5.3.1, a qvalue of 0 means "not acceptable".)"
        assert!(super::should_gzip(&ae_hdrs("gzip")));
        assert!(super::should_gzip(&ae_hdrs("gzip;q=0.001")));
        assert!(!super::should_gzip(&ae_hdrs("gzip;q=0")));

        // "An Accept-Encoding header field with a combined field-value that is
        // empty implies that the user agent does not want any content-coding in
        // response."
        assert!(!super::should_gzip(&ae_hdrs("")));

        // "The asterisk "*" symbol in an Accept-Encoding field
        // matches any available content-coding not explicitly listed in the
        // header field."
        assert!(super::should_gzip(&ae_hdrs("*")));
        assert!(!super::should_gzip(&ae_hdrs("gzip;q=0, *")));
        assert!(super::should_gzip(&ae_hdrs("identity=q=0, *")));

        // "If multiple content-codings are acceptable, then the acceptable
        // content-coding with the highest non-zero qvalue is preferred."
        assert!(super::should_gzip(&ae_hdrs("identity;q=0.5, gzip;q=1.0")));
        assert!(!super::should_gzip(&ae_hdrs("identity;q=1.0, gzip;q=0.5")));

        // "If an Accept-Encoding header field is present in a request
        // and none of the available representations for the response have a
        // content-coding that is listed as acceptable, the origin server SHOULD
        // send a response without any content-coding."
        assert!(!super::should_gzip(&ae_hdrs("*;q=0")));
    }
}
<|endoftext|>


<commit_before>#![crate_name = "libvorbisfile"]
#![doc(html_root_url = "http://www.rust-ci.org/tari/vorbisfile.rs/doc/libvorbisfile/")]

#![deny(dead_code, missing_doc)]
#![feature(unsafe_destructor)]

//! Ogg Vorbis file decoding, library bindings.

extern crate debug;
extern crate libc;
use libc::{c_void, c_int, c_long, size_t};

use std::c_str::CString;
use std::mem;
use std::str;
use std::ptr;
use std::raw;
use std::slice::raw::mut_buf_as_slice;

#[allow(dead_code, non_snake_case)]
mod ffi;

pub type OVResult<T> = Result<T, OVError>;

/// Decode error.
#[deriving(Show, Clone)]
pub enum OVError {
    /// Reached end of file.
    EndOfStream,
    /// Encounted missing or corrupt data.
    ///
    /// Recovery from this error is usually automatic and is returned for
    /// informational purposes only.
    StreamInterrupted,
    /// I/O error while reading compressed data to decode.
    ReadError,
    /// Internal inconsistency in encode or decode state. Recovery impossible.
    InternalFault,
    /// Feature not implemented.
    NotImplemented,
    /// User passed an invalid argument to a function.
    InvalidArgument,
    /// Provided data is not recognized as Ogg Vorbis.
    NotVorbis,
    /// Provided data appears to be Ogg Vorbis but has a corrupt or
    /// indecipherable header.
    InvalidHeader,
    /// Bitstream format revision is not supported.
    UnsupportedVersion,
    /// The specified Vorbis link exists but is corrupt.
    CorruptLink,
    /// The stream is not seekable.
    NotSeekable,
}

impl OVError {
    fn from_native(code: c_int) -> OVError {
        match code {
            ffi::OV_HOLE => StreamInterrupted,
            ffi::OV_EREAD => ReadError,
            ffi::OV_EFAULT => InternalFault,
            ffi::OV_EIMPL => NotImplemented,
            ffi::OV_EINVAL => InvalidArgument,
            ffi::OV_ENOTVORBIS => NotVorbis,
            ffi::OV_EBADHEADER => InvalidHeader,
            ffi::OV_EVERSION => UnsupportedVersion,
            ffi::OV_EBADLINK => CorruptLink,
            ffi::OV_ENOSEEK => NotSeekable,
            x => fail!("Unexpected OVError code: {}", x)
        }
    }
}

/// Ogg Vorbis file decoder.
pub struct VorbisFile<R> {
    src: R,
    decoder: ffi::OggVorbis_File,
    // Totally not 'static, but need a lifetime specifier to get a slice.
    channels: Vec<raw::Slice<f32>>,
}

/// File metadata
pub struct Comments<'a> {
    /// The Vorbis implementation that encoded the stream.
    pub vendor: CString,
    /// User-specified key-value pairs of the form KEY=VALUE.
    pub comments: Vec<&'a str>
}

#[allow(unused_variable)]
extern "C" fn seek(datasource: *mut c_void, offset: i64, whence: c_int) -> c_int {
    // TODO permit seeking
    -1
}
#[allow(unused_variable)]
extern "C" fn close(datasource: *mut c_void) -> c_int {
    // No need to do anything. VorbisFile owns the Reader we're using.
    0
}
#[allow(unused_variable)]
extern "C" fn tell(datasource: *mut c_void) -> c_long {
    // TODO permit seeking
    -1
}

// Don't expose ov_fopen and friends because that won't play nicely
// with non-libnative runtime.
impl<R: Reader> VorbisFile<R> {
    /// Ensures the FFI struct is consistent for callback invocation.
    ///
    /// Because the user may move this struct, the `datasource` pointer
    /// passed back to FFI callbacks might be invalidated. This function
    /// should be called before FFI actions that might fire callbacks to ensure
    /// the self-pointer is valid.
    fn callback_setup(&mut self) {
        let ds = self as *mut _ as *mut c_void;
        self.decoder.datasource = ds;
    }

    /// Create a Ogg Vorbis decoder.
    pub fn new(src: R) -> OVResult<VorbisFile<R>> {
        let mut vf = VorbisFile {
            src: src,
            decoder: unsafe { mem::uninitialized() },
            channels: Vec::new()
        };
        let callbacks = ffi::ov_callbacks {
            read: VorbisFile::<R>::read,
            seek: seek,
            tell: tell,
            close: close,
        };

        let status = unsafe {
            ffi::ov_open_callbacks(&mut vf.src as *mut _ as *mut c_void,
                                   &mut vf.decoder as *mut _,
                                   ptr::mut_null(), 0, callbacks)
        };

        match status {
            0 => Ok(vf),
            f => {
                // Must not run the destructor. decoder is still uninitialized.
                unsafe {
                    mem::forget(vf.decoder);
                }
                Err(OVError::from_native(f))
            }
        }
    }

    /// Gets the comment struct for the specified bitstream.
    ///
    /// For nonseekable streams, returns the comments for the current
    /// bitstream. Otherwise, specify bitstream -1 to get the current
    /// bitstream.
    pub fn comment<'a>(&'a mut self, link: int) -> Option<Comments<'a>> {
        let cm = unsafe {
            let p = ffi::ov_comment(&mut self.decoder, link as c_int);
            if p.is_null() {
                return None;
            } else {
                *p
            }
        };

        unsafe fn make_str<'a>(data: *const u8, len: uint) -> Option<&'a str> {
            let slice = raw::Slice {
                data: data,
                len: len
            };
            str::from_utf8(mem::transmute(slice))
        }

        Some(Comments {
            vendor: unsafe {
                CString::new(cm.vendor as *const _, false)
            },
            comments: unsafe {
                let mut v = Vec::with_capacity(cm.comments as uint);
                for i in range(0, cm.comments) {
                    let len = *cm.comment_lengths.offset(i as int);
                    match make_str(*cm.user_comments.offset(i as int) as *const _,
                                   len as uint) {
                        Some(s) => {
                            v.push(s);
                        }
                        None => {
                            // Ignore. Vorbis specifies all comment data is valid
                            // UTF-8, but we need to protect against invalid input
                        }
                    }
                }
                v
            }
        })
    }

    /// Decode a block of samples.
    ///
    /// The emitted values are a slice of channels, each containing an equal
    /// number of samples.
    pub fn decode<'a>(&'a mut self) -> OVResult<&'a [&'a [f32]]> {
        let max_samples = 4096;
        self.callback_setup();
        let mut sample_buffer: *mut *mut f32 = unsafe {
            mem::uninitialized()
        };
        let mut bitstream_idx: c_int = unsafe {
            mem::uninitialized()
        };

        let n_samples = unsafe {
            match ffi::ov_read_float(&mut self.decoder, &mut sample_buffer,
                                     max_samples, &mut bitstream_idx) {
                0 => {
                    return Err(EndOfStream);
                }
                x if x < 0 => {
                    return Err(OVError::from_native(x as c_int));
                }
                x => x
            }
        };
        let n_channels = unsafe {
            (*ffi::ov_info(&mut self.decoder, bitstream_idx)).channels
        };

        self.channels.truncate(0);
        for i in range(0, n_channels) {
            unsafe {
                let channel_buffer = *sample_buffer.offset(i as int);
                let channel_slice = raw::Slice::<f32> {
                    data: channel_buffer as *const f32,
                    len: n_samples as uint
                };
                self.channels.push(channel_slice);
            };
        }
        Ok(unsafe {
            mem::transmute(self.channels.as_slice())
        })
    }

    /// Read `nmemb` items into `ptr` of `size` bytes each.
    ///
    /// If 0 is returned, error status is implied by errno. If nonzero, there was
    /// a read error. Otherwise, reached EOF.
    extern "C" fn read(buffer: *mut c_void, size: size_t, nmemb: size_t,
                       datasource: *mut c_void) -> size_t {
        let vf: &mut VorbisFile<R> = unsafe { mem::transmute(datasource) };
        let ptr = buffer as *mut u8;

        for i in range(0, nmemb) {
            let more = unsafe {
                mut_buf_as_slice(ptr.offset(i as int), size as uint, |buf| {
                    match vf.src.read_at_least(size as uint, buf) {
                        Ok(_) => true,
                        // Assume errno is set under the covers.
                        Err(_) => false
                    }
                })
            };
            if !more {
                // Got error, which might be EOF.
                return i;
            }
        }
        // Completed successfully
        return nmemb;
    }
}

#[unsafe_destructor]
impl<R: Reader> Drop for VorbisFile<R> {
    fn drop(&mut self) {
        self.callback_setup();
        unsafe {
            ffi::ov_clear(&mut self.decoder);
        }
    }
}
<commit_msg>Return mutable channel buffers from decode().<commit_after>#![crate_name = "libvorbisfile"]
#![doc(html_root_url = "http://www.rust-ci.org/tari/vorbisfile.rs/doc/libvorbisfile/")]

#![deny(dead_code, missing_doc)]
#![feature(unsafe_destructor)]

//! Ogg Vorbis file decoding, library bindings.

extern crate debug;
extern crate libc;
use libc::{c_void, c_int, c_long, size_t};

use std::c_str::CString;
use std::mem;
use std::str;
use std::ptr;
use std::raw;
use std::slice::raw::mut_buf_as_slice;

#[allow(dead_code, non_snake_case)]
mod ffi;

pub type OVResult<T> = Result<T, OVError>;

/// Decode error.
#[deriving(Show, Clone)]
pub enum OVError {
    /// Reached end of file.
    EndOfStream,
    /// Encounted missing or corrupt data.
    ///
    /// Recovery from this error is usually automatic and is returned for
    /// informational purposes only.
    StreamInterrupted,
    /// I/O error while reading compressed data to decode.
    ReadError,
    /// Internal inconsistency in encode or decode state. Recovery impossible.
    InternalFault,
    /// Feature not implemented.
    NotImplemented,
    /// User passed an invalid argument to a function.
    InvalidArgument,
    /// Provided data is not recognized as Ogg Vorbis.
    NotVorbis,
    /// Provided data appears to be Ogg Vorbis but has a corrupt or
    /// indecipherable header.
    InvalidHeader,
    /// Bitstream format revision is not supported.
    UnsupportedVersion,
    /// The specified Vorbis link exists but is corrupt.
    CorruptLink,
    /// The stream is not seekable.
    NotSeekable,
}

impl OVError {
    fn from_native(code: c_int) -> OVError {
        match code {
            ffi::OV_HOLE => StreamInterrupted,
            ffi::OV_EREAD => ReadError,
            ffi::OV_EFAULT => InternalFault,
            ffi::OV_EIMPL => NotImplemented,
            ffi::OV_EINVAL => InvalidArgument,
            ffi::OV_ENOTVORBIS => NotVorbis,
            ffi::OV_EBADHEADER => InvalidHeader,
            ffi::OV_EVERSION => UnsupportedVersion,
            ffi::OV_EBADLINK => CorruptLink,
            ffi::OV_ENOSEEK => NotSeekable,
            x => fail!("Unexpected OVError code: {}", x)
        }
    }
}

/// Ogg Vorbis file decoder.
pub struct VorbisFile<R> {
    src: R,
    decoder: ffi::OggVorbis_File,
    // Totally not 'static, but need a lifetime specifier to get a slice.
    channels: Vec<raw::Slice<f32>>,
}

/// File metadata
pub struct Comments<'a> {
    /// The Vorbis implementation that encoded the stream.
    pub vendor: CString,
    /// User-specified key-value pairs of the form KEY=VALUE.
    pub comments: Vec<&'a str>
}

#[allow(unused_variable)]
extern "C" fn seek(datasource: *mut c_void, offset: i64, whence: c_int) -> c_int {
    // TODO permit seeking
    -1
}
#[allow(unused_variable)]
extern "C" fn close(datasource: *mut c_void) -> c_int {
    // No need to do anything. VorbisFile owns the Reader we're using.
    0
}
#[allow(unused_variable)]
extern "C" fn tell(datasource: *mut c_void) -> c_long {
    // TODO permit seeking
    -1
}

// Don't expose ov_fopen and friends because that won't play nicely
// with non-libnative runtime.
impl<R: Reader> VorbisFile<R> {
    /// Ensures the FFI struct is consistent for callback invocation.
    ///
    /// Because the user may move this struct, the `datasource` pointer
    /// passed back to FFI callbacks might be invalidated. This function
    /// should be called before FFI actions that might fire callbacks to ensure
    /// the self-pointer is valid.
    fn callback_setup(&mut self) {
        let ds = self as *mut _ as *mut c_void;
        self.decoder.datasource = ds;
    }

    /// Create a Ogg Vorbis decoder.
    pub fn new(src: R) -> OVResult<VorbisFile<R>> {
        let mut vf = VorbisFile {
            src: src,
            decoder: unsafe { mem::uninitialized() },
            channels: Vec::new()
        };
        let callbacks = ffi::ov_callbacks {
            read: VorbisFile::<R>::read,
            seek: seek,
            tell: tell,
            close: close,
        };

        let status = unsafe {
            ffi::ov_open_callbacks(&mut vf.src as *mut _ as *mut c_void,
                                   &mut vf.decoder as *mut _,
                                   ptr::mut_null(), 0, callbacks)
        };

        match status {
            0 => Ok(vf),
            f => {
                // Must not run the destructor. decoder is still uninitialized.
                unsafe {
                    mem::forget(vf.decoder);
                }
                Err(OVError::from_native(f))
            }
        }
    }

    /// Gets the comment struct for the specified bitstream.
    ///
    /// For nonseekable streams, returns the comments for the current
    /// bitstream. Otherwise, specify bitstream -1 to get the current
    /// bitstream.
    pub fn comment<'a>(&'a mut self, link: int) -> Option<Comments<'a>> {
        let cm = unsafe {
            let p = ffi::ov_comment(&mut self.decoder, link as c_int);
            if p.is_null() {
                return None;
            } else {
                *p
            }
        };

        unsafe fn make_str<'a>(data: *const u8, len: uint) -> Option<&'a str> {
            let slice = raw::Slice {
                data: data,
                len: len
            };
            str::from_utf8(mem::transmute(slice))
        }

        Some(Comments {
            vendor: unsafe {
                CString::new(cm.vendor as *const _, false)
            },
            comments: unsafe {
                let mut v = Vec::with_capacity(cm.comments as uint);
                for i in range(0, cm.comments) {
                    let len = *cm.comment_lengths.offset(i as int);
                    match make_str(*cm.user_comments.offset(i as int) as *const _,
                                   len as uint) {
                        Some(s) => {
                            v.push(s);
                        }
                        None => {
                            // Ignore. Vorbis specifies all comment data is valid
                            // UTF-8, but we need to protect against invalid input
                        }
                    }
                }
                v
            }
        })
    }

    /// Decode a block of samples.
    ///
    /// The emitted values are a slice of channels, each containing an equal
    /// number of samples.
    pub fn decode<'a>(&'a mut self) -> OVResult<&'a [&'a mut [f32]]> {
        let max_samples = 4096;
        self.callback_setup();
        let mut sample_buffer: *mut *mut f32 = unsafe {
            mem::uninitialized()
        };
        let mut bitstream_idx: c_int = unsafe {
            mem::uninitialized()
        };

        let n_samples = unsafe {
            match ffi::ov_read_float(&mut self.decoder, &mut sample_buffer,
                                     max_samples, &mut bitstream_idx) {
                0 => {
                    return Err(EndOfStream);
                }
                x if x < 0 => {
                    return Err(OVError::from_native(x as c_int));
                }
                x => x
            }
        };
        let n_channels = unsafe {
            (*ffi::ov_info(&mut self.decoder, bitstream_idx)).channels
        };

        self.channels.truncate(0);
        for i in range(0, n_channels) {
            unsafe {
                let channel_buffer = *sample_buffer.offset(i as int);
                let channel_slice = raw::Slice::<f32> {
                    data: channel_buffer as *const f32,
                    len: n_samples as uint
                };
                self.channels.push(channel_slice);
            };
        }
        Ok(unsafe {
            mem::transmute(self.channels.as_slice())
        })
    }

    /// Read `nmemb` items into `ptr` of `size` bytes each.
    ///
    /// If 0 is returned, error status is implied by errno. If nonzero, there was
    /// a read error. Otherwise, reached EOF.
    extern "C" fn read(buffer: *mut c_void, size: size_t, nmemb: size_t,
                       datasource: *mut c_void) -> size_t {
        let vf: &mut VorbisFile<R> = unsafe { mem::transmute(datasource) };
        let ptr = buffer as *mut u8;

        for i in range(0, nmemb) {
            let more = unsafe {
                mut_buf_as_slice(ptr.offset(i as int), size as uint, |buf| {
                    match vf.src.read_at_least(size as uint, buf) {
                        Ok(_) => true,
                        // Assume errno is set under the covers.
                        Err(_) => false
                    }
                })
            };
            if !more {
                // Got error, which might be EOF.
                return i;
            }
        }
        // Completed successfully
        return nmemb;
    }
}

#[unsafe_destructor]
impl<R: Reader> Drop for VorbisFile<R> {
    fn drop(&mut self) {
        self.callback_setup();
        unsafe {
            ffi::ov_clear(&mut self.decoder);
        }
    }
}
<|endoftext|>


<commit_before>#![feature(associated_consts)]
#![feature(drain)]

extern crate uuid;
extern crate typed_arena;
mod js_types;
mod alloc;

use std::collections::hash_set::HashSet;
use std::ptr::null_mut;
use std::rc::Rc;
use uuid::Uuid;

use alloc::scope::Scope;
use js_types::js_type::JsVar;

pub struct ScopeManager {
    root_scope: Rc<Scope>,
    curr_scope: *mut Rc<Scope>,
}

impl ScopeManager {
    pub fn new<F>(callback: F) -> ScopeManager where F: Fn() -> HashSet<Uuid> + 'static {
        let scope = Rc::new(Scope::new(callback));
        let mut mgr =
            ScopeManager {
                root_scope: scope,
                curr_scope: null_mut(),
            };
        mgr.curr_scope = &mut (mgr.root_scope) as *mut Rc<Scope>;
        mgr
    }

    pub fn push_scope<F>(&mut self, callback: F) where F: Fn() -> HashSet<Uuid> + 'static {
        unsafe {
            let weak_clone = Rc::downgrade(&*self.curr_scope.clone());
            self.curr_scope =
                Rc::get_mut(&mut *self.curr_scope)
                    .unwrap()
                    .add_child(Scope::as_child(weak_clone, callback)) as *mut Rc<Scope>;
        }
    }

    pub fn pop_scope(&mut self) {
        let parent = unsafe { (*self.curr_scope).parent.clone() };
        if let Some(parent) = parent {
            if let Some(mut scope) = parent.upgrade() {
                // Pop old scope
                let num_children = scope.children.len();
                Rc::get_mut(&mut scope).unwrap().children.remove(num_children - 1);
                // Set curr_scope to old scope's parent
                self.curr_scope = &mut scope as *mut Rc<Scope>;
            }
        } else {
            panic!("Tried to pop to parent scope, but parent did not exist!");
        }
    }
}

pub fn init<F>(callback: F) -> ScopeManager
    where F: Fn() -> HashSet<Uuid> + 'static {
    ScopeManager::new(callback)
}

pub fn load(scope: &Scope, uuid: Uuid) -> Option<JsVar> {
    scope.get_var_copy(&uuid)
}

pub fn store(scope: &mut Scope, var: JsVar) -> bool {
    scope.update_var(var)
}
<commit_msg>Move load, store, & alloc into ScopeManager, rename init -> init_gc<commit_after>#![feature(associated_consts)]
#![feature(drain)]

extern crate uuid;
extern crate typed_arena;
mod js_types;
mod alloc;

use std::collections::hash_set::HashSet;
use std::ptr::null_mut;
use std::rc::Rc;
use uuid::Uuid;

use alloc::scope::Scope;
use js_types::js_type::JsVar;

pub struct ScopeManager {
    root_scope: Rc<Scope>,
    curr_scope: *mut Rc<Scope>,
}

impl ScopeManager {
    pub fn new<F>(callback: F) -> ScopeManager where F: Fn() -> HashSet<Uuid> + 'static {
        let scope = Rc::new(Scope::new(callback));
        let mut mgr =
            ScopeManager {
                root_scope: scope,
                curr_scope: null_mut(),
            };
        mgr.curr_scope = &mut (mgr.root_scope) as *mut Rc<Scope>;
        mgr
    }

    pub fn push_scope<F>(&mut self, callback: F) where F: Fn() -> HashSet<Uuid> + 'static {
        unsafe {
            let weak_clone = Rc::downgrade(&*self.curr_scope.clone());
            self.curr_scope =
                Rc::get_mut(&mut *self.curr_scope)
                    .unwrap()
                    .add_child(Scope::as_child(weak_clone, callback)) as *mut Rc<Scope>;
        }
    }

    pub fn pop_scope(&mut self) {
        let parent = unsafe { (*self.curr_scope).parent.clone() };
        if let Some(parent) = parent {
            if let Some(mut scope) = parent.upgrade() {
                // Pop old scope
                let num_children = scope.children.len();
                Rc::get_mut(&mut scope).unwrap().children.remove(num_children - 1);
                // Set curr_scope to old scope's parent
                self.curr_scope = &mut scope as *mut Rc<Scope>;
            }
        } else {
            panic!("Tried to pop to parent scope, but parent did not exist!");
        }
    }

    pub fn alloc(&mut self, var: JsVar) -> Uuid {
        unsafe { Rc::get_mut(&mut *self.curr_scope).unwrap().alloc(var) }
    }

    pub fn load(&self, uuid: Uuid) -> Option<JsVar> {
        unsafe { (*self.curr_scope).get_var_copy(&uuid) }
    }

    pub fn store(&mut self, var: JsVar) -> bool {
        unsafe { Rc::get_mut(&mut *self.curr_scope).unwrap().update_var(var) }
    }
}

pub fn init_gc<F>(callback: F) -> ScopeManager
    where F: Fn() -> HashSet<Uuid> + 'static {
    ScopeManager::new(callback)
}

<|endoftext|>


<commit_before>//! The `neon` crate provides the entire [Neon](https://www.neon-bindings.com/) API.

extern crate neon_runtime;
extern crate cslice;
extern crate semver;

#[cfg(test)]
extern crate rustc_version;

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

pub mod mem;
pub mod vm;
pub mod js;
pub mod task;
pub mod meta;

#[doc(hidden)]
pub mod macro_internal;

// FIXME: document that the first argument is an identifier that binds a ModuleContext

/// Register the current crate as a Node module, providing startup
/// logic for initializing the module object at runtime.
///
/// Example:
///
/// ```rust,ignore
/// register_module!(cx, {
///     cx.export_function("foo", foo)?;
///     cx.export_function("bar", bar)?;
///     cx.export_function("baz", baz)?;
///     Ok(())
/// });
/// ```
#[macro_export]
macro_rules! register_module {
    ($module:ident, $init:block) => {
        // Mark this function as a global constructor (like C++).
        #[allow(improper_ctypes)]
        #[cfg_attr(target_os = "linux", link_section = ".ctors")]
        #[cfg_attr(target_os = "macos", link_section = "__DATA,__mod_init_func")]
        #[cfg_attr(target_os = "windows", link_section = ".CRT$XCU")]
        pub static __LOAD_NEON_MODULE: extern "C" fn() = {
            fn __init_neon_module(mut $module: $crate::vm::ModuleContext) -> $crate::vm::VmResult<()> $init

            extern "C" fn __load_neon_module() {
                // Put everything else in the ctor fn so the user fn can't see it.
                #[repr(C)]
                struct __NodeModule {
                    version: i32,
                    flags: u32,
                    dso_handle: *mut u8,
                    filename: *const u8,
                    register_func: Option<extern "C" fn(
                        $crate::mem::Handle<$crate::js::JsObject>, *mut u8, *mut u8)>,
                    context_register_func: Option<extern "C" fn(
                        $crate::mem::Handle<$crate::js::JsObject>, *mut u8, *mut u8, *mut u8)>,
                    modname: *const u8,
                    priv_data: *mut u8,
                    link: *mut __NodeModule
                }

                static mut __NODE_MODULE: __NodeModule = __NodeModule {
                    version: 0,
                    flags: 0,
                    dso_handle: 0 as *mut _,
                    filename: b"neon_source.rs\0" as *const u8,
                    register_func: Some(__register_neon_module),
                    context_register_func: None,
                    modname: b"neon_module\0" as *const u8,
                    priv_data: 0 as *mut _,
                    link: 0 as *mut _
                };

                extern "C" fn __register_neon_module(
                        m: $crate::mem::Handle<$crate::js::JsObject>, _: *mut u8, _: *mut u8) {
                    $crate::macro_internal::initialize_module(m, __init_neon_module);
                }

                extern "C" {
                    fn node_module_register(module: *mut __NodeModule);
                }

                // Suppress the default Rust panic hook, which prints diagnostics to stderr.
                ::std::panic::set_hook(::std::boxed::Box::new(|_| { }));

                unsafe {
                    // Set the ABI version based on the NODE_MODULE_VERSION constant provided by the current node headers.
                    __NODE_MODULE.version = $crate::macro_internal::runtime::module::get_version();
                    node_module_register(&mut __NODE_MODULE);
                }
            }

            __load_neon_module
        };
    }
}

#[doc(hidden)]
#[macro_export]
macro_rules! class_definition {
    ( $cls:ident ; $cname:ident ; $typ:ty ; $allocator:tt ; $call_ctor:tt ; $new_ctor:tt ; $mnames:tt ; $mdefs:tt ; init($cx:pat) $body:block $($rest:tt)* ) => {
        class_definition!($cls ;
                          $cname ;
                          $typ ;
                          {
                              fn _______allocator_rust_y_u_no_hygienic_items_______($cx: $crate::vm::CallContext<$crate::js::JsUndefined>) -> $crate::vm::VmResult<$typ> {
                                  $body
                              }

                              $crate::macro_internal::AllocateCallback(_______allocator_rust_y_u_no_hygienic_items_______)
                          } ;
                          $call_ctor ;
                          $new_ctor ;
                          $mnames ;
                          $mdefs ;
                          $($rest)*);
    };

    ( $cls:ident ; $cname:ident ; $typ:ty ; $allocator:tt ; $call_ctor:tt ; $new_ctor:tt ; ($($mname:tt)*) ; ($($mdef:tt)*) ; method $name:ident($cx:pat) $body:block $($rest:tt)* ) => {
        class_definition!($cls ;
                          $cname ;
                          $typ ;
                          $allocator ;
                          $call_ctor ;
                          $new_ctor ;
                          ($($mname)* $name) ;
                          ($($mdef)* {
                              fn _______method_rust_y_u_no_hygienic_items_______($cx: $crate::vm::CallContext<$cls>) -> $crate::vm::JsResult<$crate::js::JsValue> {
                                  $body
                              }

                              $crate::macro_internal::MethodCallback(_______method_rust_y_u_no_hygienic_items_______)
                          }) ;
                          $($rest)*);
    };

    ( $cls:ident ; $cname:ident ; $typ:ty ; $allocator:tt ; $call_ctor:tt ; $new_ctor:tt ; $mnames:tt ; $mdefs:tt ; constructor($cx:pat) $body:block $($rest:tt)* ) => {
        class_definition!($cls ;
                          $cname ;
                          $typ ;
                          $allocator ;
                          $call_ctor ;
                          ({
                              fn _______constructor_rust_y_u_no_hygienic_items_______($cx: $crate::vm::CallContext<$cls>) -> $crate::vm::VmResult<Option<$crate::mem::Handle<$crate::js::JsObject>>> {
                                  $body
                              }

                              $crate::macro_internal::ConstructCallback::new(_______constructor_rust_y_u_no_hygienic_items_______)
                          }) ;
                          $mnames ;
                          $mdefs ;
                          $($rest)*);
    };

    ( $cls:ident ; $cname:ident ; $typ:ty ; $allocator:tt ; $call_ctor:tt ; $new_ctor:tt ; $mnames:tt ; $mdefs:tt ; call($cx:pat) $body:block $($rest:tt)* ) => {
        class_definition!($cls ;
                          $cname ;
                          $typ ;
                          $allocator ;
                          ({
                              fn _______call_rust_y_u_no_hygienic_items_______($cx: $crate::vm::CallContext<$crate::js::JsValue>) -> $crate::vm::JsResult<$crate::js::JsValue> {
                                  $body
                              }

                              $crate::macro_internal::ConstructorCallCallback::new(_______call_rust_y_u_no_hygienic_items_______)
                          }) ;
                          $new_ctor ;
                          $mnames ;
                          $mdefs ;
                          $($rest)*);
    };

    ( $cls:ident ; $cname:ident ; $typ:ty ; $allocator:block ; ($($call_ctor:block)*) ; ($($new_ctor:block)*) ; ($($mname:ident)*) ; ($($mdef:block)*) ; $($rest:tt)* ) => {
        impl $crate::js::class::Class for $cls {
            type Internals = $typ;

            fn setup<'a, C: $crate::vm::Context<'a>>(_: &mut C) -> $crate::vm::VmResult<$crate::js::class::ClassDescriptor<'a, Self>> {
                ::std::result::Result::Ok(Self::describe(stringify!($cname), $allocator)
                                             $(.construct($new_ctor))*
                                             $(.call($call_ctor))*
                                             $(.method(stringify!($mname), $mdef))*)
            }
        }
    };
}

#[doc(hidden)]
#[macro_export]
macro_rules! impl_managed {
    ($cls:ident) => {
        impl $crate::mem::Managed for $cls {
            fn to_raw(self) -> $crate::macro_internal::runtime::raw::Local {
                let $cls(raw) = self;
                raw
            }

            fn from_raw(raw: $crate::macro_internal::runtime::raw::Local) -> Self {
                $cls(raw)
            }
        }
    }
}

/// Declare custom native JavaScript types with Rust implementations.
///
/// Example:
///
/// ```rust,ignore
/// pub struct Greeter {
///     greeting: String
/// }
///
/// declare_types! {
///
///     /// A class for generating greeting strings.
///     pub class JsGreeter for Greeter {
///         init(cx) {
///             let greeting = cx.argument(0)?.to_string(&mut cx)?.value();
///             Ok(Greeter {
///                 greeting: greeting
///             })
///         }
///
///         method hello(cx) {
///             let name = cx.argument(0)?.to_string(&mut cx)?.value();
///             let this = cx.this();
///             let msg = {
///                 let guard = cx.lock();
///                 let greeter = this.borrow(&guard);
///                 format!("{}, {}!", greeter.greeting, name)
///             };
///             Ok(cx.string(&msg[..])?.upcast())
///         }
///     }
///
/// }
/// ```
#[macro_export]
macro_rules! declare_types {
    { $(#[$attr:meta])* pub class $cls:ident for $typ:ident { $($body:tt)* } $($rest:tt)* } => {
        declare_types! { $(#[$attr])* pub class $cls as $typ for $typ { $($body)* } $($rest)* }
    };

    { $(#[$attr:meta])* class $cls:ident for $typ:ident { $($body:tt)* } $($rest:tt)* } => {
        declare_types! { $(#[$attr])* class $cls as $typ for $typ { $($body)* } $($rest)* }
    };

    { $(#[$attr:meta])* pub class $cls:ident as $cname:ident for $typ:ty { $($body:tt)* } $($rest:tt)* } => {
        #[derive(Copy, Clone)]
        #[repr(C)]
        $(#[$attr])*
        pub struct $cls($crate::macro_internal::runtime::raw::Local);

        impl_managed!($cls);

        class_definition!($cls ; $cname ; $typ ; () ; () ; () ; () ; () ; $($body)*);

        declare_types! { $($rest)* }
    };

    { $(#[$attr:meta])* class $cls:ident as $cname:ident for $typ:ty { $($body:tt)* } $($rest:tt)* } => {
        #[derive(Copy, Clone)]
        #[repr(C)]
        $(#[$attr])*
        struct $cls($crate::macro_internal::runtime::raw::Local);

        impl_managed!($cls);

        class_definition!($cls ; $cname ; $typ ; () ; () ; () ; () ; () ; $($body)*);

        declare_types! { $($rest)* }
    };

    { } => { };
}

#[cfg(all(windows, not(neon_profile = "release")))]
compile_error!("Neon only builds with --release. For tests, try `cargo test --release`.");

#[cfg(test)]
mod tests {
    use std::path::{Path, PathBuf};
    use std::process::Command;
    use std::sync::Mutex;

    use rustc_version::{version_meta, Channel};

    // Create a mutex to enforce sequential running of the tests.
    lazy_static! {
        static ref TEST_MUTEX: Mutex<()> = Mutex::new(());
    }

    fn project_root() -> PathBuf {
        Path::new(env!("CARGO_MANIFEST_DIR")).to_path_buf()
    }

    fn log(test_name: &str) {
        eprintln!("======================================================");
        eprintln!("Neon test: {}", test_name);
        eprintln!("======================================================");
    }

    fn run(cmd: &str, dir: &Path) {
        let (shell, command_flag) = if cfg!(windows) {
            ("cmd", "/C")
        } else {
            ("sh", "-c")
        };

        assert!(Command::new(&shell)
                        .current_dir(dir)
                        .args(&[&command_flag, cmd])
                        .status()
                        .expect("failed to execute test command")
                        .success());
    }

    fn cli_setup() {
        let cli = project_root().join("cli");

        run("npm install", &cli);
        run("npm run transpile", &cli);
    }

    #[test]
    fn cli_test() {
        let _guard = TEST_MUTEX.lock();

        log("cli_test");

        cli_setup();

        let test_cli = project_root().join("test").join("cli");
        run("npm install", &test_cli);
        run("npm run transpile", &test_cli);
        run("npm test", &test_cli);
    }

    #[cfg(not(windows))]
    #[test]
    fn static_test() {
        let _guard = TEST_MUTEX.lock();

        log("static_test");

        if version_meta().unwrap().channel != Channel::Nightly {
            return;
        }

        run("cargo test --release", &project_root().join("test").join("static"));
    }

    #[test]
    fn dynamic_test() {
        let _guard = TEST_MUTEX.lock();

        log("dynamic_test");

        cli_setup();

        let test_dynamic = project_root().join("test").join("dynamic");
        run("npm install", &test_dynamic);
        run("npm test", &test_dynamic);
    }
}
<commit_msg>`ConstructCallback` and `ConstructorCallCallback` no longer have a `new` method, just a public type declaration<commit_after>//! The `neon` crate provides the entire [Neon](https://www.neon-bindings.com/) API.

extern crate neon_runtime;
extern crate cslice;
extern crate semver;

#[cfg(test)]
extern crate rustc_version;

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

pub mod mem;
pub mod vm;
pub mod js;
pub mod task;
pub mod meta;

#[doc(hidden)]
pub mod macro_internal;

// FIXME: document that the first argument is an identifier that binds a ModuleContext

/// Register the current crate as a Node module, providing startup
/// logic for initializing the module object at runtime.
///
/// Example:
///
/// ```rust,ignore
/// register_module!(cx, {
///     cx.export_function("foo", foo)?;
///     cx.export_function("bar", bar)?;
///     cx.export_function("baz", baz)?;
///     Ok(())
/// });
/// ```
#[macro_export]
macro_rules! register_module {
    ($module:ident, $init:block) => {
        // Mark this function as a global constructor (like C++).
        #[allow(improper_ctypes)]
        #[cfg_attr(target_os = "linux", link_section = ".ctors")]
        #[cfg_attr(target_os = "macos", link_section = "__DATA,__mod_init_func")]
        #[cfg_attr(target_os = "windows", link_section = ".CRT$XCU")]
        pub static __LOAD_NEON_MODULE: extern "C" fn() = {
            fn __init_neon_module(mut $module: $crate::vm::ModuleContext) -> $crate::vm::VmResult<()> $init

            extern "C" fn __load_neon_module() {
                // Put everything else in the ctor fn so the user fn can't see it.
                #[repr(C)]
                struct __NodeModule {
                    version: i32,
                    flags: u32,
                    dso_handle: *mut u8,
                    filename: *const u8,
                    register_func: Option<extern "C" fn(
                        $crate::mem::Handle<$crate::js::JsObject>, *mut u8, *mut u8)>,
                    context_register_func: Option<extern "C" fn(
                        $crate::mem::Handle<$crate::js::JsObject>, *mut u8, *mut u8, *mut u8)>,
                    modname: *const u8,
                    priv_data: *mut u8,
                    link: *mut __NodeModule
                }

                static mut __NODE_MODULE: __NodeModule = __NodeModule {
                    version: 0,
                    flags: 0,
                    dso_handle: 0 as *mut _,
                    filename: b"neon_source.rs\0" as *const u8,
                    register_func: Some(__register_neon_module),
                    context_register_func: None,
                    modname: b"neon_module\0" as *const u8,
                    priv_data: 0 as *mut _,
                    link: 0 as *mut _
                };

                extern "C" fn __register_neon_module(
                        m: $crate::mem::Handle<$crate::js::JsObject>, _: *mut u8, _: *mut u8) {
                    $crate::macro_internal::initialize_module(m, __init_neon_module);
                }

                extern "C" {
                    fn node_module_register(module: *mut __NodeModule);
                }

                // Suppress the default Rust panic hook, which prints diagnostics to stderr.
                ::std::panic::set_hook(::std::boxed::Box::new(|_| { }));

                unsafe {
                    // Set the ABI version based on the NODE_MODULE_VERSION constant provided by the current node headers.
                    __NODE_MODULE.version = $crate::macro_internal::runtime::module::get_version();
                    node_module_register(&mut __NODE_MODULE);
                }
            }

            __load_neon_module
        };
    }
}

#[doc(hidden)]
#[macro_export]
macro_rules! class_definition {
    ( $cls:ident ; $cname:ident ; $typ:ty ; $allocator:tt ; $call_ctor:tt ; $new_ctor:tt ; $mnames:tt ; $mdefs:tt ; init($cx:pat) $body:block $($rest:tt)* ) => {
        class_definition!($cls ;
                          $cname ;
                          $typ ;
                          {
                              fn _______allocator_rust_y_u_no_hygienic_items_______($cx: $crate::vm::CallContext<$crate::js::JsUndefined>) -> $crate::vm::VmResult<$typ> {
                                  $body
                              }

                              $crate::macro_internal::AllocateCallback(_______allocator_rust_y_u_no_hygienic_items_______)
                          } ;
                          $call_ctor ;
                          $new_ctor ;
                          $mnames ;
                          $mdefs ;
                          $($rest)*);
    };

    ( $cls:ident ; $cname:ident ; $typ:ty ; $allocator:tt ; $call_ctor:tt ; $new_ctor:tt ; ($($mname:tt)*) ; ($($mdef:tt)*) ; method $name:ident($cx:pat) $body:block $($rest:tt)* ) => {
        class_definition!($cls ;
                          $cname ;
                          $typ ;
                          $allocator ;
                          $call_ctor ;
                          $new_ctor ;
                          ($($mname)* $name) ;
                          ($($mdef)* {
                              fn _______method_rust_y_u_no_hygienic_items_______($cx: $crate::vm::CallContext<$cls>) -> $crate::vm::JsResult<$crate::js::JsValue> {
                                  $body
                              }

                              $crate::macro_internal::MethodCallback(_______method_rust_y_u_no_hygienic_items_______)
                          }) ;
                          $($rest)*);
    };

    ( $cls:ident ; $cname:ident ; $typ:ty ; $allocator:tt ; $call_ctor:tt ; $new_ctor:tt ; $mnames:tt ; $mdefs:tt ; constructor($cx:pat) $body:block $($rest:tt)* ) => {
        class_definition!($cls ;
                          $cname ;
                          $typ ;
                          $allocator ;
                          $call_ctor ;
                          ({
                              fn _______constructor_rust_y_u_no_hygienic_items_______($cx: $crate::vm::CallContext<$cls>) -> $crate::vm::VmResult<Option<$crate::mem::Handle<$crate::js::JsObject>>> {
                                  $body
                              }

                              $crate::macro_internal::ConstructCallback(_______constructor_rust_y_u_no_hygienic_items_______)
                          }) ;
                          $mnames ;
                          $mdefs ;
                          $($rest)*);
    };

    ( $cls:ident ; $cname:ident ; $typ:ty ; $allocator:tt ; $call_ctor:tt ; $new_ctor:tt ; $mnames:tt ; $mdefs:tt ; call($cx:pat) $body:block $($rest:tt)* ) => {
        class_definition!($cls ;
                          $cname ;
                          $typ ;
                          $allocator ;
                          ({
                              fn _______call_rust_y_u_no_hygienic_items_______($cx: $crate::vm::CallContext<$crate::js::JsValue>) -> $crate::vm::JsResult<$crate::js::JsValue> {
                                  $body
                              }

                              $crate::macro_internal::ConstructorCallCallback(_______call_rust_y_u_no_hygienic_items_______)
                          }) ;
                          $new_ctor ;
                          $mnames ;
                          $mdefs ;
                          $($rest)*);
    };

    ( $cls:ident ; $cname:ident ; $typ:ty ; $allocator:block ; ($($call_ctor:block)*) ; ($($new_ctor:block)*) ; ($($mname:ident)*) ; ($($mdef:block)*) ; $($rest:tt)* ) => {
        impl $crate::js::class::Class for $cls {
            type Internals = $typ;

            fn setup<'a, C: $crate::vm::Context<'a>>(_: &mut C) -> $crate::vm::VmResult<$crate::js::class::ClassDescriptor<'a, Self>> {
                ::std::result::Result::Ok(Self::describe(stringify!($cname), $allocator)
                                             $(.construct($new_ctor))*
                                             $(.call($call_ctor))*
                                             $(.method(stringify!($mname), $mdef))*)
            }
        }
    };
}

#[doc(hidden)]
#[macro_export]
macro_rules! impl_managed {
    ($cls:ident) => {
        impl $crate::mem::Managed for $cls {
            fn to_raw(self) -> $crate::macro_internal::runtime::raw::Local {
                let $cls(raw) = self;
                raw
            }

            fn from_raw(raw: $crate::macro_internal::runtime::raw::Local) -> Self {
                $cls(raw)
            }
        }
    }
}

/// Declare custom native JavaScript types with Rust implementations.
///
/// Example:
///
/// ```rust,ignore
/// pub struct Greeter {
///     greeting: String
/// }
///
/// declare_types! {
///
///     /// A class for generating greeting strings.
///     pub class JsGreeter for Greeter {
///         init(cx) {
///             let greeting = cx.argument(0)?.to_string(&mut cx)?.value();
///             Ok(Greeter {
///                 greeting: greeting
///             })
///         }
///
///         method hello(cx) {
///             let name = cx.argument(0)?.to_string(&mut cx)?.value();
///             let this = cx.this();
///             let msg = {
///                 let guard = cx.lock();
///                 let greeter = this.borrow(&guard);
///                 format!("{}, {}!", greeter.greeting, name)
///             };
///             Ok(cx.string(&msg[..])?.upcast())
///         }
///     }
///
/// }
/// ```
#[macro_export]
macro_rules! declare_types {
    { $(#[$attr:meta])* pub class $cls:ident for $typ:ident { $($body:tt)* } $($rest:tt)* } => {
        declare_types! { $(#[$attr])* pub class $cls as $typ for $typ { $($body)* } $($rest)* }
    };

    { $(#[$attr:meta])* class $cls:ident for $typ:ident { $($body:tt)* } $($rest:tt)* } => {
        declare_types! { $(#[$attr])* class $cls as $typ for $typ { $($body)* } $($rest)* }
    };

    { $(#[$attr:meta])* pub class $cls:ident as $cname:ident for $typ:ty { $($body:tt)* } $($rest:tt)* } => {
        #[derive(Copy, Clone)]
        #[repr(C)]
        $(#[$attr])*
        pub struct $cls($crate::macro_internal::runtime::raw::Local);

        impl_managed!($cls);

        class_definition!($cls ; $cname ; $typ ; () ; () ; () ; () ; () ; $($body)*);

        declare_types! { $($rest)* }
    };

    { $(#[$attr:meta])* class $cls:ident as $cname:ident for $typ:ty { $($body:tt)* } $($rest:tt)* } => {
        #[derive(Copy, Clone)]
        #[repr(C)]
        $(#[$attr])*
        struct $cls($crate::macro_internal::runtime::raw::Local);

        impl_managed!($cls);

        class_definition!($cls ; $cname ; $typ ; () ; () ; () ; () ; () ; $($body)*);

        declare_types! { $($rest)* }
    };

    { } => { };
}

#[cfg(all(windows, not(neon_profile = "release")))]
compile_error!("Neon only builds with --release. For tests, try `cargo test --release`.");

#[cfg(test)]
mod tests {
    use std::path::{Path, PathBuf};
    use std::process::Command;
    use std::sync::Mutex;

    use rustc_version::{version_meta, Channel};

    // Create a mutex to enforce sequential running of the tests.
    lazy_static! {
        static ref TEST_MUTEX: Mutex<()> = Mutex::new(());
    }

    fn project_root() -> PathBuf {
        Path::new(env!("CARGO_MANIFEST_DIR")).to_path_buf()
    }

    fn log(test_name: &str) {
        eprintln!("======================================================");
        eprintln!("Neon test: {}", test_name);
        eprintln!("======================================================");
    }

    fn run(cmd: &str, dir: &Path) {
        let (shell, command_flag) = if cfg!(windows) {
            ("cmd", "/C")
        } else {
            ("sh", "-c")
        };

        assert!(Command::new(&shell)
                        .current_dir(dir)
                        .args(&[&command_flag, cmd])
                        .status()
                        .expect("failed to execute test command")
                        .success());
    }

    fn cli_setup() {
        let cli = project_root().join("cli");

        run("npm install", &cli);
        run("npm run transpile", &cli);
    }

    #[test]
    fn cli_test() {
        let _guard = TEST_MUTEX.lock();

        log("cli_test");

        cli_setup();

        let test_cli = project_root().join("test").join("cli");
        run("npm install", &test_cli);
        run("npm run transpile", &test_cli);
        run("npm test", &test_cli);
    }

    #[cfg(not(windows))]
    #[test]
    fn static_test() {
        let _guard = TEST_MUTEX.lock();

        log("static_test");

        if version_meta().unwrap().channel != Channel::Nightly {
            return;
        }

        run("cargo test --release", &project_root().join("test").join("static"));
    }

    #[test]
    fn dynamic_test() {
        let _guard = TEST_MUTEX.lock();

        log("dynamic_test");

        cli_setup();

        let test_dynamic = project_root().join("test").join("dynamic");
        run("npm install", &test_dynamic);
        run("npm test", &test_dynamic);
    }
}
<|endoftext|>