<commit_before>//! Guessing of MIME types by file extension.
//!
//! Uses a static list of file-extension : MIME type mappings.
//!
//! #### Note: MIME Types Returned Are Not Stable/Guaranteed
//! The media types returned for a given extension are not considered to be part of the crate's
//! stable API and are often updated in patch (#.#.x) releases to be as correct as possible.
//!
//! Additionally, only the extensions of paths/filenames are inspected in order to guess the MIME
//! type. The file that may or may not reside at that path may or may not be a valid file of the
//! returned MIME type.  Be wary of unsafe or un-validated assumptions about file structure or
//! length.
#![cfg_attr(feature = "bench", feature(test))]

extern crate mime;
extern crate phf;
extern crate unicase;

pub use mime::Mime;
use unicase::UniCase;

use std::ffi::OsStr;
use std::path::Path;

include!(concat!(env!("OUT_DIR"), "/mime_types_generated.rs"));

#[cfg(feature = "rev-mappings")]
struct TopLevelExts {
    start: usize,
    end: usize,
    subs: phf::Map<UniCase<&'static str>, (usize, usize)>,
}

macro_rules! try_opt (
    ($expr:expr) => (
        match $expr {
            Some(val) => val,
            None => return None,
        }
    )
);

#[cfg(test)]
#[path = "mime_types.rs"]
mod mime_types_src;

/// Guess the MIME type of `path` by its extension (as defined by `Path::extension()`).
///
/// If `path` has no extension, or its extension has no known MIME type mapping,
/// then the MIME type is assumed to be `application/octet-stream`.
///
/// ## Note
/// **Guess** is the operative word here, as there are no guarantees that the contents of the file
/// that `path` points to match the MIME type associated with the path's extension.
///
/// Take care when processing files with assumptions based on the return value of this function.
///
/// In HTTP applications, it might be [preferable][rfc7231] to not send a `Content-Type`
/// header at all instead of defaulting to `application/content-stream`.
///
/// [rfc7231]: https://tools.ietf.org/html/rfc7231#section-3.1.1.5
pub fn guess_mime_type<P: AsRef<Path>>(path: P) -> Mime {
    guess_mime_type_opt(path).unwrap_or_else(octet_stream)
}

/// Guess the MIME type of `path` by its extension (as defined by `Path::extension()`).
///
/// If `path` has no extension, or its extension has no known MIME type mapping,
/// then `None` is returned.
///
/// ## Note
/// **Guess** is the operative word here, as there are no guarantees that the contents of the file
/// that `path` points to match the MIME type associated with the path's extension.
///
/// Take care when processing files with assumptions based on the return value of this function.
pub fn guess_mime_type_opt<P: AsRef<Path>>(path: P) -> Option<Mime> {
    mime_str_for_path_ext(path).map(|mime| mime.parse::<Mime>().unwrap())
}

/// Guess the MIME type string of `path` by its extension (as defined by `Path::extension()`).
///
/// If `path` has no extension, or its extension has no known MIME type mapping,
/// then `None` is returned.
///
/// ## Note
/// **Guess** is the operative word here, as there are no guarantees that the contents of the file
/// that `path` points to match the MIME type associated with the path's extension.
///
/// Take care when processing files with assumptions based on the return value of this function.
pub fn mime_str_for_path_ext<P: AsRef<Path>>(path: P) -> Option<&'static str> {
    let ext = path
        .as_ref()
        .extension()
        .and_then(OsStr::to_str)
        .unwrap_or("");

    get_mime_type_str(ext)
}

/// Get the MIME type associated with a file extension.
///
/// If there is no association for the extension, or `ext` is empty,
/// `application/octet-stream` is returned.
///
/// ## Note
/// In HTTP applications, it might be [preferable][rfc7231] to not send a `Content-Type`
/// header at all instead of defaulting to `application/content-stream`.
///
/// [rfc7231]: https://tools.ietf.org/html/rfc7231#section-3.1.1.5
pub fn get_mime_type(search_ext: &str) -> Mime {
    get_mime_type_opt(search_ext).unwrap_or_else(octet_stream)
}

/// Get the MIME type associated with a file extension.
///
/// If there is no association for the extension, or `ext` is empty,
/// `None` is returned.
pub fn get_mime_type_opt(search_ext: &str) -> Option<Mime> {
    get_mime_type_str(search_ext).map(|mime| mime.parse::<Mime>().unwrap())
}

/// Get the MIME type string associated with a file extension. Case-insensitive.
///
/// If `search_ext` is not already lowercase,
/// it will be converted to lowercase to facilitate the search.
///
/// Returns `None` if `search_ext` is empty or an associated extension was not found.
pub fn get_mime_type_str(search_ext: &str) -> Option<&'static str> {
    if search_ext.is_empty() {
        return None;
    }

    map_lookup(&MIME_TYPES, search_ext).cloned()
}

/// Get a list of known extensions for a given `Mime`.
///
/// Ignores parameters (only searches with `<main type>/<subtype>`). Case-insensitive (for extension types).
///
/// Returns `None` if the MIME type is unknown.
///
/// ### Wildcards
/// If the top-level of the MIME type is a wildcard (`*`), returns all extensions.
///
/// If the sub-level of the MIME type is a wildcard, returns all extensions for the top-level.
#[cfg(feature = "rev-mappings")]
pub fn get_mime_extensions(mime: &Mime) -> Option<&'static [&'static str]> {
    get_extensions(mime.type_().as_ref(), mime.subtype().as_ref())
}

/// Get a list of known extensions for a MIME type string.
///
/// Ignores parameters (only searches `<main type>/<subtype>`). Case-insensitive.
///
/// Returns `None` if the MIME type is unknown.
///
/// ### Wildcards
/// If the top-level of the MIME type is a wildcard (`*`), returns all extensions.
///
/// If the sub-level of the MIME type is a wildcard, returns all extensions for the top-level.
///
/// ### Panics
/// If `mime_str` is not a valid MIME type specifier (naive).
#[cfg(feature = "rev-mappings")]
pub fn get_mime_extensions_str(mut mime_str: &str) -> Option<&'static [&'static str]> {
    mime_str = mime_str.trim();

    if let Some(sep_idx) = mime_str.find(';') {
        mime_str = &mime_str[..sep_idx];
    }

    let (top, sub) = {
        let split_idx = mime_str.find('/').unwrap();
        (&mime_str[..split_idx], &mime_str[split_idx + 1..])
    };

    get_extensions(top, sub)
}

/// Get the extensions for a given top-level and sub-level of a MIME type
/// (`{toplevel}/{sublevel}`).
///
/// Returns `None` if `toplevel` or `sublevel` are unknown.
///
/// ### Wildcards
/// If the top-level of the MIME type is a wildcard (`*`), returns all extensions.
///
/// If the sub-level of the MIME type is a wildcard, returns all extensions for the top-level.
#[cfg(feature = "rev-mappings")]
pub fn get_extensions(toplevel: &str, sublevel: &str) -> Option<&'static [&'static str]> {
    if toplevel == "*" {
        return Some(EXTS);
    }

    let top = try_opt!(map_lookup(&REV_MAPPINGS, toplevel));

    if sublevel == "*" {
        return Some(&EXTS[top.start..top.end]);
    }

    let sub = try_opt!(map_lookup(&top.subs, sublevel));
    Some(&EXTS[sub.0..sub.1])
}

/// Get the MIME type for `application/octet-stream` (generic binary stream)
pub fn octet_stream() -> Mime {
    "application/octet-stream".parse().unwrap()
}

fn map_lookup<'map, V>(
    map: &'map phf::Map<UniCase<&'static str>, V>,
    key: &str,
) -> Option<&'map V> {
    // This transmute should be safe as `get` will not store the reference with
    // the expanded lifetime. This is due to `Borrow` being overly strict and
    // can't have an impl for `&'static str` to `Borrow<&'a str>`.
    //
    // See https://github.com/rust-lang/rust/issues/28853#issuecomment-158735548
    let key = unsafe { ::std::mem::transmute::<_, &'static str>(key) };
    map.get(&UniCase(key))
}

#[cfg(test)]
mod tests {
    use super::{get_mime_type, guess_mime_type, MIME_TYPES};
    use super::{get_mime_type_opt, guess_mime_type_opt};
    use mime::Mime;
    #[allow(deprecated, unused_imports)]
    use std::ascii::AsciiExt;
    use std::path::Path;

    #[test]
    fn test_mime_type_guessing() {
        assert_eq!(get_mime_type("gif").to_string(), "image/gif".to_string());
        assert_eq!(get_mime_type("TXT").to_string(), "text/plain".to_string());
        assert_eq!(
            get_mime_type("blahblah").to_string(),
            "application/octet-stream".to_string()
        );

        assert_eq!(
            guess_mime_type(Path::new("/path/to/file.gif")).to_string(),
            "image/gif".to_string()
        );
        assert_eq!(
            guess_mime_type("/path/to/file.gif").to_string(),
            "image/gif".to_string()
        );
    }

    #[test]
    fn test_mime_type_guessing_opt() {
        assert_eq!(
            get_mime_type_opt("gif").unwrap().to_string(),
            "image/gif".to_string()
        );
        assert_eq!(
            get_mime_type_opt("TXT").unwrap().to_string(),
            "text/plain".to_string()
        );
        assert_eq!(get_mime_type_opt("blahblah"), None);

        assert_eq!(
            guess_mime_type_opt("/path/to/file.gif")
                .unwrap()
                .to_string(),
            "image/gif".to_string()
        );
        assert_eq!(guess_mime_type_opt("/path/to/file"), None);
    }

    #[test]
    fn test_are_mime_types_parseable() {
        for (_, mime) in &MIME_TYPES {
            mime.parse::<Mime>().unwrap();
        }
    }

    // RFC: Is this test necessary anymore? --@cybergeek94, 2/1/2016
    #[test]
    fn test_are_extensions_ascii() {
        for (ext, _) in &MIME_TYPES {
            assert!(ext.is_ascii(), "Extension not ASCII: {:?}", ext);
        }
    }

    #[test]
    fn test_are_extensions_sorted() {
        use mime_types_src::MIME_TYPES;

        for (&(ext, _), &(n_ext, _)) in MIME_TYPES.iter().zip(MIME_TYPES.iter().skip(1)) {
            assert!(
                ext <= n_ext,
                "Extensions in src/mime_types should be sorted alphabetically
                in ascending order. Failed assert: {:?} <= {:?}",
                ext,
                n_ext
            );
        }
    }

}

#[cfg(feature = "bench")]
mod bench {
    extern crate test;

    use self::test::Bencher;

    use super::{get_mime_type_str, MIME_TYPES};

    /// WARNING: this may take a while!
    #[bench]
    fn bench_mime_str(b: &mut Bencher) {
        for (mime_ext, _) in &MIME_TYPES {
            b.iter(|| {
                get_mime_type_str(mime_ext).expect(mime_ext);
            });
        }
    }

    #[bench]
    fn bench_mime_str_uppercase(b: &mut Bencher) {
        let uppercased: Vec<_> = MIME_TYPES
            .into_iter()
            .map(|(s, _)| s.to_uppercase())
            .collect();

        for mime_ext in &uppercased {
            b.iter(|| {
                get_mime_type_str(mime_ext).expect(mime_ext);
            });
        }
    }
}
<commit_msg>WIP prototyping new `MimeGuess` API<commit_after>//! Guessing of MIME types by file extension.
//!
//! Uses a static list of file-extension : MIME type mappings.
//!
//! #### Note: MIME Types Returned Are Not Stable/Guaranteed
//! The media types returned for a given extension are not considered to be part of the crate's
//! stable API and are often updated in patch (#.#.x) releases to be as correct as possible.
//!
//! Additionally, only the extensions of paths/filenames are inspected in order to guess the MIME
//! type. The file that may or may not reside at that path may or may not be a valid file of the
//! returned MIME type.  Be wary of unsafe or un-validated assumptions about file structure or
//! length.
#![cfg_attr(feature = "bench", feature(test))]

extern crate mime;
extern crate phf;
extern crate unicase;

pub use mime::Mime;
use unicase::UniCase;

use std::ffi::OsStr;
use std::path::Path;
use std::{iter, slice};

include!(concat!(env!("OUT_DIR"), "/mime_types_generated.rs"));

#[cfg(feature = "rev-mappings")]
struct TopLevelExts {
    start: usize,
    end: usize,
    subs: phf::Map<UniCase<&'static str>, (usize, usize)>,
}

macro_rules! try_opt (
    ($expr:expr) => (
        match $expr {
            Some(val) => val,
            None => return None,
        }
    )
);

#[cfg(test)]
#[path = "mime_types.rs"]
mod mime_types_src;

/// A "guess" of the MIME/Media Type(s) of an extension or path as one or more
/// [`Mime`](::mime::Mime) instances.
///
/// ### Note: Ordering
/// A given file format may have one or more applicable Media Types; in this case
/// the first Media Type returned is whatever is declared in the latest IETF RFC for the
/// assumed file format or the one that explicitly supercedes all others.
/// Ordering of additional Media Types is arbitrary.
///
/// ### Note: Values Not Stable
/// The exact Media Types returned in any given guess are not considered to be stable and are often
/// updated in point-releases in order to reflect the most up-to-date information possible.
#[derive(Debug, PartialEq, Eq)]
pub struct MimeGuess(&'static [Mime]);

impl MimeGuess {
    /// Guess the MIME type of a file (real or otherwise) with the given extension.
    ///
    /// If `ext` is empty or has no (currently) known MIME type mapping, then an empty guess is
    /// returned.
    pub fn from_ext(ext: &str) -> MimeGuess {
        map_lookup(&MIME_TYPES, ext)
            .map_or(MimeGuess(&[]), MimeGuess)
    }

    /// Guess the MIME type of `path` by its extension (as defined by
    /// [`Path::extension()`](::std::path::Path::extension)). **No disk access is performed.**
    ///
    /// If `path` has no extension, the extension cannot be converted to `str`, or has
    /// no known MIME type mapping, then an empty guess is returned.
    ///
    /// ## Note
    /// **Guess** is the operative word here, as there are no guarantees that the contents of the
    /// file that `path` points to match the MIME type associated with the path's extension.
    ///
    /// Take care when processing files with assumptions based on the return value of this function.
    pub fn from_path<P: AsRef<Path>>(path: P) -> MimeGuess {
        path.as_ref().extension()
            .and_then(OsStr::to_str)
            .map_or(MimeGuess(&[]), Self::from_ext)
    }

    /// Get the guessed MIME(s) as a slice; may be empty.
    ///
    /// See [Note: Ordering](#note-ordering) above.
    pub fn as_slice(&self) -> &'static [Mime] {
        self.0
    }

    /// Get the first guessed `Mime`, if applicable.
    ///
    /// See [Note: Ordering](#note-ordering) above.
    ///
    /// If you require a `&'static Mime`, use `self.as_slice().get(0)` instead.
    pub fn first(&self) -> Option<Mime> {
        self.0.get(0).cloned()
    }

    /// Get the first guessed Media Type as a string, if applicable.
    ///
    /// See [Note: Ordering](#note-ordering) above.
    pub fn first_as_str(&self) -> Option<&str> {
        self.first().map(AsRef::as_ref)
    }

    /// `true` if the guess did not return any known mappings for the given path or extension.
    pub fn is_empty(&self) -> bool {
        self.0.is_empty()
    }

    /// Get the number of MIME types in the current guess.
    pub fn count(&self) -> usize {
         self.0.len()
    }

    /// Get the first guessed `Mime`, or if the guess is empty, return `application/octet-stream`
    /// instead.
    ///
    /// ### Note
    /// In HTTP applications, it might be [preferable][rfc7231] to not send a `Content-Type`
    /// header at all instead of defaulting to `application/content-stream`.
    ///
    /// [rfc7231]: https://tools.ietf.org/html/rfc7231#section-3.1.1.5
    pub fn or_octet_stream(&self) -> Mime {
        self.or(mime::APPLICATION_OCTET_STREAM)
    }

    /// If the guess is empty, return `text/plain` instead.
    pub fn or_text_plain(&self) -> Mime {
        self.or(mime::TEXT_PLAIN)
    }

    pub fn or(&self, default: Mime) -> Mime {

    }
}

impl IntoIterator for MimeGuess {
    type Item = Mime;
    type IntoIter = iter::Cloned<slice::Iter<'static, Mime>>;

    fn into_iter(self) -> Self::IntoIter {
        self.0.iter().cloned()
    }
}

impl<'a> IntoIterator for &'a MimeGuess {
    type Item = &'static Mime;
    type IntoIter = iter::Cloned<slice::Iter<'static, Mime>>;

    fn into_iter(self) -> Self::IntoIter {
        self.0.iter().cloned()
    }
}

/// Wrapper of [`MimeGuess::from_ext()`](MimeGuess::from_ext).
pub fn from_ext(ext: &str) -> MimeGuess {
    MimeGuess::from_ext(ext)
}

/// Wrapper of [`MimeGuess::from_path()`](MimeGuess::from_path).
pub fn from_path<P: AsRef<Path>>(path: Path) -> MimeGuess {
    MimeGuess::from_path(path)
}

/// Guess the MIME type of `path` by its extension (as defined by `Path::extension()`).
///
/// If `path` has no extension, or its extension has no known MIME type mapping,
/// then the MIME type is assumed to be `application/octet-stream`.
///
/// ## Note
/// **Guess** is the operative word here, as there are no guarantees that the contents of the file
/// that `path` points to match the MIME type associated with the path's extension.
///
/// Take care when processing files with assumptions based on the return value of this function.
///
/// In HTTP applications, it might be [preferable][rfc7231] to not send a `Content-Type`
/// header at all instead of defaulting to `application/content-stream`.
///
/// [rfc7231]: https://tools.ietf.org/html/rfc7231#section-3.1.1.5
#[deprecated(since = "2.1.0", note = "Use `from_path(path).or_octet_stream()` instead")]
pub fn guess_mime_type<P: AsRef<Path>>(path: P) -> Mime {
    from_path(path).or_octet_stream()
}

/// Guess the MIME type of `path` by its extension (as defined by `Path::extension()`).
///
/// If `path` has no extension, or its extension has no known MIME type mapping,
/// then `None` is returned.
///
#[deprecated(since = "2.1.0", note = "Use `from_path().first()` instead")]
pub fn guess_mime_type_opt<P: AsRef<Path>>(path: P) -> Option<Mime> {
    mime_str_for_path_ext(path).map(|mime| mime.parse::<Mime>().unwrap())
}

/// Guess the MIME type string of `path` by its extension (as defined by `Path::extension()`).
///
/// If `path` has no extension, or its extension has no known MIME type mapping,
/// then `None` is returned.
///
/// ## Note
/// **Guess** is the operative word here, as there are no guarantees that the contents of the file
/// that `path` points to match the MIME type associated with the path's extension.
///
/// Take care when processing files with assumptions based on the return value of this function.
#[deprecated(since = "2.1.0", note = "Use `from_path().first().map(AsRef::as_ref)` instead")]
pub fn mime_str_for_path_ext<P: AsRef<Path>>(path: P) -> Option<&'static str> {
    from_path(path).first().map(AsRef::as_ref)
}

/// Get the MIME type associated with a file extension.
///
/// If there is no association for the extension, or `ext` is empty,
/// `application/octet-stream` is returned.
///
/// ## Note
/// In HTTP applications, it might be [preferable][rfc7231] to not send a `Content-Type`
/// header at all instead of defaulting to `application/content-stream`.
///
/// [rfc7231]: https://tools.ietf.org/html/rfc7231#section-3.1.1.5
#[deprecated(since = "2.1.0", note = "use `from_ext(search_ext).or_octet_stream()` instead")]
pub fn get_mime_type(search_ext: &str) -> Mime {
    from_ext(search_ext).or_octet_stream()
}

/// Get the MIME type associated with a file extension.
///
/// If there is no association for the extension, or `ext` is empty,
/// `None` is returned.
#[deprecated(since = "2.1.0", note = "use `from_ext(search_ext).first()` instead")]
pub fn get_mime_type_opt(search_ext: &str) -> Option<Mime> {
    get_mime_type_str(search_ext).map(|mime| mime.parse::<Mime>().unwrap())
}

/// Get the MIME type string associated with a file extension. Case-insensitive.
///
/// If `search_ext` is not already lowercase,
/// it will be converted to lowercase to facilitate the search.
///
/// Returns `None` if `search_ext` is empty or an associated extension was not found.
#[deprecated(since = "2.1.0", note = "use `from_ext(search_ext).first_str()` instead")]
pub fn get_mime_type_str(search_ext: &str) -> Option<&'static str> {
    if search_ext.is_empty() {
        return None;
    }

    map_lookup(&MIME_TYPES, search_ext).cloned()
}

/// Get a list of known extensions for a given `Mime`.
///
/// Ignores parameters (only searches with `<main type>/<subtype>`). Case-insensitive (for extension types).
///
/// Returns `None` if the MIME type is unknown.
///
/// ### Wildcards
/// If the top-level of the MIME type is a wildcard (`*`), returns all extensions.
///
/// If the sub-level of the MIME type is a wildcard, returns all extensions for the top-level.
#[cfg(feature = "rev-mappings")]
pub fn get_mime_extensions(mime: &Mime) -> Option<&'static [&'static str]> {
    get_extensions(mime.type_().as_ref(), mime.subtype().as_ref())
}

/// Get a list of known extensions for a MIME type string.
///
/// Ignores parameters (only searches `<main type>/<subtype>`). Case-insensitive.
///
/// Returns `None` if the MIME type is unknown.
///
/// ### Wildcards
/// If the top-level of the MIME type is a wildcard (`*`), returns all extensions.
///
/// If the sub-level of the MIME type is a wildcard, returns all extensions for the top-level.
///
/// ### Panics
/// If `mime_str` is not a valid MIME type specifier (naive).
#[cfg(feature = "rev-mappings")]
pub fn get_mime_extensions_str(mut mime_str: &str) -> Option<&'static [&'static str]> {
    mime_str = mime_str.trim();

    if let Some(sep_idx) = mime_str.find(';') {
        mime_str = &mime_str[..sep_idx];
    }

    let (top, sub) = {
        let split_idx = mime_str.find('/').unwrap();
        (&mime_str[..split_idx], &mime_str[split_idx + 1..])
    };

    get_extensions(top, sub)
}

/// Get the extensions for a given top-level and sub-level of a MIME type
/// (`{toplevel}/{sublevel}`).
///
/// Returns `None` if `toplevel` or `sublevel` are unknown.
///
/// ### Wildcards
/// If the top-level of the MIME type is a wildcard (`*`), returns all extensions.
///
/// If the sub-level of the MIME type is a wildcard, returns all extensions for the top-level.
#[cfg(feature = "rev-mappings")]
pub fn get_extensions(toplevel: &str, sublevel: &str) -> Option<&'static [&'static str]> {
    if toplevel == "*" {
        return Some(EXTS);
    }

    let top = try_opt!(map_lookup(&REV_MAPPINGS, toplevel));

    if sublevel == "*" {
        return Some(&EXTS[top.start..top.end]);
    }

    let sub = try_opt!(map_lookup(&top.subs, sublevel));
    Some(&EXTS[sub.0..sub.1])
}

/// Get the MIME type for `application/octet-stream` (generic binary stream)
#[deprecated(since = "2.1.0", note = "use `mime::APPLICATION_OCTET_STREAM` instead")]
pub fn octet_stream() -> Mime {
    "application/octet-stream".parse().unwrap()
}

fn map_lookup<'map, V>(
    map: &'map phf::Map<UniCase<&'static str>, V>,
    key: &str,
) -> Option<&'map V> {
    // This transmute should be safe as `get` will not store the reference with
    // the expanded lifetime. This is due to `Borrow` being overly strict and
    // can't have an impl for `&'static str` to `Borrow<&'a str>`.
    //
    // See https://github.com/rust-lang/rust/issues/28853#issuecomment-158735548
    let key = unsafe { ::std::mem::transmute::<_, &'static str>(key) };
    map.get(&UniCase(key))
}

#[cfg(test)]
mod tests {
    use super::{get_mime_type, guess_mime_type, MIME_TYPES};
    use super::{get_mime_type_opt, guess_mime_type_opt};
    use mime::Mime;
    #[allow(deprecated, unused_imports)]
    use std::ascii::AsciiExt;
    use std::path::Path;

    #[test]
    fn test_mime_type_guessing() {
        assert_eq!(get_mime_type("gif").to_string(), "image/gif".to_string());
        assert_eq!(get_mime_type("TXT").to_string(), "text/plain".to_string());
        assert_eq!(
            get_mime_type("blahblah").to_string(),
            "application/octet-stream".to_string()
        );

        assert_eq!(
            guess_mime_type(Path::new("/path/to/file.gif")).to_string(),
            "image/gif".to_string()
        );
        assert_eq!(
            guess_mime_type("/path/to/file.gif").to_string(),
            "image/gif".to_string()
        );
    }

    #[test]
    fn test_mime_type_guessing_opt() {
        assert_eq!(
            get_mime_type_opt("gif").unwrap().to_string(),
            "image/gif".to_string()
        );
        assert_eq!(
            get_mime_type_opt("TXT").unwrap().to_string(),
            "text/plain".to_string()
        );
        assert_eq!(get_mime_type_opt("blahblah"), None);

        assert_eq!(
            guess_mime_type_opt("/path/to/file.gif")
                .unwrap()
                .to_string(),
            "image/gif".to_string()
        );
        assert_eq!(guess_mime_type_opt("/path/to/file"), None);
    }

    #[test]
    fn test_are_mime_types_parseable() {
        for (_, mime) in &MIME_TYPES {
            mime.parse::<Mime>().unwrap();
        }
    }

    // RFC: Is this test necessary anymore? --@cybergeek94, 2/1/2016
    #[test]
    fn test_are_extensions_ascii() {
        for (ext, _) in &MIME_TYPES {
            assert!(ext.is_ascii(), "Extension not ASCII: {:?}", ext);
        }
    }

    #[test]
    fn test_are_extensions_sorted() {
        use mime_types_src::MIME_TYPES;

        for (&(ext, _), &(n_ext, _)) in MIME_TYPES.iter().zip(MIME_TYPES.iter().skip(1)) {
            assert!(
                ext <= n_ext,
                "Extensions in src/mime_types should be sorted alphabetically
                in ascending order. Failed assert: {:?} <= {:?}",
                ext,
                n_ext
            );
        }
    }

}

#[cfg(feature = "bench")]
mod bench {
    extern crate test;

    use self::test::Bencher;

    use super::{get_mime_type_str, MIME_TYPES};

    /// WARNING: this may take a while!
    #[bench]
    fn bench_mime_str(b: &mut Bencher) {
        for (mime_ext, _) in &MIME_TYPES {
            b.iter(|| {
                get_mime_type_str(mime_ext).expect(mime_ext);
            });
        }
    }

    #[bench]
    fn bench_mime_str_uppercase(b: &mut Bencher) {
        let uppercased: Vec<_> = MIME_TYPES
            .into_iter()
            .map(|(s, _)| s.to_uppercase())
            .collect();

        for mime_ext in &uppercased {
            b.iter(|| {
                get_mime_type_str(mime_ext).expect(mime_ext);
            });
        }
    }
}
<|endoftext|>


<commit_before>#![deny(missing_docs)]
#![deny(missing_copy_implementations)]

//! A drag controller

extern crate event;
extern crate input;

use event::{
    FocusEvent,
    GenericEvent,
    MouseCursorEvent,
    PressEvent,
    ReleaseEvent,
};
use input::Button::Mouse;
use input::MouseButton;

/// Describes a drag
#[deriving(Copy)]
pub enum Drag {
    /// When the drag is interrupted by something,
    /// for example when the window is defocused.
    /// By returning true, the drag will continue when
    /// the window retrieves focus.
    Interrupt,
    /// Starts the drag.
    Start(f64, f64),
    /// Moves the drag.
    Move(f64, f64),
    /// Ends the drag.
    End(f64, f64),
}

/// Controls dragging.
#[deriving(Copy)]
pub struct DragController {
    /// Whether to drag or not.
    pub drag: bool,
    /// The current positon of dragging.
    pub pos: [f64, ..2],
}

impl DragController {
    /// Creates a new drag controller.
    pub fn new() -> DragController {
        DragController {
            drag: false,
            pos: [0.0, 0.0],
        }
    }

    /// Handles event.
    ///
    /// Calls closure when events for dragging happen.
    /// If the drag event callback returns `false`, it will cancel dragging.
    pub fn event<E: GenericEvent>(&mut self, e: &E, f: |Drag| -> bool) {
        e.mouse_cursor(|x, y| {
            self.pos = [x, y];
            if self.drag {
                self.drag = f(Drag::Move(x, y));
            }
        });
        e.press(|button| {
            match button {
                Mouse(MouseButton::Left) => {
                    if !self.drag {
                        self.drag = f(Drag::Start(self.pos[0], self.pos[1]));
                    }
                }
                _ => {}
            }
        });

        // Rest of the event are only handled when dragging.
        if !self.drag { return; }

        e.release(|button| {
            match button {
                Mouse(MouseButton::Left) => {
                    if self.drag {
                        f(Drag::End(self.pos[0], self.pos[1]));
                    }
                    self.drag = false;
                }
                _ => {}
            }
        });
        e.focus(|focused| {
            if focused == false {
                self.drag = f(Drag::Interrupt);
            }
        });
    }
}

<commit_msg>Upgrade to latest Rust<commit_after>#![deny(missing_docs)]
#![deny(missing_copy_implementations)]

//! A drag controller

extern crate event;
extern crate input;

use event::{
    FocusEvent,
    GenericEvent,
    MouseCursorEvent,
    PressEvent,
    ReleaseEvent,
};
use input::Button::Mouse;
use input::MouseButton;

/// Describes a drag
#[derive(Copy)]
pub enum Drag {
    /// When the drag is interrupted by something,
    /// for example when the window is defocused.
    /// By returning true, the drag will continue when
    /// the window retrieves focus.
    Interrupt,
    /// Starts the drag.
    Start(f64, f64),
    /// Moves the drag.
    Move(f64, f64),
    /// Ends the drag.
    End(f64, f64),
}

/// Controls dragging.
#[derive(Copy)]
pub struct DragController {
    /// Whether to drag or not.
    pub drag: bool,
    /// The current positon of dragging.
    pub pos: [f64; 2],
}

impl DragController {
    /// Creates a new drag controller.
    pub fn new() -> DragController {
        DragController {
            drag: false,
            pos: [0.0, 0.0],
        }
    }

    /// Handles event.
    ///
    /// Calls closure when events for dragging happen.
    /// If the drag event callback returns `false`, it will cancel dragging.
    pub fn event<E: GenericEvent>(&mut self, e: &E, f: |Drag| -> bool) {
        e.mouse_cursor(|x, y| {
            self.pos = [x, y];
            if self.drag {
                self.drag = f(Drag::Move(x, y));
            }
        });
        e.press(|button| {
            match button {
                Mouse(MouseButton::Left) => {
                    if !self.drag {
                        self.drag = f(Drag::Start(self.pos[0], self.pos[1]));
                    }
                }
                _ => {}
            }
        });

        // Rest of the event are only handled when dragging.
        if !self.drag { return; }

        e.release(|button| {
            match button {
                Mouse(MouseButton::Left) => {
                    if self.drag {
                        f(Drag::End(self.pos[0], self.pos[1]));
                    }
                    self.drag = false;
                }
                _ => {}
            }
        });
        e.focus(|focused| {
            if focused == false {
                self.drag = f(Drag::Interrupt);
            }
        });
    }
}

<|endoftext|>


<commit_before>//! ## Initialization
//! Libgcrypt requires initialization before first use. The functions `init` and `init_fips` can be
//! used to initialize the library. The closure passed to these functions is used to configure the
//! library. More information on configuration options can be found in the libgcrypt
//! [documentation](https://www.gnupg.org/documentation/manuals/gcrypt/Initializing-the-library.html#Initializing-the-library).
//!
//! An example:
//!
//! ```rust
//! let token = gcrypt::init(|mut x| {
//!     x.disable_secmem();
//! });
//! ```
//!
//! Calling any function in the wrapper that requires initialization before `init` or `init_fips`
//! are called will cause the wrapper to attempt to initialize the library with a default
//! configuration.
#![cfg_attr(any(nightly, feature = "nightly"), feature(nonzero))]
#[macro_use]
extern crate cfg_if;
extern crate libc;
#[macro_use]
extern crate bitflags;
#[macro_use]
extern crate lazy_static;
#[macro_use]
pub extern crate gpg_error as error;
extern crate libgcrypt_sys as ffi;

use std::ffi::{CStr, CString};
use std::ptr;
use std::sync::Mutex;
use std::sync::atomic::{ATOMIC_BOOL_INIT, AtomicBool, Ordering};

use libc::c_int;

pub use error::{Error, Result};
pub use buffer::Buffer;

#[macro_use]
mod utils;
mod buffer;
pub mod rand;
pub mod mpi;
pub mod sexp;
pub mod pkey;
pub mod cipher;
pub mod digest;
pub mod mac;
pub mod kdf;

cfg_if! {
    if #[cfg(feature = "v1_7_0")] {
        const TARGET_VERSION: &'static str = "1.7.0\0";
    } else if #[cfg(feature = "v1_6_0")] {
        const TARGET_VERSION: &'static str = "1.6.0\0";
    } else {
        const TARGET_VERSION: &'static str = "1.5.0\0";
    }
}

static INITIALIZED: AtomicBool = ATOMIC_BOOL_INIT;
lazy_static! {
    static ref CONTROL_LOCK: Mutex<()> = Mutex::new(());
}

pub struct Initializer(());

impl Initializer {
    #[inline]
    pub fn check_version<S: Into<String>>(&mut self, version: S) -> bool {
        let version = match CString::new(version.into()) {
            Ok(v) => v,
            Err(..) => return false,
        };
        unsafe { !ffi::gcry_check_version(version.as_ptr()).is_null() }
    }

    #[inline]
    pub fn enable_quick_random(&mut self) -> &mut Self {
        unsafe {
            ffi::gcry_control(ffi::GCRYCTL_ENABLE_QUICK_RANDOM, 0);
        }
        self
    }

    #[inline]
    pub fn enable_secure_rndpool(&mut self) -> &mut Self {
        unsafe {
            ffi::gcry_control(ffi::GCRYCTL_USE_SECURE_RNDPOOL, 0);
        }
        self
    }

    #[inline]
    pub fn disable_secmem(&mut self) -> &mut Self {
        unsafe {
            ffi::gcry_control(ffi::GCRYCTL_DISABLE_SECMEM, 0);
        }
        self
    }

    #[inline]
    pub fn enable_secmem(&mut self, amt: usize) -> Result<&mut Self> {
        unsafe {
            return_err!(ffi::gcry_control(ffi::GCRYCTL_INIT_SECMEM, amt as c_int));
        }
        Ok(self)
    }
}

#[derive(Debug, Copy, Clone)]
pub struct Token(());

impl Token {
    #[inline]
    pub fn is_fips_mode_active(&self) -> bool {
        unsafe { ffi::gcry_fips_mode_active() }
    }

    #[inline]
    pub fn check_version<S: Into<String>>(&self, version: S) -> bool {
        let version = match CString::new(version.into()) {
            Ok(v) => v,
            Err(..) => return false,
        };
        unsafe { !ffi::gcry_check_version(version.as_ptr()).is_null() }
    }

    #[inline]
    pub fn version(&self) -> &'static str {
        unsafe {
            CStr::from_ptr(ffi::gcry_check_version(ptr::null()))
                .to_str()
                .expect("Version is invalid")
        }
    }

    #[inline]
    pub fn run_self_tests(&self) -> bool {
        unsafe { ffi::gcry_control(ffi::GCRYCTL_SELFTEST, 0) == 0 }
    }

    #[inline]
    pub fn destroy_secmem(&self) {
        unsafe {
            ffi::gcry_control(ffi::GCRYCTL_TERM_SECMEM, 0);
        }
    }
}

pub fn enable_memory_guard() -> bool {
    let _lock = CONTROL_LOCK.lock().unwrap();
    let initialized = unsafe { ffi::gcry_control(ffi::GCRYCTL_ANY_INITIALIZATION_P, 0) != 0 };
    if !initialized {
        unsafe {
            ffi::gcry_control(ffi::GCRYCTL_ENABLE_M_GUARD, 0);
        }
    }
    !initialized
}

#[inline]
fn is_init_finished() -> bool {
    unsafe { ffi::gcry_control(ffi::GCRYCTL_INITIALIZATION_FINISHED_P, 0) != 0 }
}

#[inline]
pub fn is_initialized() -> bool {
    if INITIALIZED.load(Ordering::Acquire) {
        return true;
    }

    let _lock = CONTROL_LOCK.lock().unwrap();
    is_init_finished()
}

pub fn init<F: FnOnce(&mut Initializer)>(f: F) -> Token {
    if INITIALIZED.load(Ordering::Acquire) {
        return Token(());
    }

    let _lock = CONTROL_LOCK.lock().unwrap();
    if !is_init_finished() {
        unsafe {
            if cfg!(unix) {
                ffi::gcry_control(ffi::GCRYCTL_SET_THREAD_CBS,
                                  ffi::gcry_threads_pthread_shim());
            }
            assert!(!ffi::gcry_check_version(TARGET_VERSION.as_ptr() as *const _).is_null());
        }
        f(&mut Initializer(()));
        unsafe {
            ffi::gcry_control(ffi::GCRYCTL_INITIALIZATION_FINISHED, 0);
        }
    }
    INITIALIZED.store(true, Ordering::Release);
    Token(())
}

pub fn init_fips_mode<F: FnOnce(&mut Initializer)>(f: F) -> Token {
    if INITIALIZED.load(Ordering::Acquire) {
        return Token(());
    }

    let _lock = CONTROL_LOCK.lock().unwrap();
    if !is_init_finished() {
        unsafe {
            if cfg!(unix) {
                ffi::gcry_control(ffi::GCRYCTL_SET_THREAD_CBS,
                                  ffi::gcry_threads_pthread_shim());
            }
            ffi::gcry_control(ffi::GCRYCTL_FORCE_FIPS_MODE, 0);
            assert!(!ffi::gcry_check_version(TARGET_VERSION.as_ptr() as *const _).is_null());
        }
        f(&mut Initializer(()));
        unsafe {
            ffi::gcry_control(ffi::GCRYCTL_INITIALIZATION_FINISHED, 0);
        }
    }
    INITIALIZED.store(true, Ordering::Release);
    Token(())
}

#[inline]
pub fn get_token() -> Token {
    init(|mut x| { x.disable_secmem(); })
}

type NonZero<T> = utils::NonZero<T>;
<commit_msg>Fix nightly build<commit_after>//! ## Initialization
//! Libgcrypt requires initialization before first use. The functions `init` and `init_fips` can be
//! used to initialize the library. The closure passed to these functions is used to configure the
//! library. More information on configuration options can be found in the libgcrypt
//! [documentation](https://www.gnupg.org/documentation/manuals/gcrypt/Initializing-the-library.html#Initializing-the-library).
//!
//! An example:
//!
//! ```rust
//! let token = gcrypt::init(|mut x| {
//!     x.disable_secmem();
//! });
//! ```
//!
//! Calling any function in the wrapper that requires initialization before `init` or `init_fips`
//! are called will cause the wrapper to attempt to initialize the library with a default
//! configuration.
#![cfg_attr(any(nightly, feature = "nightly"), feature(nonzero))]
extern crate core;
#[macro_use]
extern crate cfg_if;
extern crate libc;
#[macro_use]
extern crate bitflags;
#[macro_use]
extern crate lazy_static;
#[macro_use]
pub extern crate gpg_error as error;
extern crate libgcrypt_sys as ffi;

use std::ffi::{CStr, CString};
use std::ptr;
use std::sync::Mutex;
use std::sync::atomic::{ATOMIC_BOOL_INIT, AtomicBool, Ordering};

use libc::c_int;

pub use error::{Error, Result};
pub use buffer::Buffer;

#[macro_use]
mod utils;
mod buffer;
pub mod rand;
pub mod mpi;
pub mod sexp;
pub mod pkey;
pub mod cipher;
pub mod digest;
pub mod mac;
pub mod kdf;

cfg_if! {
    if #[cfg(feature = "v1_7_0")] {
        const TARGET_VERSION: &'static str = "1.7.0\0";
    } else if #[cfg(feature = "v1_6_0")] {
        const TARGET_VERSION: &'static str = "1.6.0\0";
    } else {
        const TARGET_VERSION: &'static str = "1.5.0\0";
    }
}

static INITIALIZED: AtomicBool = ATOMIC_BOOL_INIT;
lazy_static! {
    static ref CONTROL_LOCK: Mutex<()> = Mutex::new(());
}

pub struct Initializer(());

impl Initializer {
    #[inline]
    pub fn check_version<S: Into<String>>(&mut self, version: S) -> bool {
        let version = match CString::new(version.into()) {
            Ok(v) => v,
            Err(..) => return false,
        };
        unsafe { !ffi::gcry_check_version(version.as_ptr()).is_null() }
    }

    #[inline]
    pub fn enable_quick_random(&mut self) -> &mut Self {
        unsafe {
            ffi::gcry_control(ffi::GCRYCTL_ENABLE_QUICK_RANDOM, 0);
        }
        self
    }

    #[inline]
    pub fn enable_secure_rndpool(&mut self) -> &mut Self {
        unsafe {
            ffi::gcry_control(ffi::GCRYCTL_USE_SECURE_RNDPOOL, 0);
        }
        self
    }

    #[inline]
    pub fn disable_secmem(&mut self) -> &mut Self {
        unsafe {
            ffi::gcry_control(ffi::GCRYCTL_DISABLE_SECMEM, 0);
        }
        self
    }

    #[inline]
    pub fn enable_secmem(&mut self, amt: usize) -> Result<&mut Self> {
        unsafe {
            return_err!(ffi::gcry_control(ffi::GCRYCTL_INIT_SECMEM, amt as c_int));
        }
        Ok(self)
    }
}

#[derive(Debug, Copy, Clone)]
pub struct Token(());

impl Token {
    #[inline]
    pub fn is_fips_mode_active(&self) -> bool {
        unsafe { ffi::gcry_fips_mode_active() }
    }

    #[inline]
    pub fn check_version<S: Into<String>>(&self, version: S) -> bool {
        let version = match CString::new(version.into()) {
            Ok(v) => v,
            Err(..) => return false,
        };
        unsafe { !ffi::gcry_check_version(version.as_ptr()).is_null() }
    }

    #[inline]
    pub fn version(&self) -> &'static str {
        unsafe {
            CStr::from_ptr(ffi::gcry_check_version(ptr::null()))
                .to_str()
                .expect("Version is invalid")
        }
    }

    #[inline]
    pub fn run_self_tests(&self) -> bool {
        unsafe { ffi::gcry_control(ffi::GCRYCTL_SELFTEST, 0) == 0 }
    }

    #[inline]
    pub fn destroy_secmem(&self) {
        unsafe {
            ffi::gcry_control(ffi::GCRYCTL_TERM_SECMEM, 0);
        }
    }
}

pub fn enable_memory_guard() -> bool {
    let _lock = CONTROL_LOCK.lock().unwrap();
    let initialized = unsafe { ffi::gcry_control(ffi::GCRYCTL_ANY_INITIALIZATION_P, 0) != 0 };
    if !initialized {
        unsafe {
            ffi::gcry_control(ffi::GCRYCTL_ENABLE_M_GUARD, 0);
        }
    }
    !initialized
}

#[inline]
fn is_init_finished() -> bool {
    unsafe { ffi::gcry_control(ffi::GCRYCTL_INITIALIZATION_FINISHED_P, 0) != 0 }
}

#[inline]
pub fn is_initialized() -> bool {
    if INITIALIZED.load(Ordering::Acquire) {
        return true;
    }

    let _lock = CONTROL_LOCK.lock().unwrap();
    is_init_finished()
}

pub fn init<F: FnOnce(&mut Initializer)>(f: F) -> Token {
    if INITIALIZED.load(Ordering::Acquire) {
        return Token(());
    }

    let _lock = CONTROL_LOCK.lock().unwrap();
    if !is_init_finished() {
        unsafe {
            if cfg!(unix) {
                ffi::gcry_control(ffi::GCRYCTL_SET_THREAD_CBS,
                                  ffi::gcry_threads_pthread_shim());
            }
            assert!(!ffi::gcry_check_version(TARGET_VERSION.as_ptr() as *const _).is_null());
        }
        f(&mut Initializer(()));
        unsafe {
            ffi::gcry_control(ffi::GCRYCTL_INITIALIZATION_FINISHED, 0);
        }
    }
    INITIALIZED.store(true, Ordering::Release);
    Token(())
}

pub fn init_fips_mode<F: FnOnce(&mut Initializer)>(f: F) -> Token {
    if INITIALIZED.load(Ordering::Acquire) {
        return Token(());
    }

    let _lock = CONTROL_LOCK.lock().unwrap();
    if !is_init_finished() {
        unsafe {
            if cfg!(unix) {
                ffi::gcry_control(ffi::GCRYCTL_SET_THREAD_CBS,
                                  ffi::gcry_threads_pthread_shim());
            }
            ffi::gcry_control(ffi::GCRYCTL_FORCE_FIPS_MODE, 0);
            assert!(!ffi::gcry_check_version(TARGET_VERSION.as_ptr() as *const _).is_null());
        }
        f(&mut Initializer(()));
        unsafe {
            ffi::gcry_control(ffi::GCRYCTL_INITIALIZATION_FINISHED, 0);
        }
    }
    INITIALIZED.store(true, Ordering::Release);
    Token(())
}

#[inline]
pub fn get_token() -> Token {
    init(|mut x| { x.disable_secmem(); })
}

type NonZero<T> = utils::NonZero<T>;
<|endoftext|>


<commit_before>#[macro_use]
extern crate ndarray;

use ndarray::{
    OwnedArray,
    Ix,
};

pub type V = OwnedArray<f64, Ix>;

pub struct OnlineStats {
    sum_of_weights : f64,
    mean : V,
    m2 : V,
    n : u64
}

impl OnlineStats {
    pub fn new(width: usize) -> OnlineStats {
        OnlineStats {
            sum_of_weights: 0.,
            mean: V::zeros(width),
            m2:   V::zeros(width),
            n: 0 }
    }

    pub fn next_value(&mut self, data : &V, weight : f64) {
        let temp = weight + self.sum_of_weights;
        // nice
        let delta = data - &self.mean;
        let r = &delta * (weight / temp); // Interoperation with scalars works nicely.

        self.mean.iadd(&r); // While I don't like this style, is efficient and will be += when rust supports it so fine.

        self.m2.iadd(&(self.sum_of_weights * (r * &delta)));
        self.sum_of_weights = temp;
        self.n += 1;
    }

    pub fn mean_and_variance(&self) -> (V, V) {
        //let var = if self.n > 1 {self.M2 / self.sumOfWeights * self.n / (self.n - 1) } else {Float::inf};
        let var = if self.n > 1 {
            &self.m2 * ((self.n as f64) / (self.sum_of_weights * ((self.n - 1) as f64)))
        } else {
            V::from_elem(self.m2.dim(), 1.)
            // ones(self.m2.num_rows(), self.m2.num_cols()).map(|v| f64::INFINITY)
        };
        (self.mean.clone(), var)
    }
}

use ndarray::arr1;

#[test]
fn weighted_stats17(){
    let const_vec = arr1(&[1., 3., 4.]);
    let const_vec2 = arr1(&[1., 1.5, 1.]);
    let const_vec3 = arr1(&[0., 2., 4.]);
    let mut s = OnlineStats::new(3);
    s.next_value(&const_vec, 1.);
    let (m1, _) = s.mean_and_variance();
    assert_eq!(m1, const_vec);
    s.next_value(&const_vec2, 2.);
    let (m2, _) = s.mean_and_variance();
    assert_eq!(m2, arr1(&[1., 2., 2.]));
    s.next_value(&const_vec3, 3.);
    let (m3, _) = s.mean_and_variance();
    assert_eq!(m3, arr1(&[0.5, 2., 3.]));
}
<commit_msg>Work around lifetime issue problem<commit_after>#[macro_use]
extern crate ndarray;

use ndarray::{
    OwnedArray,
    Ix,
};

pub type V = OwnedArray<f64, Ix>;

pub struct OnlineStats {
    sum_of_weights : f64,
    mean : V,
    m2 : V,
    n : u64
}

impl OnlineStats {
    pub fn new(width: usize) -> OnlineStats {
        OnlineStats {
            sum_of_weights: 0.,
            mean: V::zeros(width),
            m2:   V::zeros(width),
            n: 0 }
    }

    pub fn next_value(&mut self, data : &V, weight : f64) {
        let temp = weight + self.sum_of_weights;
        // nice
        let delta = &*data - &self.mean;
        let r = &delta * (weight / temp); // Interoperation with scalars works nicely.

        self.mean.iadd(&r); // While I don't like this style, is efficient and will be += when rust supports it so fine.

        self.m2.iadd(&(self.sum_of_weights * (r * &delta)));
        self.sum_of_weights = temp;
        self.n += 1;
    }

    pub fn mean_and_variance(&self) -> (V, V) {
        //let var = if self.n > 1 {self.M2 / self.sumOfWeights * self.n / (self.n - 1) } else {Float::inf};
        let var = if self.n > 1 {
            &self.m2 * ((self.n as f64) / (self.sum_of_weights * ((self.n - 1) as f64)))
        } else {
            V::from_elem(self.m2.dim(), 1.)
            // ones(self.m2.num_rows(), self.m2.num_cols()).map(|v| f64::INFINITY)
        };
        (self.mean.clone(), var)
    }
}

use ndarray::arr1;

#[test]
fn weighted_stats17(){
    let const_vec = arr1(&[1., 3., 4.]).to_owned();
    let const_vec2 = arr1(&[1., 1.5, 1.]).to_owned();
    let const_vec3 = arr1(&[0., 2., 4.]).to_owned();
    let mut s = OnlineStats::new(3);
    s.next_value(&const_vec, 1.);
    let (m1, _) = s.mean_and_variance();
    assert_eq!(m1, const_vec);
    s.next_value(&const_vec2, 2.);
    let (m2, _) = s.mean_and_variance();
    assert_eq!(m2, arr1(&[1., 2., 2.]));
    s.next_value(&const_vec3, 3.);
    let (m3, _) = s.mean_and_variance();
    assert_eq!(m3, arr1(&[0.5, 2., 3.]));
}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#![crate_name = "cssparser"]
#![crate_type = "rlib"]

#![cfg_attr(feature = "bench", feature(test))]
#![deny(missing_docs)]

/*!

Implementation of [CSS Syntax Module Level 3](https://drafts.csswg.org/css-syntax/) for Rust.

# Input

Everything is based on `Parser` objects, which borrow a `&str` input.
If you have bytes (from a file, the network, or something)
and want to support character encodings other than UTF-8,
see the `stylesheet_encoding` function,
which can be used together with rust-encoding or encoding-rs.

# Conventions for parsing functions

* Take (at least) a `input: &mut cssparser::Parser` parameter
* Return `Result<_, ()>`
* When returning `Ok(_)`,
  the function must have consumed exactly the amount of input that represents the parsed value.
* When returning `Err(())`, any amount of input may have been consumed.

As a consequence, when calling another parsing function, either:

* Any `Err(())` return value must be propagated.
  This happens by definition for tail calls,
  and can otherwise be done with the `try!` macro.
* Or the call must be wrapped in a `Parser::try` call.
  `try` takes a closure that takes a `Parser` and returns a `Result`,
  calls it once,
  and returns itself that same result.
  If the result is `Err`,
  it restores the position inside the input to the one saved before calling the closure.

Examples:

```{rust,ignore}
// 'none' | <image>
fn parse_background_image(context: &ParserContext, input: &mut Parser)
                                    -> Result<Option<Image>, ()> {
    if input.try(|input| input.expect_ident_matching("none")).is_ok() {
        Ok(None)
    } else {
        Image::parse(context, input).map(Some)  // tail call
    }
}
```

```{rust,ignore}
// [ <length> | <percentage> ] [ <length> | <percentage> ]?
fn parse_border_spacing(_context: &ParserContext, input: &mut Parser)
                          -> Result<(LengthOrPercentage, LengthOrPercentage), ()> {
    let first = try!(LengthOrPercentage::parse);
    let second = input.try(LengthOrPercentage::parse).unwrap_or(first);
    (first, second)
}
```

*/

#![recursion_limit="200"]  // For color::parse_color_keyword

extern crate dtoa_short;
extern crate itoa;
#[macro_use] extern crate cssparser_macros;
#[macro_use] extern crate matches;
#[macro_use] extern crate procedural_masquerade;
#[doc(hidden)] pub extern crate phf as _internal__phf;
#[cfg(test)] extern crate encoding_rs;
#[cfg(test)] extern crate difference;
#[cfg(test)] extern crate rustc_serialize;
#[cfg(feature = "serde")] extern crate serde;
#[cfg(feature = "heapsize")] #[macro_use] extern crate heapsize;
extern crate smallvec;

pub use cssparser_macros::*;

pub use tokenizer::{Token, SourcePosition, SourceLocation};
pub use rules_and_declarations::{parse_important};
pub use rules_and_declarations::{DeclarationParser, DeclarationListParser, parse_one_declaration};
pub use rules_and_declarations::{RuleListParser, parse_one_rule};
pub use rules_and_declarations::{AtRuleType, QualifiedRuleParser, AtRuleParser};
pub use from_bytes::{stylesheet_encoding, EncodingSupport};
pub use color::{RGBA, Color, parse_color_keyword, AngleOrNumber, NumberOrPercentage, ColorComponentParser};
pub use nth::parse_nth;
pub use serializer::{ToCss, CssStringWriter, serialize_identifier, serialize_string, TokenSerializationType};
pub use parser::{Parser, Delimiter, Delimiters, ParserState, ParserInput};
pub use parser::{ParseError, ParseErrorKind, BasicParseError, BasicParseErrorKind};
pub use unicode_range::UnicodeRange;
pub use cow_rc_str::CowRcStr;

// For macros
#[doc(hidden)] pub use macros::_internal__to_lowercase;

// For macros when used in this crate. Unsure how $crate works with procedural-masquerade.
mod cssparser { pub use _internal__phf; }

#[macro_use]
mod macros;

mod rules_and_declarations;

#[cfg(feature = "dummy_match_byte")]
mod tokenizer;

#[cfg(not(feature = "dummy_match_byte"))]
mod tokenizer {
    include!(concat!(env!("OUT_DIR"), "/tokenizer.rs"));
}
mod parser;
mod from_bytes;
mod color;
mod nth;
mod serializer;
mod unicode_range;
mod cow_rc_str;

#[cfg(test)] mod tests;
#[cfg(test)] mod size_of_tests;
<commit_msg>Actually expose serialize_name.<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#![crate_name = "cssparser"]
#![crate_type = "rlib"]

#![cfg_attr(feature = "bench", feature(test))]
#![deny(missing_docs)]

/*!

Implementation of [CSS Syntax Module Level 3](https://drafts.csswg.org/css-syntax/) for Rust.

# Input

Everything is based on `Parser` objects, which borrow a `&str` input.
If you have bytes (from a file, the network, or something)
and want to support character encodings other than UTF-8,
see the `stylesheet_encoding` function,
which can be used together with rust-encoding or encoding-rs.

# Conventions for parsing functions

* Take (at least) a `input: &mut cssparser::Parser` parameter
* Return `Result<_, ()>`
* When returning `Ok(_)`,
  the function must have consumed exactly the amount of input that represents the parsed value.
* When returning `Err(())`, any amount of input may have been consumed.

As a consequence, when calling another parsing function, either:

* Any `Err(())` return value must be propagated.
  This happens by definition for tail calls,
  and can otherwise be done with the `try!` macro.
* Or the call must be wrapped in a `Parser::try` call.
  `try` takes a closure that takes a `Parser` and returns a `Result`,
  calls it once,
  and returns itself that same result.
  If the result is `Err`,
  it restores the position inside the input to the one saved before calling the closure.

Examples:

```{rust,ignore}
// 'none' | <image>
fn parse_background_image(context: &ParserContext, input: &mut Parser)
                                    -> Result<Option<Image>, ()> {
    if input.try(|input| input.expect_ident_matching("none")).is_ok() {
        Ok(None)
    } else {
        Image::parse(context, input).map(Some)  // tail call
    }
}
```

```{rust,ignore}
// [ <length> | <percentage> ] [ <length> | <percentage> ]?
fn parse_border_spacing(_context: &ParserContext, input: &mut Parser)
                          -> Result<(LengthOrPercentage, LengthOrPercentage), ()> {
    let first = try!(LengthOrPercentage::parse);
    let second = input.try(LengthOrPercentage::parse).unwrap_or(first);
    (first, second)
}
```

*/

#![recursion_limit="200"]  // For color::parse_color_keyword

extern crate dtoa_short;
extern crate itoa;
#[macro_use] extern crate cssparser_macros;
#[macro_use] extern crate matches;
#[macro_use] extern crate procedural_masquerade;
#[doc(hidden)] pub extern crate phf as _internal__phf;
#[cfg(test)] extern crate encoding_rs;
#[cfg(test)] extern crate difference;
#[cfg(test)] extern crate rustc_serialize;
#[cfg(feature = "serde")] extern crate serde;
#[cfg(feature = "heapsize")] #[macro_use] extern crate heapsize;
extern crate smallvec;

pub use cssparser_macros::*;

pub use tokenizer::{Token, SourcePosition, SourceLocation};
pub use rules_and_declarations::{parse_important};
pub use rules_and_declarations::{DeclarationParser, DeclarationListParser, parse_one_declaration};
pub use rules_and_declarations::{RuleListParser, parse_one_rule};
pub use rules_and_declarations::{AtRuleType, QualifiedRuleParser, AtRuleParser};
pub use from_bytes::{stylesheet_encoding, EncodingSupport};
pub use color::{RGBA, Color, parse_color_keyword, AngleOrNumber, NumberOrPercentage, ColorComponentParser};
pub use nth::parse_nth;
pub use serializer::{ToCss, CssStringWriter, serialize_identifier, serialize_name, serialize_string, TokenSerializationType};
pub use parser::{Parser, Delimiter, Delimiters, ParserState, ParserInput};
pub use parser::{ParseError, ParseErrorKind, BasicParseError, BasicParseErrorKind};
pub use unicode_range::UnicodeRange;
pub use cow_rc_str::CowRcStr;

// For macros
#[doc(hidden)] pub use macros::_internal__to_lowercase;

// For macros when used in this crate. Unsure how $crate works with procedural-masquerade.
mod cssparser { pub use _internal__phf; }

#[macro_use]
mod macros;

mod rules_and_declarations;

#[cfg(feature = "dummy_match_byte")]
mod tokenizer;

#[cfg(not(feature = "dummy_match_byte"))]
mod tokenizer {
    include!(concat!(env!("OUT_DIR"), "/tokenizer.rs"));
}
mod parser;
mod from_bytes;
mod color;
mod nth;
mod serializer;
mod unicode_range;
mod cow_rc_str;

#[cfg(test)] mod tests;
#[cfg(test)] mod size_of_tests;
<|endoftext|>


<commit_before>//! This library provides wrapper types that permit sending non `Send` types to
//! other threads and use runtime checks to ensure safety.
//!
//! It provides two types: `Fragile<T>` and `Sticky<T>` which are similar in nature
//! but have different behaviors with regards to how destructors are executed.
//!
//! Both types wrap a value and provide a `Send` bound.  Neither of the types permit
//! access to the enclosed value unless the thread that wrapped the value is attempting
//! to access it.  The difference between the two types starts playing a role once
//! destructors are involved.
//!
//! A `Fragile<T>` will actually send the `T` from thread to thread but will only
//! permit the original thread to invoke the destructor.  If the value gets dropped
//! in a different thread, the destructor will panic.
//!
//! A `Sticky<T>` on the other hand does not actually send the `T` around but keeps
//! it stored in the original thread's thread local storage.  If it gets dropped
//! in the originating thread it gets cleaned up immediately, otherwise it leaks
//! until the thread shuts down naturally.
//!
//! # Example usage
//!
//! ```
//! use std::thread;
//! use fragile::Fragile;
//!
//! // creating and using a fragile object in the same thread works
//! let val = Fragile::new(true);
//! assert_eq!(*val.get(), true);
//! assert!(val.try_get().is_ok());
//!
//! // once send to another thread it stops working
//! thread::spawn(move || {
//!     assert!(val.try_get().is_err());
//! }).join()
//!     .unwrap();
//! ```
//!
//! # Why?
//!
//! Most of the time trying to use this crate is going to indicate some code smell.  But
//! there are situations where this is useful.  For instance you might have a bunch of
//! non `Send` types but want to work with a `Send` error type.  In that case the non
//! sendable extra information can be contained within the error and in cases where the
//! error did not cross a thread boundary yet extra information can be obtained.
mod errors;
mod fragile;
mod semisticky;
mod sticky;

pub use errors::InvalidThreadAccess;
pub use fragile::Fragile;
pub use semisticky::SemiSticky;
pub use sticky::Sticky;
<commit_msg>Added docs for semisticky<commit_after>//! This library provides wrapper types that permit sending non `Send` types to
//! other threads and use runtime checks to ensure safety.
//!
//! It provides three types: `Fragile<T>` and `Sticky<T>` which are similar in nature
//! but have different behaviors with regards to how destructors are executed and
//! the extra `SemiSticky<T>` type which uses `Sticky<T>` if the value has a
//! destructor and `Fragile<T>` if it does not.
//!
//! Both types wrap a value and provide a `Send` bound.  Neither of the types permit
//! access to the enclosed value unless the thread that wrapped the value is attempting
//! to access it.  The difference between the two types starts playing a role once
//! destructors are involved.
//!
//! A `Fragile<T>` will actually send the `T` from thread to thread but will only
//! permit the original thread to invoke the destructor.  If the value gets dropped
//! in a different thread, the destructor will panic.
//!
//! A `Sticky<T>` on the other hand does not actually send the `T` around but keeps
//! it stored in the original thread's thread local storage.  If it gets dropped
//! in the originating thread it gets cleaned up immediately, otherwise it leaks
//! until the thread shuts down naturally.
//!
//! # Example usage
//!
//! ```
//! use std::thread;
//! use fragile::Fragile;
//!
//! // creating and using a fragile object in the same thread works
//! let val = Fragile::new(true);
//! assert_eq!(*val.get(), true);
//! assert!(val.try_get().is_ok());
//!
//! // once send to another thread it stops working
//! thread::spawn(move || {
//!     assert!(val.try_get().is_err());
//! }).join()
//!     .unwrap();
//! ```
//!
//! # Why?
//!
//! Most of the time trying to use this crate is going to indicate some code smell.  But
//! there are situations where this is useful.  For instance you might have a bunch of
//! non `Send` types but want to work with a `Send` error type.  In that case the non
//! sendable extra information can be contained within the error and in cases where the
//! error did not cross a thread boundary yet extra information can be obtained.
mod errors;
mod fragile;
mod semisticky;
mod sticky;

pub use errors::InvalidThreadAccess;
pub use fragile::Fragile;
pub use semisticky::SemiSticky;
pub use sticky::Sticky;
<|endoftext|>


<commit_before>use super::parse_module;

use core::semantic::ast::Node;

macro_rules! expr_test {
    ($name:ident, $code:expr) => {
        #[test]
        fn $name() {
            assert_eq!( parse_module($code)
                            .unwrap()[0]
                            .to_sexpr(0)
                      , $code)
        }
    }
}

expr_test!(test_basic_add, "(+ 1 2)");
expr_test!(test_basic_sub, "(- 3 4)");
expr_test!(test_basic_div, "(/ 5 6)");
expr_test!(test_basic_mul, "(* 1 2)");
expr_test!(test_nested_arith_1, "(+ 1 (- 2 3))");
expr_test!(test_nested_arith_2, "(* (+ 1 2) 3 4)");
expr_test!(test_nested_arith_3, "(+ (/ 1 2) (* 3 4))");

expr_test!(test_call_1, "(my_fn 1 2)");
expr_test!(test_call_2, "(my_fn (my_other_fn a_var a_different_var))");
expr_test!(test_call_3,
    "(my_fn (my_other_fn a_var a_different_var) VarWithUppercase Othervar)");
expr_test!(test_call_4, "(my_fn (my_other_fn a_var a_different_var) (another_fn a_var))");

expr_test!(test_call_ptr_1, "(my_fn a *b)");
expr_test!(test_call_ptr_2, "(my_fn *a *b)");
expr_test!(test_call_ptr_3, "(my_fn &a)");
expr_test!(test_call_ptr_4, "(my_fn a &b)");
expr_test!(test_call_ptr_5, "(my_fn &a &b)");
expr_test!(test_call_ptr_6, "(my_fn @a)");
expr_test!(test_call_ptr_7, "(my_fn a @b)");
expr_test!(test_call_ptr_8, "(my_fn @a @b)");
<commit_msg>Add (failing) def syntax test<commit_after>use super::parse_module;

use core::semantic::ast::Node;

macro_rules! expr_test {
    ($name:ident, $code:expr) => {
        #[test]
        fn $name() {
            assert_eq!( parse_module($code)
                            .unwrap()[0]
                            .to_sexpr(0)
                      , $code)
        }
    }
}

expr_test!(test_basic_add, "(+ 1 2)");
expr_test!(test_basic_sub, "(- 3 4)");
expr_test!(test_basic_div, "(/ 5 6)");
expr_test!(test_basic_mul, "(* 1 2)");
expr_test!(test_nested_arith_1, "(+ 1 (- 2 3))");
expr_test!(test_nested_arith_2, "(* (+ 1 2) 3 4)");
expr_test!(test_nested_arith_3, "(+ (/ 1 2) (* 3 4))");

expr_test!(test_call_1, "(my_fn 1 2)");
expr_test!(test_call_2, "(my_fn (my_other_fn a_var a_different_var))");
expr_test!(test_call_3
  , "(my_fn (my_other_fn a_var a_different_var) VarWithUppercase Othervar)");
expr_test!(test_call_4
  , "(my_fn (my_other_fn a_var a_different_var) (another_fn a_var))");

expr_test!(test_call_ptr_1, "(my_fn a *b)");
expr_test!(test_call_ptr_2, "(my_fn *a *b)");
expr_test!(test_call_ptr_3, "(my_fn &a)");
expr_test!(test_call_ptr_4, "(my_fn a &b)");
expr_test!(test_call_ptr_5, "(my_fn &a &b)");
expr_test!(test_call_ptr_6, "(my_fn @a)");
expr_test!(test_call_ptr_7, "(my_fn a @b)");
expr_test!(test_call_ptr_8, "(my_fn @a @b)");

expr_test!(test_defsyntax_1,
r#"(def fac (fn (-> I64 I64)
    ((0) 1)
    ((n) (fac (- n 1)))))"#);
<|endoftext|>


<commit_before>// Hound -- A WAV encoding library in Rust
// Copyright (C) 2015 Ruud van Asseldonk
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 3 of the License only.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

//! Hound, a WAV encoding library.
//!
//! TODO: Add some examples here.

#![warn(missing_docs)]
#![allow(dead_code)] // TODO: Remove for v0.1
#![feature(convert, io)]

use std::fs;
use std::io;
use std::io::{Seek, Write};
use std::path;

trait WriteExt: io::Write {
    fn write_le_u16(&mut self, x: u16) -> io::Result<()>;
    fn write_le_u32(&mut self, x: u32) -> io::Result<()>;
}

impl<W> WriteExt for W where W: io::Write {

    fn write_le_u16(&mut self, x: u16) -> io::Result<()> {
        let mut buf = [0u8; 2];
        buf[0] = (x & 0xff) as u8;
        buf[1] = (x >> 8) as u8;
        self.write_all(&buf)
    }

    fn write_le_u32(&mut self, x: u32) -> io::Result<()> {
        let mut buf = [0u8; 4];
        buf[0] = ((x >> 00) & 0xff) as u8;
        buf[1] = ((x >> 08) & 0xff) as u8;
        buf[2] = ((x >> 16) & 0xff) as u8;
        buf[3] = ((x >> 24) & 0xff) as u8;
        self.write_all(&buf)
    }
}

trait Sample {
    fn write<W: io::Write>(self, writer: &mut W, bits: u32) -> io::Result<()>;
}

impl Sample for u16 {
    fn write<W: io::Write>(self, writer: &mut W, bits: u32) -> io::Result<()> {
        writer.write_le_u16(self)
        // TODO: take bits into account
    }
}

/// Specifies properties of the audio data.
pub struct WavSpec {
    /// The number of channels.
    channels: u16,

    /// The number of samples per second.
    ///
    /// A common value is 44100, this is 44.1 kHz which is used for CD audio.
    sample_rate: u32,

    /// The number of bits per sample.
    ///
    /// A common value is 16 bits per sample, which is used for CD audio.
    bits_per_sample: u32
}

struct WavWriter<W> where W: io::Write {
    /// Specifies properties of the audio data.
    spec: WavSpec,

    /// Whether the header has been written already.
    wrote_header: bool,

    /// The writer that will be written to.
    writer: io::BufWriter<W>,

    /// The number of bytes written to the data section.
    ///
    /// This is an `u32` because WAVE cannot accomodate more data.
    data_bytes_written: u32
}

impl<W> WavWriter<W> where W: io::Write + io::Seek {
    /// Creates a writer that writes the WAVE format to the underlying writer.
    pub fn new(writer: W, spec: WavSpec) -> WavWriter<W> {
        unimplemented!();
    }

    /// Creates a writer that writes the WAVE format to a file.
    ///
    /// The file will be overwritten if it exists.
    pub fn create<P: AsRef<path::Path>>(filename: P, spec: WavSpec)
           -> io::Result<WavWriter<fs::File>> {
        let file = try!(fs::File::create(filename));
        Ok(WavWriter::new(file, spec))
    }

    /// Writes the RIFF WAVE header
    fn write_header(&mut self) -> io::Result<()> {
        let mut header = [0u8; 44];
        let spec = &self.spec;

        // Write the header in-memory first.
        {
            let mut buffer: io::Cursor<&mut [u8]> = io::Cursor::new(&mut header);
            try!(buffer.write_all("RIFF".as_bytes()));

            // Skip 4 bytes that will be filled with the file size afterwards.
            buffer.seek(io::SeekFrom::Current(4));

            try!(buffer.write_all("WAVE".as_bytes()));
            try!(buffer.write_all("fmt\0".as_bytes()));
            try!(buffer.write_le_u32(16)); // Size of the WAVE header
            try!(buffer.write_le_u16(1));  // PCM encoded audio
            try!(buffer.write_le_u16(spec.channels));
            try!(buffer.write_le_u32(spec.sample_rate));
            let bytes_per_sec = spec.sample_rate
                              * spec.bits_per_sample
                              * spec.channels as u32 / 8;
            try!(buffer.write_le_u32(bytes_per_sec));
            try!(buffer.write_le_u16(16)); // TODO: block align
            try!(buffer.write_le_u32(spec.bits_per_sample));

            // TODO: data section header
        }

        // Then write the entire header at once.
        try!(self.writer.write_all(&header));

        Ok(())
    }

    pub fn write_sample<S: Sample>(&mut self, sample: S) -> io::Result<()> {
        if !self.wrote_header {
            try!(self.write_header());
        }

        try!(sample.write(&mut self.writer, self.spec.bits_per_sample));
        self.data_bytes_written += self.spec.bits_per_sample / 8;
        Ok(())
    }
}
<commit_msg>add drop support<commit_after>// Hound -- A WAV encoding library in Rust
// Copyright (C) 2015 Ruud van Asseldonk
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 3 of the License only.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

//! Hound, a WAV encoding library.
//!
//! TODO: Add some examples here.

#![warn(missing_docs)]
#![allow(dead_code)] // TODO: Remove for v0.1
#![feature(convert, io, unsafe_destructor)]

use std::fs;
use std::io;
use std::io::{Seek, Write};
use std::path;

trait WriteExt: io::Write {
    fn write_le_u16(&mut self, x: u16) -> io::Result<()>;
    fn write_le_u32(&mut self, x: u32) -> io::Result<()>;
}

impl<W> WriteExt for W where W: io::Write {

    fn write_le_u16(&mut self, x: u16) -> io::Result<()> {
        let mut buf = [0u8; 2];
        buf[0] = (x & 0xff) as u8;
        buf[1] = (x >> 8) as u8;
        self.write_all(&buf)
    }

    fn write_le_u32(&mut self, x: u32) -> io::Result<()> {
        let mut buf = [0u8; 4];
        buf[0] = ((x >> 00) & 0xff) as u8;
        buf[1] = ((x >> 08) & 0xff) as u8;
        buf[2] = ((x >> 16) & 0xff) as u8;
        buf[3] = ((x >> 24) & 0xff) as u8;
        self.write_all(&buf)
    }
}

trait Sample {
    fn write<W: io::Write>(self, writer: &mut W, bits: u32) -> io::Result<()>;
}

impl Sample for u16 {
    fn write<W: io::Write>(self, writer: &mut W, bits: u32) -> io::Result<()> {
        writer.write_le_u16(self)
        // TODO: take bits into account
    }
}

/// Specifies properties of the audio data.
pub struct WavSpec {
    /// The number of channels.
    channels: u16,

    /// The number of samples per second.
    ///
    /// A common value is 44100, this is 44.1 kHz which is used for CD audio.
    sample_rate: u32,

    /// The number of bits per sample.
    ///
    /// A common value is 16 bits per sample, which is used for CD audio.
    bits_per_sample: u32
}

/// A writer that accepts samples and writes the WAVE format.
///
/// TODO: add example.
///
/// The writer employs buffering internally to avoid too many `write` calls to
/// the underlying writer. The underlying writer is assumed to be at offset 0
/// upon creation.
///
/// After all samples have been written, the file must be finalized. This can
/// be done by calling `finalize`. If `finalize` is not called, the file will
/// be finalized upon drop. However, finalization involves IO that may fail,
/// and without calling `finalize`, such a failure cannot be observed.
struct WavWriter<W> where W: io::Write + io::Seek {
    /// Specifies properties of the audio data.
    spec: WavSpec,

    /// Whether the header has been written already.
    wrote_header: bool,

    /// The writer that will be written to.
    writer: io::BufWriter<W>,

    /// The number of bytes written to the data section.
    ///
    /// This is an `u32` because WAVE cannot accomodate more data.
    data_bytes_written: u32,

    /// Whether `finalize_internal` has been called.
    finalized: bool
}

impl<W> WavWriter<W> where W: io::Write + io::Seek {
    /// Creates a writer that writes the WAVE format to the underlying writer.
    pub fn new(writer: W, spec: WavSpec) -> WavWriter<W> {
        unimplemented!();
    }

    /// Creates a writer that writes the WAVE format to a file.
    ///
    /// The file will be overwritten if it exists.
    pub fn create<P: AsRef<path::Path>>(filename: P, spec: WavSpec)
           -> io::Result<WavWriter<fs::File>> {
        let file = try!(fs::File::create(filename));
        Ok(WavWriter::new(file, spec))
    }

    /// Writes the RIFF WAVE header
    fn write_header(&mut self) -> io::Result<()> {
        let mut header = [0u8; 44];
        let spec = &self.spec;

        // Write the header in-memory first.
        {
            let mut buffer: io::Cursor<&mut [u8]> = io::Cursor::new(&mut header);
            try!(buffer.write_all("RIFF".as_bytes()));

            // Skip 4 bytes that will be filled with the file size afterwards.
            try!(buffer.seek(io::SeekFrom::Current(4)));

            try!(buffer.write_all("WAVE".as_bytes()));
            try!(buffer.write_all("fmt\0".as_bytes()));
            try!(buffer.write_le_u32(16)); // Size of the WAVE header
            try!(buffer.write_le_u16(1));  // PCM encoded audio
            try!(buffer.write_le_u16(spec.channels));
            try!(buffer.write_le_u32(spec.sample_rate));
            let bytes_per_sec = spec.sample_rate
                              * spec.bits_per_sample
                              * spec.channels as u32 / 8;
            try!(buffer.write_le_u32(bytes_per_sec));
            try!(buffer.write_le_u16(16)); // TODO: block align
            try!(buffer.write_le_u32(spec.bits_per_sample));

            // TODO: data section header
        }

        // Then write the entire header at once.
        try!(self.writer.write_all(&header));

        Ok(())
    }

    pub fn write_sample<S: Sample>(&mut self, sample: S) -> io::Result<()> {
        if !self.wrote_header {
            try!(self.write_header());
        }

        try!(sample.write(&mut self.writer, self.spec.bits_per_sample));
        self.data_bytes_written += self.spec.bits_per_sample / 8;
        Ok(())
    }

    fn finalize_internal(&mut self) -> io::Result<()> {
        self.finalized = true;

        // Flush remaining samples via the BufWriter.
        try!(self.writer.flush());

        // Extract the underlying writer and rewind it to the start, to update
        // the header fields of which we now know the value.
        let mut writer = self.writer.get_mut();
        try!(writer.seek(io::SeekFrom::Start(0)));

        // TODO: update size fields
        Ok(())
    }

    pub fn finalize(mut self) -> io::Result<()> {
        self.finalize_internal()
    }
}

#[unsafe_destructor] // TODO: this can hopefully be removed at the next nightly!
impl<W> Drop for WavWriter<W> where W: io::Write + io::Seek {
    fn drop(&mut self) {
        // `finalize_internal` must be called only once. If that is done via
        // `finalize`, then this method is a no-op. If the user did not
        // finalize explicitly, then we should do it now. This can fail, but
        // drop should not panic, so a failure is ignored silently here.
        if !self.finalized {
            let _r = self.finalize_internal();
        }
    }
}
<|endoftext|>


<commit_before>use std::io;

#[doc(hidden)]
// Shortcut for writing string literals,
// so they don't go through write_fmt machinery.
pub trait WriteStrExt {
    type Result;
    fn write_str(&mut self, s: &str) -> Self::Result;
}

// The fmt::Write already has this method,
// so we implement it only for W: io::Write.
impl<W: io::Write> WriteStrExt for W {
    type Result = io::Result<()>;
    fn write_str(&mut self, s: &str) -> Self::Result {
        self.write_all(s.as_bytes())
    }
}

#[macro_export]
macro_rules! wite {
    // single tt rules ---------------------------------------------------------
    (@one $w:ident, ($e:expr)) => { write!($w, "{}", $e) };
    (@one $w:ident, [$e:expr]) => { write!($w, "{:?}", $e) };
    (@one $w:ident, {$e:tt : $($fmt:tt)*}) => {
        write!($w, concat!("{:", stringify!($($fmt)*), "}"), $e)
    };
    (@one $w:ident, {$($arg:tt)*}) => {
        write!($w, $($arg)*)
    };
    (@one $w:ident, $string:tt) => {
        {
            #[allow(unused_imports)]
            use $crate::WriteStrExt;

            $w.write_str(concat!($string))
        }
    };

    // expression parsing (manually, because we can't use :expr before `{`)
    (@expr $w:ident {$($before:tt)*} ($($e:tt)*) {$($block:tt)*} $($rest:tt)* ) => {
        wite!(@rec $w, $($before)* ($($e)*) {$($block)*} $($rest)*)
    };
    (@expr $w:ident {$($before:tt)*} ($($expr:tt)*) $tt:tt $($rest:tt)* ) => {
        wite!(@expr $w {$($before)*} ($($expr)* $tt) $($rest)*)
    };

    // recursive parsing -------------------------------------------------------
    // for
    (@rec $w:ident, for $p:pat in ($e:expr) { $($body:tt)* } $($rest:tt)* ) => {
        {
            for $p in $e {
                wite!(@rec $w, $($body)*);
            }
            wite!(@rec $w, $($rest)*);
        }
    };
    (@rec $w:ident, for $p:pat in $($tt:tt)* ) => {
        wite!(@expr $w { for $p in } () $($tt)*)
    };

    // match
    (
        @rec $w:ident,
        match ($e:expr) {
            $( $($p:pat)|+ $(if $g:expr)* => { $($body:tt)* } )*
        }
        $($rest:tt)*
    ) => {
        {
            match $e {
                $(
                    $($p)|+ $(if $g)* => {
                        wite!(@rec $w, $($body)*)
                    }
                )*
            }
            wite!(@rec $w, $($rest)*);
        }
    };
    (@rec $w:ident, match $($tt:tt)* ) => {
        wite!(@expr $w { match } () $($tt)*)
    };

    // if let
    (
        @rec $w:ident,
        if let $p:pat = ($e:expr) { $($then:tt)* }
        else { $($els:tt)* }
        $($rest:tt)*
    ) => {
        {
            if let $p = $e {
                wite!(@rec $w, $($then)*);
            } else {
                wite!(@rec $w, $($els)*);
            }
            wite!(@rec $w, $($rest)*);
        }
    };
    (
        @rec $w:ident,
        if let $p:pat = ($e:expr) { $($then:tt)* }
        else if $($rest:tt)*
    ) => {
        wite!(@ifelseerror)
    };
    (
        @rec $w:ident,
        if let $p:pat = ($e:expr) { $($then:tt)* }
        $($rest:tt)*
    ) => {
        wite!(@rec $w, if let $p = ($e) { $($then)* } else {} $($rest)*);
    };
    (@rec $w:ident, if let $p:pat = $($tt:tt)* ) => {
        wite!(@expr $w { if let $p = } () $($tt)*)
    };

    // if
    (
        @rec $w:ident,
        if ($cond:expr) { $($then:tt)* }
        else { $($els:tt)* }
        $($rest:tt)*
    ) => {
        {
            if $cond {
                wite!(@rec $w, $($then)*);
            } else {
                wite!(@rec $w, $($els)*);
            }
            wite!(@rec $w, $($rest)*);
        }
    };
    (
        @rec $w:ident,
        if ($cont:expr) { $($then:tt)* }
        else if $($rest:tt)*
    ) => {
        wite!(@ifelseerror)
    };
    (@rec $w:ident, if ($cond:expr) { $($then:tt)* } $($rest:tt)* ) => {
        wite!(@rec $w, if ($cond) { $($then)* } else {} $($rest)*);
    };
    (@rec $w:ident, if $($tt:tt)* ) => {
        wite!(@expr $w { if } () $($tt)*)
    };

    // single tt
    (@rec $w:ident, $part:tt $($rest:tt)*) => {
        {
            match wite!(@one $w, $part) {
                Ok(_) => (),
                error => return error,
            }
            wite!(@rec $w, $($rest)*);
        }
    };

    // terminator
    (@rec $w:ident, ) => { () };

    (@ifelseerror) => {
        {
            let ERROR: () = "`else if` is unsupported";
            let NOTE: () = "use `match` or `else { if ... }` instead";
        }
    };

    // entry point -------------------------------------------------------------
    ($writer:expr, $($part:tt)*) => {
        (||{
            let mut _w = $writer;
            if false {
                // This dummy write's purpose is to silence a warning
                // about "unused import `Write`". We can't just
                // do `let _: Option<&Write> = None;` though, because
                // in case when writing to Formatter, the `Write` trait
                // doesn't have to be in scope.
                let _ = write!(_w, "");
            }
            wite!(@rec _w, $($part)*);
            Ok(())
        })()
    };
}

#[macro_export]
macro_rules! witeln {
    ($($arg:tt)*) => { wite!($($arg)* "\n") }
}

#[macro_export]
macro_rules! pint {
    ($($arg:tt)*) => {
        {
            use ::std::io::Write;
            let o = ::std::io::stdout();
            wite!(o.lock(), $($arg)*).unwrap();
        }
    }
}

#[macro_export]
macro_rules! pintln {
    ($($arg:tt)*) => { pint!($($arg)* "\n") }
}

#[macro_export]
macro_rules! perr {
    ($($arg:tt)*) => {
        {
            use ::std::io::Write;
            let o = ::std::io::stderr();
            wite!(o.lock(), $($arg)*).unwrap();
        }
    }
}

#[macro_export]
macro_rules! perrln {
    ($($arg:tt)*) => { perr!($($arg)* "\n") }
}

#[macro_export]
macro_rules! fomat {
    // capacity estimation -----------------------------------------------------
    (@cap ($len:expr, $multiplier:expr)) => {
        ($len, $multiplier)
    };

    // skip all irrelevant tts and conditional bodies
    (@cap ($($lm:tt)*) for $p:pat in $($tt:tt)*) => {
        fomat!(@cap-ignore ($($lm)*) $($tt)*)
    };
    (@cap ($($lm:tt)*) if let $p:pat = $($tt:tt)*) => {
        fomat!(@cap-ignore ($($lm)*) $($tt)*)
    };
    (@cap ($($lm:tt)*) if $($tt:tt)*) => {
        fomat!(@cap-ignore ($($lm)*) $($tt)*)
    };
    (@cap ($($lm:tt)*) else $($tt:tt)*) => {
        fomat!(@cap-ignore ($($lm)*) $($tt)*)
    };
    (@cap ($($lm:tt)*) match $($tt:tt)*) => {
        fomat!(@cap-ignore ($($lm)*) $($tt)*)
    };

    // When there's any unconditional string interpolation,
    // we multiply the initial capacity by 2
    // (which would probably happen anyway).
    (@cap ($len:expr, $mul:expr) ($($x:tt)*) $($rest:tt)*) => {
        fomat!(@cap ($len, 2) $($rest)*)
    };
    (@cap ($len:expr, $mul:expr) [$($x:tt)*] $($rest:tt)*) => {
        fomat!(@cap ($len, 2) $($rest)*)
    };
    (@cap ($len:expr, $mul:expr) {$($x:tt)*} $($rest:tt)*) => {
        fomat!(@cap ($len, 2) $($rest)*)
    };

    // Now the only legal tt is a string literal
    (@cap ($len:expr, $mul:expr) $string:tt $($rest:tt)*) => {
        // Concat forces the token to be a string literal.
        fomat!(@cap ($len + concat!($string).len(), $mul) $($rest)*)
    };

    // Ignores everything till after next block
    (@cap-ignore ($($lm:tt)*) { $($block:tt)* } $($rest:tt)*) => {
        fomat!(@cap ($($lm)*) $($rest)*)
    };
    (@cap-ignore ($($lm:tt)*) $tt:tt $($rest:tt)*) => {
        fomat!(@cap-ignore ($($lm)*) $($rest)*)
    };

    // entry points ------------------------------------------------------------
    () => { String::new() };
    ($($arg:tt)*) => {
        {
            use ::std::fmt::Write;
            let (len, mul) = fomat!(@cap (0, 1) $($arg)*);
            let mut _s = String::with_capacity(len * mul);
            wite!(&mut _s, $($arg)*).ok();
            _s
        }
    }
}

#[test]
fn basics() {
    let world = "World";
    assert_eq!(fomat!("Hello, "(world)"!"), "Hello, World!");
    let x = 3;
    assert_eq!(fomat!((x)" * 2 = "(x * 2)), "3 * 2 = 6");
}

#[test]
fn empty() {
    assert_eq!(fomat!(), "");
}

#[test]
fn vec() {
    let v = vec![1,2,3];
    assert_eq!(fomat!([v]), "[1, 2, 3]");
}

#[test]
fn write() {
    use std::io::Write;
    let mut v = Vec::new();
    witeln!(&mut v, "hi" "!").unwrap();
    assert_eq!(v, "hi!\n".as_bytes());
}

#[test]
fn format() {
    assert_eq!( fomat!({5:02}), "05" );
    assert_eq!( fomat!({"{}-{}", 4, 2}), "4-2" );
}

#[test]
fn hello() {
    let foo = "foo";
    let x = 2;
    let y = 4;
    pintln!("Bar "(foo)" and "(x));
    pintln!( (x)" < "(y) );
    pintln!( for x in (&[1,2,3]) { (x)" :: " } "nil" );
}

#[test]
fn matrix() {
    let matrix = vec![vec![0]];
    assert_eq!(
        fomat!( for row in &matrix { for x in row { {x:3} } "\n" } ),
        "  0\n"
    );
}

#[test]
fn boo() {
    let a = Some(5);
    pintln!(if let Some(_) = a { "yes" });
}

#[test]
fn test_match() {
    let s = fomat!(
        match Some(5) {
            Some(x) if x > 3 => { (x) }
            Some(2) | None => {}
            _ => {}
        }
        "."
    );
    assert_eq!(s, "5.");
}

#[test]
fn capacity() {
    assert_eq!(fomat!("Hello, " "world!").capacity(), 13);
    assert_eq!(fomat!("Hello, "[40+2]).capacity(), 14);
    let s = fomat!(
        "Hello"
        for x in [1][1..].iter() { (x) "a" }
        if let Some(()) = None { "b" }
        if false { "c" } else {}
        match 1 { 2 => { "e" } _ => {} }
        "!"
    );
    assert_eq!(s.capacity(), 6);
}

#[test]
fn fmt_write() {
    use std::fmt;
    struct Foo;

    impl fmt::Display for Foo {
        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
            wite!(f, "foo"(42))
        }
    }

    assert_eq!(format!("{}", Foo), "foo42");
}
<commit_msg>add equal sign shorthand for printing `expression = value`<commit_after>use std::io;

#[doc(hidden)]
// Shortcut for writing string literals,
// so they don't go through write_fmt machinery.
pub trait WriteStrExt {
    type Result;
    fn write_str(&mut self, s: &str) -> Self::Result;
}

// The fmt::Write already has this method,
// so we implement it only for W: io::Write.
impl<W: io::Write> WriteStrExt for W {
    type Result = io::Result<()>;
    fn write_str(&mut self, s: &str) -> Self::Result {
        self.write_all(s.as_bytes())
    }
}

#[macro_export]
macro_rules! wite {
    // single tt rules ---------------------------------------------------------
    (@one $w:ident, ($e:expr)) => { write!($w, "{}", $e) };
    (@one $w:ident, [$e:expr]) => { write!($w, "{:?}", $e) };
    (@one $w:ident, {$e:tt : $($fmt:tt)*}) => {
        write!($w, concat!("{:", stringify!($($fmt)*), "}"), $e)
    };
    (@one $w:ident, {$($arg:tt)*}) => {
        write!($w, $($arg)*)
    };
    (@one $w:ident, $string:tt) => {
        {
            #[allow(unused_imports)]
            use $crate::WriteStrExt;

            $w.write_str(concat!($string))
        }
    };

    // expression parsing (manually, because we can't use :expr before `{`)
    (@expr $w:ident {$($before:tt)*} ($($e:tt)*) {$($block:tt)*} $($rest:tt)* ) => {
        wite!(@rec $w, $($before)* ($($e)*) {$($block)*} $($rest)*)
    };
    (@expr $w:ident {$($before:tt)*} ($($expr:tt)*) $tt:tt $($rest:tt)* ) => {
        wite!(@expr $w {$($before)*} ($($expr)* $tt) $($rest)*)
    };

    // recursive parsing -------------------------------------------------------
    // for
    (@rec $w:ident, for $p:pat in ($e:expr) { $($body:tt)* } $($rest:tt)* ) => {
        {
            for $p in $e {
                wite!(@rec $w, $($body)*);
            }
            wite!(@rec $w, $($rest)*);
        }
    };
    (@rec $w:ident, for $p:pat in $($tt:tt)* ) => {
        wite!(@expr $w { for $p in } () $($tt)*)
    };

    // match
    (
        @rec $w:ident,
        match ($e:expr) {
            $( $($p:pat)|+ $(if $g:expr)* => { $($body:tt)* } )*
        }
        $($rest:tt)*
    ) => {
        {
            match $e {
                $(
                    $($p)|+ $(if $g)* => {
                        wite!(@rec $w, $($body)*)
                    }
                )*
            }
            wite!(@rec $w, $($rest)*);
        }
    };
    (@rec $w:ident, match $($tt:tt)* ) => {
        wite!(@expr $w { match } () $($tt)*)
    };

    // if let
    (
        @rec $w:ident,
        if let $p:pat = ($e:expr) { $($then:tt)* }
        else { $($els:tt)* }
        $($rest:tt)*
    ) => {
        {
            if let $p = $e {
                wite!(@rec $w, $($then)*);
            } else {
                wite!(@rec $w, $($els)*);
            }
            wite!(@rec $w, $($rest)*);
        }
    };
    (
        @rec $w:ident,
        if let $p:pat = ($e:expr) { $($then:tt)* }
        else if $($rest:tt)*
    ) => {
        wite!(@ifelseerror)
    };
    (
        @rec $w:ident,
        if let $p:pat = ($e:expr) { $($then:tt)* }
        $($rest:tt)*
    ) => {
        wite!(@rec $w, if let $p = ($e) { $($then)* } else {} $($rest)*);
    };
    (@rec $w:ident, if let $p:pat = $($tt:tt)* ) => {
        wite!(@expr $w { if let $p = } () $($tt)*)
    };

    // if
    (
        @rec $w:ident,
        if ($cond:expr) { $($then:tt)* }
        else { $($els:tt)* }
        $($rest:tt)*
    ) => {
        {
            if $cond {
                wite!(@rec $w, $($then)*);
            } else {
                wite!(@rec $w, $($els)*);
            }
            wite!(@rec $w, $($rest)*);
        }
    };
    (
        @rec $w:ident,
        if ($cont:expr) { $($then:tt)* }
        else if $($rest:tt)*
    ) => {
        wite!(@ifelseerror)
    };
    (@rec $w:ident, if ($cond:expr) { $($then:tt)* } $($rest:tt)* ) => {
        wite!(@rec $w, if ($cond) { $($then)* } else {} $($rest)*);
    };
    (@rec $w:ident, if $($tt:tt)* ) => {
        wite!(@expr $w { if } () $($tt)*)
    };

    // equal-sign debugging
    (@rec $w:ident, (= $e:expr) $($rest:tt)*) => {
        wite!(@rec $w, (concat!(stringify!($e), " = ")) ($e) $($rest)*)
    };
    (@rec $w:ident, [= $e:expr] $($rest:tt)*) => {
        wite!(@rec $w, (concat!(stringify!($e), " = ")) [$e] $($rest)*)
    };
    (@rec $w:ident, {= $e:tt : $($fmt:tt)*} $($rest:tt)*) => {
        wite!(@rec $w, (concat!(stringify!($e), " = ")) {$e : $($fmt)*} $($rest)*)
    };

    // single tt
    (@rec $w:ident, $part:tt $($rest:tt)*) => {
        {
            match wite!(@one $w, $part) {
                Ok(_) => (),
                error => return error,
            }
            wite!(@rec $w, $($rest)*);
        }
    };

    // terminator
    (@rec $w:ident, ) => { () };

    (@ifelseerror) => {
        {
            let ERROR: () = "`else if` is unsupported";
            let NOTE: () = "use `match` or `else { if ... }` instead";
        }
    };

    // entry point -------------------------------------------------------------
    ($writer:expr, $($part:tt)*) => {
        (||{
            let mut _w = $writer;
            if false {
                // This dummy write's purpose is to silence a warning
                // about "unused import `Write`". We can't just
                // do `let _: Option<&Write> = None;` though, because
                // in case when writing to Formatter, the `Write` trait
                // doesn't have to be in scope.
                let _ = write!(_w, "");
            }
            wite!(@rec _w, $($part)*);
            Ok(())
        })()
    };
}

#[macro_export]
macro_rules! witeln {
    ($($arg:tt)*) => { wite!($($arg)* "\n") }
}

#[macro_export]
macro_rules! pint {
    ($($arg:tt)*) => {
        {
            use ::std::io::Write;
            let o = ::std::io::stdout();
            wite!(o.lock(), $($arg)*).unwrap();
        }
    }
}

#[macro_export]
macro_rules! pintln {
    ($($arg:tt)*) => { pint!($($arg)* "\n") }
}

#[macro_export]
macro_rules! perr {
    ($($arg:tt)*) => {
        {
            use ::std::io::Write;
            let o = ::std::io::stderr();
            wite!(o.lock(), $($arg)*).unwrap();
        }
    }
}

#[macro_export]
macro_rules! perrln {
    ($($arg:tt)*) => { perr!($($arg)* "\n") }
}

#[macro_export]
macro_rules! fomat {
    // capacity estimation -----------------------------------------------------
    (@cap ($len:expr, $multiplier:expr)) => {
        ($len, $multiplier)
    };

    // skip all irrelevant tts and conditional bodies
    (@cap ($($lm:tt)*) for $p:pat in $($tt:tt)*) => {
        fomat!(@cap-ignore ($($lm)*) $($tt)*)
    };
    (@cap ($($lm:tt)*) if let $p:pat = $($tt:tt)*) => {
        fomat!(@cap-ignore ($($lm)*) $($tt)*)
    };
    (@cap ($($lm:tt)*) if $($tt:tt)*) => {
        fomat!(@cap-ignore ($($lm)*) $($tt)*)
    };
    (@cap ($($lm:tt)*) else $($tt:tt)*) => {
        fomat!(@cap-ignore ($($lm)*) $($tt)*)
    };
    (@cap ($($lm:tt)*) match $($tt:tt)*) => {
        fomat!(@cap-ignore ($($lm)*) $($tt)*)
    };

    // When there's any unconditional string interpolation,
    // we multiply the initial capacity by 2
    // (which would probably happen anyway).
    (@cap ($len:expr, $mul:expr) ($($x:tt)*) $($rest:tt)*) => {
        fomat!(@cap ($len, 2) $($rest)*)
    };
    (@cap ($len:expr, $mul:expr) [$($x:tt)*] $($rest:tt)*) => {
        fomat!(@cap ($len, 2) $($rest)*)
    };
    (@cap ($len:expr, $mul:expr) {$($x:tt)*} $($rest:tt)*) => {
        fomat!(@cap ($len, 2) $($rest)*)
    };

    // Now the only legal tt is a string literal
    (@cap ($len:expr, $mul:expr) $string:tt $($rest:tt)*) => {
        // Concat forces the token to be a string literal.
        fomat!(@cap ($len + concat!($string).len(), $mul) $($rest)*)
    };

    // Ignores everything till after next block
    (@cap-ignore ($($lm:tt)*) { $($block:tt)* } $($rest:tt)*) => {
        fomat!(@cap ($($lm)*) $($rest)*)
    };
    (@cap-ignore ($($lm:tt)*) $tt:tt $($rest:tt)*) => {
        fomat!(@cap-ignore ($($lm)*) $($rest)*)
    };

    // entry points ------------------------------------------------------------
    () => { String::new() };
    ($($arg:tt)*) => {
        {
            use ::std::fmt::Write;
            let (len, mul) = fomat!(@cap (0, 1) $($arg)*);
            let mut _s = String::with_capacity(len * mul);
            wite!(&mut _s, $($arg)*).ok();
            _s
        }
    }
}

#[test]
fn basics() {
    let world = "World";
    assert_eq!(fomat!("Hello, "(world)"!"), "Hello, World!");
    let x = 3;
    assert_eq!(fomat!((x)" * 2 = "(x * 2)), "3 * 2 = 6");
}

#[test]
fn empty() {
    assert_eq!(fomat!(), "");
}

#[test]
fn vec() {
    let v = vec![1,2,3];
    assert_eq!(fomat!([v]), "[1, 2, 3]");
}

#[test]
fn write() {
    use std::io::Write;
    let mut v = Vec::new();
    witeln!(&mut v, "hi" "!").unwrap();
    assert_eq!(v, "hi!\n".as_bytes());
}

#[test]
fn format() {
    assert_eq!( fomat!({5:02}), "05" );
    assert_eq!( fomat!({"{}-{}", 4, 2}), "4-2" );
}

#[test]
fn hello() {
    let foo = "foo";
    let x = 2;
    let y = 4;
    pintln!("Bar "(foo)" and "(x));
    pintln!( (x)" < "(y) );
    pintln!( for x in (&[1,2,3]) { (x)" :: " } "nil" );
}

#[test]
fn matrix() {
    let matrix = vec![vec![0]];
    assert_eq!(
        fomat!( for row in &matrix { for x in row { {x:3} } "\n" } ),
        "  0\n"
    );
}

#[test]
fn boo() {
    let a = Some(5);
    pintln!(if let Some(_) = a { "yes" });
}

#[test]
fn test_match() {
    let s = fomat!(
        match Some(5) {
            Some(x) if x > 3 => { (x) }
            Some(2) | None => {}
            _ => {}
        }
        "."
    );
    assert_eq!(s, "5.");
}

#[test]
fn capacity() {
    assert_eq!(fomat!("Hello, " "world!").capacity(), 13);
    assert_eq!(fomat!("Hello, "[40+2]).capacity(), 14);
    let s = fomat!(
        "Hello"
        for x in [1][1..].iter() { (x) "a" }
        if let Some(()) = None { "b" }
        if false { "c" } else {}
        match 1 { 2 => { "e" } _ => {} }
        "!"
    );
    assert_eq!(s.capacity(), 6);
}

#[test]
fn fmt_write() {
    use std::fmt;
    struct Foo;

    impl fmt::Display for Foo {
        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
            wite!(f, "foo"(42))
        }
    }

    assert_eq!(format!("{}", Foo), "foo42");
}

#[test]
fn equal_sign() {
    let x = 5;
    let v = vec![10];
    assert_eq!(fomat!((=x) "."), "x = 5.");
    assert_eq!(fomat!([=&v] "."), "&v = [10].");
    assert_eq!(fomat!({=13:05b} "."), "13 = 01101.");
}
<|endoftext|>