<commit_before>//! The _dirs_ crate is
//!
//! - a tiny library with a minimal API (16 functions)
//! - that provides the platform-specific, user-accessible locations
//! - for finding and storing configuration, cache and other data
//! - on Linux, Redox, Windows (≥ Vista) and macOS.
//!
//! The library provides the location of these directories by leveraging the mechanisms defined by
//!
//! - the [XDG base directory](https://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html) and the [XDG user directory](https://www.freedesktop.org/wiki/Software/xdg-user-dirs/) specifications on Linux,
//! - the [Known Folder](https://msdn.microsoft.com/en-us/library/windows/desktop/bb776911(v=vs.85).aspx) system on Windows, and
//! - the [Standard Directories](https://developer.apple.com/library/content/documentation/FileManagement/Conceptual/FileSystemProgrammingGuide/FileSystemOverview/FileSystemOverview.html#//apple_ref/doc/uid/TP40010672-CH2-SW6) on macOS.

#![deny(missing_docs)]

#[macro_use]
extern crate cfg_if;

use std::path::PathBuf;

cfg_if! {
    if #[cfg(target_os = "windows")] {
        mod win;
        use win as sys;
    } else if #[cfg(target_os = "macos")] {
        mod mac;
        use mac as sys;
    } else if #[cfg(target_os = "wasi")] {
        mod wasi;
        use wasi as sys;
    } else {
        mod lin;
        use lin as sys;
    }
}

/// Returns the path to the user's home directory.
///
/// The returned value depends on the operating system and is either a `Some`, containing a value from the following table, or a `None`.
///
/// |Platform | Value                | Example        |
/// | ------- | -------------------- | -------------- |
/// | Linux   | `$HOME`              | /home/alice    |
/// | macOS   | `$HOME`              | /Users/Alice   |
/// | Windows | `{FOLDERID_Profile}` | C:\Users\Alice |
///
/// ### Linux and macOS:
///
/// - Use `$HOME` if it is set and not empty.
/// - If `$HOME` is not set or empty, then the function `getpwuid_r` is used to determine
///   the home directory of the current user.
/// - If `getpwuid_r` lacks an entry for the current user id or the home directory field is empty,
///   then the function returns `None`.
///
/// ### Windows:
///
/// This function retrieves the user profile folder using `SHGetKnownFolderPath`.
///
/// All the examples on this page mentioning `$HOME` use this behavior.
///
/// _Note:_ This function's behavior differs from [`std::env::home_dir`],
/// which works incorrectly on Linux, macOS and Windows.
///
/// [`std::env::home_dir`]: https://doc.rust-lang.org/std/env/fn.home_dir.html
pub fn home_dir() -> Option<PathBuf> {
    sys::home_dir()
}
/// Returns the path to the user's cache directory.
///
/// The returned value depends on the operating system and is either a `Some`, containing a value from the following table, or a `None`.
///
/// |Platform | Value                               | Example                      |
/// | ------- | ----------------------------------- | ---------------------------- |
/// | Linux   | `$XDG_CACHE_HOME` or `$HOME`/.cache | /home/alice/.cache           |
/// | macOS   | `$HOME`/Library/Caches              | /Users/Alice/Library/Caches  |
/// | Windows | `{FOLDERID_LocalAppData}`           | C:\Users\Alice\AppData\Local |
pub fn cache_dir() -> Option<PathBuf> {
    sys::cache_dir()
}
/// Returns the path to the user's config directory.
///
/// The returned value depends on the operating system and is either a `Some`, containing a value from the following table, or a `None`.
///
/// |Platform | Value                                 | Example                          |
/// | ------- | ------------------------------------- | -------------------------------- |
/// | Linux   | `$XDG_CONFIG_HOME` or `$HOME`/.config | /home/alice/.config              |
/// | macOS   | `$HOME`/Library/Preferences           | /Users/Alice/Library/Preferences |
/// | Windows | `{FOLDERID_RoamingAppData}`           | C:\Users\Alice\AppData\Roaming   |
pub fn config_dir() -> Option<PathBuf> {
    sys::config_dir()
}
/// Returns the path to the user's data directory.
///
/// The returned value depends on the operating system and is either a `Some`, containing a value from the following table, or a `None`.
///
/// |Platform | Value                                    | Example                                  |
/// | ------- | ---------------------------------------- | ---------------------------------------- |
/// | Linux   | `$XDG_DATA_HOME` or `$HOME`/.local/share | /home/alice/.local/share                 |
/// | macOS   | `$HOME`/Library/Application Support      | /Users/Alice/Library/Application Support |
/// | Windows | `{FOLDERID_RoamingAppData}`              | C:\Users\Alice\AppData\Roaming           |
pub fn data_dir() -> Option<PathBuf> {
    sys::data_dir()
}
/// Returns the path to the user's local data directory.
///
/// The returned value depends on the operating system and is either a `Some`, containing a value from the following table, or a `None`.
///
/// |Platform | Value                                    | Example                                  |
/// | ------- | ---------------------------------------- | ---------------------------------------- |
/// | Linux   | `$XDG_DATA_HOME` or `$HOME`/.local/share | /home/alice/.local/share                 |
/// | macOS   | `$HOME`/Library/Application Support      | /Users/Alice/Library/Application Support |
/// | Windows | `{FOLDERID_LocalAppData}`                | C:\Users\Alice\AppData\Local             |
pub fn data_local_dir() -> Option<PathBuf> {
    sys::data_local_dir()
}
/// Returns the path to the user's executable directory.
///
/// The returned value depends on the operating system and is either a `Some`, containing a value from the following table, or a `None`.
///
/// |Platform | Value                                                            | Example                |
/// | ------- | ---------------------------------------------------------------- | ---------------------- |
/// | Linux   | `$XDG_BIN_HOME` or `$XDG_DATA_HOME`/../bin or `$HOME`/.local/bin | /home/alice/.local/bin |
/// | macOS   | –                                                                | –                      |
/// | Windows | –                                                                | –                      |
pub fn executable_dir() -> Option<PathBuf> {
    sys::executable_dir()
}
/// Returns the path to the user's runtime directory.
///
/// The returned value depends on the operating system and is either a `Some`, containing a value from the following table, or a `None`.
///
/// |Platform | Value              | Example         |
/// | ------- | ------------------ | --------------- |
/// | Linux   | `$XDG_RUNTIME_DIR` | /run/user/1001/ |
/// | macOS   | –                  | –               |
/// | Windows | –                  | –               |
pub fn runtime_dir() -> Option<PathBuf> {
    sys::runtime_dir()
}

/// Returns the path to the user's audio directory.
///
/// The returned value depends on the operating system and is either a `Some`, containing a value from the following table, or a `None`.
///
/// |Platform | Value              | Example              |
/// | ------- | ------------------ | -------------------- |
/// | Linux   | `XDG_MUSIC_DIR`    | /home/alice/Music    |
/// | macOS   | `$HOME`/Music      | /Users/Alice/Music   |
/// | Windows | `{FOLDERID_Music}` | C:\Users\Alice\Music |
pub fn audio_dir() -> Option<PathBuf> {
    sys::audio_dir()
}
/// Returns the path to the user's desktop directory.
///
/// The returned value depends on the operating system and is either a `Some`, containing a value from the following table, or a `None`.
///
/// |Platform | Value                | Example                |
/// | ------- | -------------------- | ---------------------- |
/// | Linux   | `XDG_DESKTOP_DIR`    | /home/alice/Desktop    |
/// | macOS   | `$HOME`/Desktop      | /Users/Alice/Desktop   |
/// | Windows | `{FOLDERID_Desktop}` | C:\Users\Alice\Desktop |
pub fn desktop_dir() -> Option<PathBuf> {
    sys::desktop_dir()
}
/// Returns the path to the user's document directory.
///
/// The returned value depends on the operating system and is either a `Some`, containing a value from the following table, or a `None`.
///
/// |Platform | Value                  | Example                  |
/// | ------- | ---------------------- | ------------------------ |
/// | Linux   | `XDG_DOCUMENTS_DIR`    | /home/alice/Documents    |
/// | macOS   | `$HOME`/Documents      | /Users/Alice/Documents   |
/// | Windows | `{FOLDERID_Documents}` | C:\Users\Alice\Documents |
pub fn document_dir() -> Option<PathBuf> {
    sys::document_dir()
}
/// Returns the path to the user's download directory.
///
/// The returned value depends on the operating system and is either a `Some`, containing a value from the following table, or a `None`.
///
/// |Platform | Value                  | Example                  |
/// | ------- | ---------------------- | ------------------------ |
/// | Linux   | `XDG_DOWNLOAD_DIR`     | /home/alice/Downloads    |
/// | macOS   | `$HOME`/Downloads      | /Users/Alice/Downloads   |
/// | Windows | `{FOLDERID_Downloads}` | C:\Users\Alice\Downloads |
pub fn download_dir() -> Option<PathBuf> {
    sys::download_dir()
}
/// Returns the path to the user's font directory.
///
/// The returned value depends on the operating system and is either a `Some`, containing a value from the following table, or a `None`.
///
/// |Platform | Value                                                | Example                        |
/// | ------- | ---------------------------------------------------- | ------------------------------ |
/// | Linux   | `$XDG_DATA_HOME`/fonts or `$HOME`/.local/share/fonts | /home/alice/.local/share/fonts |
/// | macOS   | `$HOME/Library/Fonts`                                | /Users/Alice/Library/Fonts     |
/// | Windows | –                                                    | –                              |
pub fn font_dir() -> Option<PathBuf> {
    sys::font_dir()
}
/// Returns the path to the user's picture directory.
///
/// The returned value depends on the operating system and is either a `Some`, containing a value from the following table, or a `None`.
///
/// |Platform | Value                 | Example                 |
/// | ------- | --------------------- | ----------------------- |
/// | Linux   | `XDG_PICTURES_DIR`    | /home/alice/Pictures    |
/// | macOS   | `$HOME`/Pictures      | /Users/Alice/Pictures   |
/// | Windows | `{FOLDERID_Pictures}` | C:\Users\Alice\Pictures |
pub fn picture_dir() -> Option<PathBuf> {
    sys::picture_dir()
}
/// Returns the path to the user's public directory.
///
/// The returned value depends on the operating system and is either a `Some`, containing a value from the following table, or a `None`.
///
/// |Platform | Value                 | Example             |
/// | ------- | --------------------- | ------------------- |
/// | Linux   | `XDG_PUBLICSHARE_DIR` | /home/alice/Public  |
/// | macOS   | `$HOME`/Public        | /Users/Alice/Public |
/// | Windows | `{FOLDERID_Public}`   | C:\Users\Public     |
pub fn public_dir() -> Option<PathBuf> {
    sys::public_dir()
}
/// Returns the path to the user's template directory.
///
/// The returned value depends on the operating system and is either a `Some`, containing a value from the following table, or a `None`.
///
/// |Platform | Value                  | Example                                                    |
/// | ------- | ---------------------- | ---------------------------------------------------------- |
/// | Linux   | `XDG_TEMPLATES_DIR`    | /home/alice/Templates                                      |
/// | macOS   | –                      | –                                                          |
/// | Windows | `{FOLDERID_Templates}` | C:\Users\Alice\AppData\Roaming\Microsoft\Windows\Templates |
pub fn template_dir() -> Option<PathBuf> {
    sys::template_dir()
}

/// Returns the path to the user's video directory.
///
/// The returned value depends on the operating system and is either a `Some`, containing a value from the following table, or a `None`.
///
/// |Platform | Value               | Example               |
/// | ------- | ------------------- | --------------------- |
/// | Linux   | `XDG_VIDEOS_DIR`    | /home/alice/Videos    |
/// | macOS   | `$HOME`/Movies      | /Users/Alice/Movies   |
/// | Windows | `{FOLDERID_Videos}` | C:\Users\Alice\Videos |
pub fn video_dir() -> Option<PathBuf> {
    sys::video_dir()
}

#[cfg(test)]
mod tests {
    #[test]
    fn test_dirs() {
        println!("home_dir:       {:?}", ::home_dir());
        println!("cache_dir:      {:?}", ::cache_dir());
        println!("config_dir:     {:?}", ::config_dir());
        println!("data_dir:       {:?}", ::data_dir());
        println!("data_local_dir: {:?}", ::data_local_dir());
        println!("executable_dir: {:?}", ::executable_dir());
        println!("runtime_dir:    {:?}", ::runtime_dir());
        println!("audio_dir:      {:?}", ::audio_dir());
        println!("home_dir:       {:?}", ::desktop_dir());
        println!("cache_dir:      {:?}", ::document_dir());
        println!("config_dir:     {:?}", ::download_dir());
        println!("font_dir:       {:?}", ::font_dir());
        println!("picture_dir:    {:?}", ::picture_dir());
        println!("public_dir:     {:?}", ::public_dir());
        println!("template_dir:   {:?}", ::template_dir());
        println!("video_dir:      {:?}", ::video_dir());
    }
}
<commit_msg>Add support for iOS<commit_after>//! The _dirs_ crate is
//!
//! - a tiny library with a minimal API (16 functions)
//! - that provides the platform-specific, user-accessible locations
//! - for finding and storing configuration, cache and other data
//! - on Linux, Redox, Windows (≥ Vista) and macOS.
//!
//! The library provides the location of these directories by leveraging the mechanisms defined by
//!
//! - the [XDG base directory](https://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html) and the [XDG user directory](https://www.freedesktop.org/wiki/Software/xdg-user-dirs/) specifications on Linux,
//! - the [Known Folder](https://msdn.microsoft.com/en-us/library/windows/desktop/bb776911(v=vs.85).aspx) system on Windows, and
//! - the [Standard Directories](https://developer.apple.com/library/content/documentation/FileManagement/Conceptual/FileSystemProgrammingGuide/FileSystemOverview/FileSystemOverview.html#//apple_ref/doc/uid/TP40010672-CH2-SW6) on macOS.

#![deny(missing_docs)]

#[macro_use]
extern crate cfg_if;

use std::path::PathBuf;

cfg_if! {
    if #[cfg(target_os = "windows")] {
        mod win;
        use win as sys;
    } else if #[cfg(any(target_os = "macos", target_os = "ios"))] {
        mod mac;
        use mac as sys;
    } else if #[cfg(target_os = "wasi")] {
        mod wasi;
        use wasi as sys;
    } else {
        mod lin;
        use lin as sys;
    }
}

/// Returns the path to the user's home directory.
///
/// The returned value depends on the operating system and is either a `Some`, containing a value from the following table, or a `None`.
///
/// |Platform | Value                | Example        |
/// | ------- | -------------------- | -------------- |
/// | Linux   | `$HOME`              | /home/alice    |
/// | macOS   | `$HOME`              | /Users/Alice   |
/// | Windows | `{FOLDERID_Profile}` | C:\Users\Alice |
///
/// ### Linux and macOS:
///
/// - Use `$HOME` if it is set and not empty.
/// - If `$HOME` is not set or empty, then the function `getpwuid_r` is used to determine
///   the home directory of the current user.
/// - If `getpwuid_r` lacks an entry for the current user id or the home directory field is empty,
///   then the function returns `None`.
///
/// ### Windows:
///
/// This function retrieves the user profile folder using `SHGetKnownFolderPath`.
///
/// All the examples on this page mentioning `$HOME` use this behavior.
///
/// _Note:_ This function's behavior differs from [`std::env::home_dir`],
/// which works incorrectly on Linux, macOS and Windows.
///
/// [`std::env::home_dir`]: https://doc.rust-lang.org/std/env/fn.home_dir.html
pub fn home_dir() -> Option<PathBuf> {
    sys::home_dir()
}
/// Returns the path to the user's cache directory.
///
/// The returned value depends on the operating system and is either a `Some`, containing a value from the following table, or a `None`.
///
/// |Platform | Value                               | Example                      |
/// | ------- | ----------------------------------- | ---------------------------- |
/// | Linux   | `$XDG_CACHE_HOME` or `$HOME`/.cache | /home/alice/.cache           |
/// | macOS   | `$HOME`/Library/Caches              | /Users/Alice/Library/Caches  |
/// | Windows | `{FOLDERID_LocalAppData}`           | C:\Users\Alice\AppData\Local |
pub fn cache_dir() -> Option<PathBuf> {
    sys::cache_dir()
}
/// Returns the path to the user's config directory.
///
/// The returned value depends on the operating system and is either a `Some`, containing a value from the following table, or a `None`.
///
/// |Platform | Value                                 | Example                          |
/// | ------- | ------------------------------------- | -------------------------------- |
/// | Linux   | `$XDG_CONFIG_HOME` or `$HOME`/.config | /home/alice/.config              |
/// | macOS   | `$HOME`/Library/Preferences           | /Users/Alice/Library/Preferences |
/// | Windows | `{FOLDERID_RoamingAppData}`           | C:\Users\Alice\AppData\Roaming   |
pub fn config_dir() -> Option<PathBuf> {
    sys::config_dir()
}
/// Returns the path to the user's data directory.
///
/// The returned value depends on the operating system and is either a `Some`, containing a value from the following table, or a `None`.
///
/// |Platform | Value                                    | Example                                  |
/// | ------- | ---------------------------------------- | ---------------------------------------- |
/// | Linux   | `$XDG_DATA_HOME` or `$HOME`/.local/share | /home/alice/.local/share                 |
/// | macOS   | `$HOME`/Library/Application Support      | /Users/Alice/Library/Application Support |
/// | Windows | `{FOLDERID_RoamingAppData}`              | C:\Users\Alice\AppData\Roaming           |
pub fn data_dir() -> Option<PathBuf> {
    sys::data_dir()
}
/// Returns the path to the user's local data directory.
///
/// The returned value depends on the operating system and is either a `Some`, containing a value from the following table, or a `None`.
///
/// |Platform | Value                                    | Example                                  |
/// | ------- | ---------------------------------------- | ---------------------------------------- |
/// | Linux   | `$XDG_DATA_HOME` or `$HOME`/.local/share | /home/alice/.local/share                 |
/// | macOS   | `$HOME`/Library/Application Support      | /Users/Alice/Library/Application Support |
/// | Windows | `{FOLDERID_LocalAppData}`                | C:\Users\Alice\AppData\Local             |
pub fn data_local_dir() -> Option<PathBuf> {
    sys::data_local_dir()
}
/// Returns the path to the user's executable directory.
///
/// The returned value depends on the operating system and is either a `Some`, containing a value from the following table, or a `None`.
///
/// |Platform | Value                                                            | Example                |
/// | ------- | ---------------------------------------------------------------- | ---------------------- |
/// | Linux   | `$XDG_BIN_HOME` or `$XDG_DATA_HOME`/../bin or `$HOME`/.local/bin | /home/alice/.local/bin |
/// | macOS   | –                                                                | –                      |
/// | Windows | –                                                                | –                      |
pub fn executable_dir() -> Option<PathBuf> {
    sys::executable_dir()
}
/// Returns the path to the user's runtime directory.
///
/// The returned value depends on the operating system and is either a `Some`, containing a value from the following table, or a `None`.
///
/// |Platform | Value              | Example         |
/// | ------- | ------------------ | --------------- |
/// | Linux   | `$XDG_RUNTIME_DIR` | /run/user/1001/ |
/// | macOS   | –                  | –               |
/// | Windows | –                  | –               |
pub fn runtime_dir() -> Option<PathBuf> {
    sys::runtime_dir()
}

/// Returns the path to the user's audio directory.
///
/// The returned value depends on the operating system and is either a `Some`, containing a value from the following table, or a `None`.
///
/// |Platform | Value              | Example              |
/// | ------- | ------------------ | -------------------- |
/// | Linux   | `XDG_MUSIC_DIR`    | /home/alice/Music    |
/// | macOS   | `$HOME`/Music      | /Users/Alice/Music   |
/// | Windows | `{FOLDERID_Music}` | C:\Users\Alice\Music |
pub fn audio_dir() -> Option<PathBuf> {
    sys::audio_dir()
}
/// Returns the path to the user's desktop directory.
///
/// The returned value depends on the operating system and is either a `Some`, containing a value from the following table, or a `None`.
///
/// |Platform | Value                | Example                |
/// | ------- | -------------------- | ---------------------- |
/// | Linux   | `XDG_DESKTOP_DIR`    | /home/alice/Desktop    |
/// | macOS   | `$HOME`/Desktop      | /Users/Alice/Desktop   |
/// | Windows | `{FOLDERID_Desktop}` | C:\Users\Alice\Desktop |
pub fn desktop_dir() -> Option<PathBuf> {
    sys::desktop_dir()
}
/// Returns the path to the user's document directory.
///
/// The returned value depends on the operating system and is either a `Some`, containing a value from the following table, or a `None`.
///
/// |Platform | Value                  | Example                  |
/// | ------- | ---------------------- | ------------------------ |
/// | Linux   | `XDG_DOCUMENTS_DIR`    | /home/alice/Documents    |
/// | macOS   | `$HOME`/Documents      | /Users/Alice/Documents   |
/// | Windows | `{FOLDERID_Documents}` | C:\Users\Alice\Documents |
pub fn document_dir() -> Option<PathBuf> {
    sys::document_dir()
}
/// Returns the path to the user's download directory.
///
/// The returned value depends on the operating system and is either a `Some`, containing a value from the following table, or a `None`.
///
/// |Platform | Value                  | Example                  |
/// | ------- | ---------------------- | ------------------------ |
/// | Linux   | `XDG_DOWNLOAD_DIR`     | /home/alice/Downloads    |
/// | macOS   | `$HOME`/Downloads      | /Users/Alice/Downloads   |
/// | Windows | `{FOLDERID_Downloads}` | C:\Users\Alice\Downloads |
pub fn download_dir() -> Option<PathBuf> {
    sys::download_dir()
}
/// Returns the path to the user's font directory.
///
/// The returned value depends on the operating system and is either a `Some`, containing a value from the following table, or a `None`.
///
/// |Platform | Value                                                | Example                        |
/// | ------- | ---------------------------------------------------- | ------------------------------ |
/// | Linux   | `$XDG_DATA_HOME`/fonts or `$HOME`/.local/share/fonts | /home/alice/.local/share/fonts |
/// | macOS   | `$HOME/Library/Fonts`                                | /Users/Alice/Library/Fonts     |
/// | Windows | –                                                    | –                              |
pub fn font_dir() -> Option<PathBuf> {
    sys::font_dir()
}
/// Returns the path to the user's picture directory.
///
/// The returned value depends on the operating system and is either a `Some`, containing a value from the following table, or a `None`.
///
/// |Platform | Value                 | Example                 |
/// | ------- | --------------------- | ----------------------- |
/// | Linux   | `XDG_PICTURES_DIR`    | /home/alice/Pictures    |
/// | macOS   | `$HOME`/Pictures      | /Users/Alice/Pictures   |
/// | Windows | `{FOLDERID_Pictures}` | C:\Users\Alice\Pictures |
pub fn picture_dir() -> Option<PathBuf> {
    sys::picture_dir()
}
/// Returns the path to the user's public directory.
///
/// The returned value depends on the operating system and is either a `Some`, containing a value from the following table, or a `None`.
///
/// |Platform | Value                 | Example             |
/// | ------- | --------------------- | ------------------- |
/// | Linux   | `XDG_PUBLICSHARE_DIR` | /home/alice/Public  |
/// | macOS   | `$HOME`/Public        | /Users/Alice/Public |
/// | Windows | `{FOLDERID_Public}`   | C:\Users\Public     |
pub fn public_dir() -> Option<PathBuf> {
    sys::public_dir()
}
/// Returns the path to the user's template directory.
///
/// The returned value depends on the operating system and is either a `Some`, containing a value from the following table, or a `None`.
///
/// |Platform | Value                  | Example                                                    |
/// | ------- | ---------------------- | ---------------------------------------------------------- |
/// | Linux   | `XDG_TEMPLATES_DIR`    | /home/alice/Templates                                      |
/// | macOS   | –                      | –                                                          |
/// | Windows | `{FOLDERID_Templates}` | C:\Users\Alice\AppData\Roaming\Microsoft\Windows\Templates |
pub fn template_dir() -> Option<PathBuf> {
    sys::template_dir()
}

/// Returns the path to the user's video directory.
///
/// The returned value depends on the operating system and is either a `Some`, containing a value from the following table, or a `None`.
///
/// |Platform | Value               | Example               |
/// | ------- | ------------------- | --------------------- |
/// | Linux   | `XDG_VIDEOS_DIR`    | /home/alice/Videos    |
/// | macOS   | `$HOME`/Movies      | /Users/Alice/Movies   |
/// | Windows | `{FOLDERID_Videos}` | C:\Users\Alice\Videos |
pub fn video_dir() -> Option<PathBuf> {
    sys::video_dir()
}

#[cfg(test)]
mod tests {
    #[test]
    fn test_dirs() {
        println!("home_dir:       {:?}", ::home_dir());
        println!("cache_dir:      {:?}", ::cache_dir());
        println!("config_dir:     {:?}", ::config_dir());
        println!("data_dir:       {:?}", ::data_dir());
        println!("data_local_dir: {:?}", ::data_local_dir());
        println!("executable_dir: {:?}", ::executable_dir());
        println!("runtime_dir:    {:?}", ::runtime_dir());
        println!("audio_dir:      {:?}", ::audio_dir());
        println!("home_dir:       {:?}", ::desktop_dir());
        println!("cache_dir:      {:?}", ::document_dir());
        println!("config_dir:     {:?}", ::download_dir());
        println!("font_dir:       {:?}", ::font_dir());
        println!("picture_dir:    {:?}", ::picture_dir());
        println!("public_dir:     {:?}", ::public_dir());
        println!("template_dir:   {:?}", ::template_dir());
        println!("video_dir:      {:?}", ::video_dir());
    }
}
<|endoftext|>


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

extern crate libc;

use libc::{int32_t, uint32_t};
use std::{slice, str};
use std::ffi::{CStr, CString};

mod ffi;

#[repr(C)]
pub enum ShaderKind {
    GlslVertex,
    GlslFragment,
    GlslCompute,
    GlslGeometry,
    GlslTessControl,
    GlslTessEvaluation,

    GlslInferFromSource,

    GlslDefaultVertex,
    GlslDefaultFragment,
    GlslDefaultCompute,
    GlslDefaultGeometry,
    GlslDefaultTessControl,
    GlslDefaultTessEvaluation,

    SpirvAssembly,
}

pub struct Compiler {
    raw: *mut ffi::ShadercCompiler,
}

impl Compiler {
    pub fn new() -> Compiler {
        Compiler { raw: unsafe { ffi::shaderc_compiler_initialize() } }
    }

    pub fn compile_into_spirv(&mut self,
                              source_text: String,
                              shader_kind: ShaderKind,
                              input_file_name: String,
                              entry_point_name: String,
                              additional_options: &CompileOptions)
                              -> CompilationResult {
        let source_size = source_text.len();
        let c_source = CString::new(source_text).expect("cannot convert source to c string");
        let c_file = CString::new(input_file_name)
                         .expect("cannot convert input_file_name to c string");
        let c_entry_point = CString::new(entry_point_name)
                                .expect("cannot convert entry_point_name to c string");
        let result = unsafe {
            ffi::shaderc_compile_into_spv(self.raw,
                                          c_source.as_ptr(),
                                          source_size,
                                          shader_kind as int32_t,
                                          c_file.as_ptr(),
                                          c_entry_point.as_ptr(),
                                          additional_options.raw)
        };
        CompilationResult::new(result, true)
    }

    pub fn compile_into_spirv_assembly(&mut self,
                                       source_text: String,
                                       shader_kind: ShaderKind,
                                       input_file_name: String,
                                       entry_point_name: String,
                                       additional_options: &CompileOptions)
                                       -> CompilationResult {
        let source_size = source_text.len();
        let c_source = CString::new(source_text).expect("cannot convert source to c string");
        let c_file = CString::new(input_file_name)
                         .expect("cannot convert input_file_name to c string");
        let c_entry_point = CString::new(entry_point_name)
                                .expect("cannot convert entry_point_name to c string");
        let result = unsafe {
            ffi::shaderc_compile_into_spv_assembly(self.raw,
                                                   c_source.as_ptr(),
                                                   source_size,
                                                   shader_kind as int32_t,
                                                   c_file.as_ptr(),
                                                   c_entry_point.as_ptr(),
                                                   additional_options.raw)
        };
        CompilationResult::new(result, false)
    }
}

impl Drop for Compiler {
    fn drop(&mut self) {
        unsafe { ffi::shaderc_compiler_release(self.raw) }
    }
}

pub struct CompileOptions {
    raw: *mut ffi::ShadercCompileOptions,
}

impl CompileOptions {
    fn new() -> CompileOptions {
        CompileOptions { raw: unsafe { ffi::shaderc_compile_options_initialize() } }
    }

    fn clone(&self) -> CompileOptions {
        CompileOptions { raw: unsafe { ffi::shaderc_compile_options_clone(self.raw) } }
    }
}

impl Drop for CompileOptions {
    fn drop(&mut self) {
        unsafe { ffi::shaderc_compile_options_release(self.raw) }
    }
}

pub struct CompilationResult {
    raw: *mut ffi::ShadercCompilationResult,
    is_binary: bool,
}

impl CompilationResult {
    fn new(result: *mut ffi::ShadercCompilationResult, is_binary: bool) -> CompilationResult {
        CompilationResult {
            raw: result,
            is_binary: is_binary,
        }
    }

    pub fn len(&self) -> usize {
        unsafe { ffi::shaderc_result_get_length(self.raw) }
    }

    pub fn as_binary(&self) -> &[u32] {
        assert!(self.is_binary);

        let num_words = self.len() / 4;

        unsafe {
            let p = ffi::shaderc_result_get_bytes(self.raw);
            slice::from_raw_parts(p as *const uint32_t, num_words)
        }
    }

    pub fn as_text(&self) -> String {
        assert!(!self.is_binary);
        unsafe {
            let p = ffi::shaderc_result_get_bytes(self.raw);
            let bytes = CStr::from_ptr(p).to_bytes();
            str::from_utf8(bytes).ok().expect("invalid utf-8 string").to_string()
        }
    }
}

impl Drop for CompilationResult {
    fn drop(&mut self) {
        unsafe { ffi::shaderc_result_release(self.raw) }
    }
}

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

    static VOID_MAIN: &'static str = "#version 310 es\nvoid main() {}";
    static VOID_MAIN_ASSEMBLY: &'static str = "\
; SPIR-V
; Version: 1.0
; Generator: Google Shaderc over Glslang; 1
; Bound: 6
; Schema: 0
               OpCapability Shader
          %1 = OpExtInstImport \"GLSL.std.450\"
               OpMemoryModel Logical GLSL450
               OpEntryPoint Vertex %main \"main\"
               OpSource ESSL 310
               OpSourceExtension \"GL_GOOGLE_cpp_style_line_directive\"
               OpSourceExtension \"GL_GOOGLE_include_directive\"
               OpName %main \"main\"
       %void = OpTypeVoid
          %3 = OpTypeFunction %void
       %main = OpFunction %void None %3
          %5 = OpLabel
               OpReturn
               OpFunctionEnd
";

    #[test]
    fn compile_vertex_shader_into_spirv() {
        let source = VOID_MAIN.to_string();
        let file = "shader.glsl".to_string();
        let entry_point = "main".to_string();

        let mut c = Compiler::new();
        let options = CompileOptions::new();
        let result = c.compile_into_spirv(source,
                                          ShaderKind::GlslVertex,
                                          file,
                                          entry_point,
                                          &options);
        assert!(result.len() > 20);
        assert!(result.as_binary().first() == Some(&0x07230203));
        let function_end_word: u32 = (1 << 16) | 56;
        assert!(result.as_binary().last() == Some(&function_end_word));
    }

    #[test]
    fn compile_vertex_shader_into_spirv_assembly() {
        let source = VOID_MAIN.to_string();
        let file = "shader.glsl".to_string();
        let entry_point = "main".to_string();

        let mut c = Compiler::new();
        let options = CompileOptions::new();
        let result = c.compile_into_spirv_assembly(source,
                                                   ShaderKind::GlslVertex,
                                                   file,
                                                   entry_point,
                                                   &options);
        assert_eq!(VOID_MAIN_ASSEMBLY, result.as_text());
    }
}
<commit_msg>Add comments for ShaderKind, compiler, options, and result.<commit_after>// Copyright 2016 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

extern crate libc;

use libc::{int32_t, uint32_t};
use std::{slice, str};
use std::ffi::{CStr, CString};

mod ffi;

/// Shader kind.
///
/// * The `Glsl<stage>` enumerants are forced shader kinds, which force the
///   compiler to compile the source code as the specified kind of shader,
///   regardless of `#pragma` annotations in the source code.
/// * The `GlslDefault<stage>` enumerants are default shader kinds, which
///   allow the compiler to fall back to compile the source code as the
///   specified kind of shader when `#pragma` is not found in the source
///   code.
#[repr(C)]
pub enum ShaderKind {
    GlslVertex,
    GlslFragment,
    GlslCompute,
    GlslGeometry,
    GlslTessControl,
    GlslTessEvaluation,

    /// Deduce the shader kind from `#pragma` annotation in the source code.
    ///
    /// Compiler will emit error if `#pragma` annotation is not found.
    GlslInferFromSource,

    GlslDefaultVertex,
    GlslDefaultFragment,
    GlslDefaultCompute,
    GlslDefaultGeometry,
    GlslDefaultTessControl,
    GlslDefaultTessEvaluation,

    SpirvAssembly,
}

/// An opaque object managing all compiler states.
pub struct Compiler {
    raw: *mut ffi::ShadercCompiler,
}

impl Compiler {
    pub fn new() -> Compiler {
        Compiler { raw: unsafe { ffi::shaderc_compiler_initialize() } }
    }

    pub fn compile_into_spirv(&mut self,
                              source_text: String,
                              shader_kind: ShaderKind,
                              input_file_name: String,
                              entry_point_name: String,
                              additional_options: &CompileOptions)
                              -> CompilationResult {
        let source_size = source_text.len();
        let c_source = CString::new(source_text).expect("cannot convert source to c string");
        let c_file = CString::new(input_file_name)
                         .expect("cannot convert input_file_name to c string");
        let c_entry_point = CString::new(entry_point_name)
                                .expect("cannot convert entry_point_name to c string");
        let result = unsafe {
            ffi::shaderc_compile_into_spv(self.raw,
                                          c_source.as_ptr(),
                                          source_size,
                                          shader_kind as int32_t,
                                          c_file.as_ptr(),
                                          c_entry_point.as_ptr(),
                                          additional_options.raw)
        };
        CompilationResult::new(result, true)
    }

    pub fn compile_into_spirv_assembly(&mut self,
                                       source_text: String,
                                       shader_kind: ShaderKind,
                                       input_file_name: String,
                                       entry_point_name: String,
                                       additional_options: &CompileOptions)
                                       -> CompilationResult {
        let source_size = source_text.len();
        let c_source = CString::new(source_text).expect("cannot convert source to c string");
        let c_file = CString::new(input_file_name)
                         .expect("cannot convert input_file_name to c string");
        let c_entry_point = CString::new(entry_point_name)
                                .expect("cannot convert entry_point_name to c string");
        let result = unsafe {
            ffi::shaderc_compile_into_spv_assembly(self.raw,
                                                   c_source.as_ptr(),
                                                   source_size,
                                                   shader_kind as int32_t,
                                                   c_file.as_ptr(),
                                                   c_entry_point.as_ptr(),
                                                   additional_options.raw)
        };
        CompilationResult::new(result, false)
    }
}

impl Drop for Compiler {
    fn drop(&mut self) {
        unsafe { ffi::shaderc_compiler_release(self.raw) }
    }
}

/// An opaque object managing options to compilation.
pub struct CompileOptions {
    raw: *mut ffi::ShadercCompileOptions,
}

impl CompileOptions {
    fn new() -> CompileOptions {
        CompileOptions { raw: unsafe { ffi::shaderc_compile_options_initialize() } }
    }

    fn clone(&self) -> CompileOptions {
        CompileOptions { raw: unsafe { ffi::shaderc_compile_options_clone(self.raw) } }
    }
}

impl Drop for CompileOptions {
    fn drop(&mut self) {
        unsafe { ffi::shaderc_compile_options_release(self.raw) }
    }
}

/// An opaque object containing the results of compilation.
pub struct CompilationResult {
    raw: *mut ffi::ShadercCompilationResult,
    is_binary: bool,
}

impl CompilationResult {
    fn new(result: *mut ffi::ShadercCompilationResult, is_binary: bool) -> CompilationResult {
        CompilationResult {
            raw: result,
            is_binary: is_binary,
        }
    }

    pub fn len(&self) -> usize {
        unsafe { ffi::shaderc_result_get_length(self.raw) }
    }

    pub fn as_binary(&self) -> &[u32] {
        assert!(self.is_binary);

        let num_words = self.len() / 4;

        unsafe {
            let p = ffi::shaderc_result_get_bytes(self.raw);
            slice::from_raw_parts(p as *const uint32_t, num_words)
        }
    }

    pub fn as_text(&self) -> String {
        assert!(!self.is_binary);
        unsafe {
            let p = ffi::shaderc_result_get_bytes(self.raw);
            let bytes = CStr::from_ptr(p).to_bytes();
            str::from_utf8(bytes).ok().expect("invalid utf-8 string").to_string()
        }
    }
}

impl Drop for CompilationResult {
    fn drop(&mut self) {
        unsafe { ffi::shaderc_result_release(self.raw) }
    }
}

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

    static VOID_MAIN: &'static str = "#version 310 es\nvoid main() {}";
    static VOID_MAIN_ASSEMBLY: &'static str = "\
; SPIR-V
; Version: 1.0
; Generator: Google Shaderc over Glslang; 1
; Bound: 6
; Schema: 0
               OpCapability Shader
          %1 = OpExtInstImport \"GLSL.std.450\"
               OpMemoryModel Logical GLSL450
               OpEntryPoint Vertex %main \"main\"
               OpSource ESSL 310
               OpSourceExtension \"GL_GOOGLE_cpp_style_line_directive\"
               OpSourceExtension \"GL_GOOGLE_include_directive\"
               OpName %main \"main\"
       %void = OpTypeVoid
          %3 = OpTypeFunction %void
       %main = OpFunction %void None %3
          %5 = OpLabel
               OpReturn
               OpFunctionEnd
";

    #[test]
    fn compile_vertex_shader_into_spirv() {
        let source = VOID_MAIN.to_string();
        let file = "shader.glsl".to_string();
        let entry_point = "main".to_string();

        let mut c = Compiler::new();
        let options = CompileOptions::new();
        let result = c.compile_into_spirv(source,
                                          ShaderKind::GlslVertex,
                                          file,
                                          entry_point,
                                          &options);
        assert!(result.len() > 20);
        assert!(result.as_binary().first() == Some(&0x07230203));
        let function_end_word: u32 = (1 << 16) | 56;
        assert!(result.as_binary().last() == Some(&function_end_word));
    }

    #[test]
    fn compile_vertex_shader_into_spirv_assembly() {
        let source = VOID_MAIN.to_string();
        let file = "shader.glsl".to_string();
        let entry_point = "main".to_string();

        let mut c = Compiler::new();
        let options = CompileOptions::new();
        let result = c.compile_into_spirv_assembly(source,
                                                   ShaderKind::GlslVertex,
                                                   file,
                                                   entry_point,
                                                   &options);
        assert_eq!(VOID_MAIN_ASSEMBLY, result.as_text());
    }
}
<|endoftext|>


<commit_before>//! An implementation of [FLAC](https://xiph.org/flac), free lossless audio
//! codec, written in Rust.
//!
//! The code is available on [GitHub](https://github.com/sourrust/flac).
//!
//! # Examples
//!
//! Basic decoding from a file.
//!
//! ```
//! use flac::StreamReader;
//! use std::fs::File;
//!
//! match StreamReader::<File>::from_file("path/to/file.flac") {
//!   Ok(mut stream) => {
//!     // Copy of `StreamInfo` to help convert to a different audio format.
//!     let info = stream.info();
//!
//!     for sample in stream.iter() {
//!       // Iterate over each decoded sample
//!     }
//!   }
//!   Err(error)     => println!("{}", error),
//! }
//! ```

#[macro_use]
extern crate nom;

#[macro_use]
mod utility;
mod frame;
mod subframe;
pub mod metadata;
pub mod stream;

pub use metadata::Metadata;
pub use stream::{Stream, StreamBuffer, StreamReader};
pub use utility::{StreamProducer, ReadStream, ByteStream};
<commit_msg>Export `ErrorKind`<commit_after>//! An implementation of [FLAC](https://xiph.org/flac), free lossless audio
//! codec, written in Rust.
//!
//! The code is available on [GitHub](https://github.com/sourrust/flac).
//!
//! # Examples
//!
//! Basic decoding from a file.
//!
//! ```
//! use flac::StreamReader;
//! use std::fs::File;
//!
//! match StreamReader::<File>::from_file("path/to/file.flac") {
//!   Ok(mut stream) => {
//!     // Copy of `StreamInfo` to help convert to a different audio format.
//!     let info = stream.info();
//!
//!     for sample in stream.iter() {
//!       // Iterate over each decoded sample
//!     }
//!   }
//!   Err(error)     => println!("{}", error),
//! }
//! ```

#[macro_use]
extern crate nom;

#[macro_use]
mod utility;
mod frame;
mod subframe;
pub mod metadata;
pub mod stream;

pub use metadata::Metadata;
pub use stream::{Stream, StreamBuffer, StreamReader};
pub use utility::{StreamProducer, ReadStream, ByteStream, ErrorKind};
<|endoftext|>


<commit_before>#![feature(no_std,lang_items,asm,core,alloc,collections)]
#![no_std]

#![crate_type="staticlib"]
#![crate_name="rustcode"]

#[macro_use]
extern crate core;
extern crate alloc;
extern crate collections;

use core::prelude::*;
use alloc::boxed::Box;
use collections::string::String;

extern crate rlibc;

#[macro_use]
mod notex;

mod machine;
mod vga;
mod mmu;
mod gdt;
mod idt;
mod interrupts;
mod paging;
mod malloc;

use vga::Color::*;

pub use idt::{idtDesc};
pub use interrupts::{double_fault_handler, gpf_handler,
                     page_fault_handler, kbd_interrupt_handler };
pub use malloc::{rust_allocate, rust_reallocate, rust_reallocate_inplace,
                 rust_deallocate, rust_usable_size, rust_stats_print };

#[lang="start"]
#[no_mangle]
pub fn k_main() {
    idt::init();
    interrupts::init();
    paging::init();

    let greet = "Hello from bare-bones Rust";

    for i in 0..vga::ROWS {
        for j in 0..vga::COLS {
            vga::write_char_with_color(i, j, ' ', White, LightBlue);
        }
    }
    vga::paint_color(0, 0, 30, White, LightGreen);
    vga::write_string(10, 5, greet);
    vga::move_cursor(10, 5 + greet.len());
    vga::write_string_with_color(11, 10, "Test", Black, LightRed);
    unsafe {
        asm! {
            "int $0\n"
                :: "N"(0x50)
        }
    }
    let heap = Box::new('H');
    let heap2 = Box::new('!');
    vga::write_char(15,4,*heap);
    vga::write_char_with_color(15, 5, *heap2, LightGray, Pink);

    let mut string = String::new();
    string.push_str("Hello, ");
    string.push_str("paging");
    vga::write_string(3,5,&string);
    unsafe { *(0xB0_00_00_01 as *mut u32) = 0xcafecafe; }
    unsafe { *(0xA0_00_10_00 as *mut mmu::Descriptor) = gdt::gdt_get(1); }
}

#[lang = "stack_exhausted"] extern fn stack_exhausted() {}
#[lang = "eh_personality"] extern fn eh_personality() {}
#[lang = "panic_fmt"] fn panic_fmt() -> ! { loop {} }

#[no_mangle]
#[allow(non_snake_case)]
pub fn _Unwind_Resume()
{
        loop{}
}
<commit_msg>Rework the string case a bit<commit_after>#![feature(no_std,lang_items,asm,core,alloc,collections)]
#![no_std]

#![crate_type="staticlib"]
#![crate_name="rustcode"]

#[macro_use]
extern crate core;
extern crate alloc;
extern crate collections;

use core::prelude::*;
use alloc::boxed::Box;
use collections::string::String;

extern crate rlibc;

#[macro_use]
mod notex;

mod machine;
mod vga;
mod mmu;
mod gdt;
mod idt;
mod interrupts;
mod paging;
mod malloc;

use vga::Color::*;

pub use idt::{idtDesc};
pub use interrupts::{double_fault_handler, gpf_handler,
                     page_fault_handler, kbd_interrupt_handler };
pub use malloc::{rust_allocate, rust_reallocate, rust_reallocate_inplace,
                 rust_deallocate, rust_usable_size, rust_stats_print };

#[lang="start"]
#[no_mangle]
pub fn k_main() {
    idt::init();
    interrupts::init();
    paging::init();

    let greet = "Hello from bare-bones Rust";

    for i in 0..vga::ROWS {
        for j in 0..vga::COLS {
            vga::write_char_with_color(i, j, ' ', White, LightBlue);
        }
    }
    vga::paint_color(0, 0, 30, White, LightGreen);
    vga::write_string(10, 5, greet);
    vga::move_cursor(10, 5 + greet.len());
    vga::write_string_with_color(11, 10, "Test", Black, LightRed);
    unsafe {
        asm! {
            "int $0\n"
                :: "N"(0x50)
        }
    }
    let heap = Box::new('H');
    let heap2 = Box::new('!');
    vga::write_char(15,4,*heap);
    vga::write_char_with_color(15, 5, *heap2, LightGray, Pink);

    let mut string = String::from_str("Hello, ");
    string.push_str("paging");
    vga::write_string(3,5,&string);
    unsafe { *(0xB0_00_00_01 as *mut u32) = 0xcafecafe; }
    unsafe { *(0xA0_00_10_00 as *mut mmu::Descriptor) = gdt::gdt_get(1); }
}

#[lang = "stack_exhausted"] extern fn stack_exhausted() {}
#[lang = "eh_personality"] extern fn eh_personality() {}
#[lang = "panic_fmt"] fn panic_fmt() -> ! { loop {} }

#[no_mangle]
#[allow(non_snake_case)]
pub fn _Unwind_Resume()
{
        loop{}
}
<|endoftext|>


<commit_before>//! perlin is a free and open source search engine library build on top of
//! perlin-core
//!
//! It aims to be fast for typical human consumption of search results (e.g.
//! ten at a time).
//!
//! The previously released version 0.1 differs massively from this. Please
//! refer to tag 'v0.1' for the code  and
//! [https://doc.perlin-ir.org/v0.1/perlin/index.html] for documentation

extern crate perlin_core;

mod document;
mod document_index;
pub mod field;

pub use document::Document;
pub use document_index::DocumentIndex;

#[cfg(test)]
pub mod test_utils;
<commit_msg>made document builder public<commit_after>//! perlin is a free and open source search engine library build on top of
//! perlin-core
//!
//! It aims to be fast for typical human consumption of search results (e.g.
//! ten at a time).
//!
//! The previously released version 0.1 differs massively from this. Please
//! refer to tag 'v0.1' for the code  and
//! [https://doc.perlin-ir.org/v0.1/perlin/index.html] for documentation

extern crate perlin_core;

mod document;
mod document_index;
pub mod field;

pub use document::{DocumentBuilder, Document};
pub use document_index::DocumentIndex;

#[cfg(test)]
pub mod test_utils;
<|endoftext|>


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

//! # Cap'n Proto Schema Compiler Plugin Library
//!
//! This library allows you to do [Cap'n Proto code generation]
//! (https://capnproto.org/otherlang.html#how-to-write-compiler-plugins)
//! within a Cargo build.
//!
//! In your Cargo.toml:
//!
//! ```ignore
//!   [package]
//!   build = "build.rs"
//!
//!   [build-dependencies]
//!   capnpc = "*"
//! ```
//!
//! In your build.rs:
//!
//! ```ignore
//! extern crate capnpc;
//!
//! fn main() {
//!     ::capnpc::compile("schema", &["schema/foo.capnp", "schema/bar.capnp"]).unwrap();
//! }
//! ```
//!
//! This will be equivalent to executing the shell command
//!
//! ```ignore
//!   capnp compile -orust:$OUT_DIR --src-prefix=schema schema/foo.capnp schema/bar.capnp
//! ```
//!

extern crate capnp;

/// Code generated from [schema.capnp]
/// (https://github.com/sandstorm-io/capnproto/blob/master/c%2B%2B/src/capnp/schema.capnp).
pub mod schema_capnp;

pub mod codegen;
pub mod codegen_types;
pub mod schema;

use std::path::Path;

pub fn compile<P1, P2>(src_prefix: P1, files: &[P2]) -> ::capnp::Result<()>
    where P1: AsRef<Path>, P2: AsRef<Path>
{
    let mut command = ::std::process::Command::new("capnp");
    command.arg("compile").arg("-o").arg("-")
           .arg(&format!("--src-prefix={}", src_prefix.as_ref().display()));

    for file in files {
        command.arg(&format!("{}", file.as_ref().display()));
    }

    command.stdout(::std::process::Stdio::piped());
    command.stderr(::std::process::Stdio::inherit());

    let mut p = try!(command.spawn().map_err(|error| {
        ::capnp::Error::failed(format!("Failed to execute capnp executable: {}. \
                                       See https://capnproto.org/install.html",
                                       error))}));
    try!(::codegen::main(p.stdout.take().unwrap(),
                         ::std::path::Path::new(&::std::env::var("OUT_DIR").unwrap())));
    try!(p.wait());
    return Ok(());
}

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

//! # Cap'n Proto Schema Compiler Plugin Library
//!
//! This library allows you to do [Cap'n Proto code generation]
//! (https://capnproto.org/otherlang.html#how-to-write-compiler-plugins)
//! within a Cargo build.
//!
//! In your Cargo.toml:
//!
//! ```ignore
//!   [package]
//!   build = "build.rs"
//!
//!   [build-dependencies]
//!   capnpc = "*"
//! ```
//!
//! In your build.rs:
//!
//! ```ignore
//! extern crate capnpc;
//!
//! fn main() {
//!     ::capnpc::compile("schema", &["schema/foo.capnp", "schema/bar.capnp"]).unwrap();
//! }
//! ```
//!
//! This will be equivalent to executing the shell command
//!
//! ```ignore
//!   capnp compile -orust:$OUT_DIR --src-prefix=schema schema/foo.capnp schema/bar.capnp
//! ```
//!

extern crate capnp;

/// Code generated from [schema.capnp]
/// (https://github.com/sandstorm-io/capnproto/blob/master/c%2B%2B/src/capnp/schema.capnp).
pub mod schema_capnp;

pub mod codegen;
pub mod codegen_types;
pub mod schema;

use std::path::Path;

fn run_command(mut command: ::std::process::Command) -> ::capnp::Result<()> {
    let mut p = try!(command.spawn());
    try!(::codegen::main(p.stdout.take().unwrap(),
                         ::std::path::Path::new(&::std::env::var("OUT_DIR").unwrap())));
    let exit_status = try!(p.wait());
    if !exit_status.success() {
        Err(::capnp::Error::failed(format!("Non-success exit status: {}", exit_status)))
    } else {
        Ok(())
    }
}

pub fn compile<P1, P2>(src_prefix: P1, files: &[P2]) -> ::capnp::Result<()>
    where P1: AsRef<Path>, P2: AsRef<Path>
{
    let mut command = ::std::process::Command::new("capnp");
    command.arg("compile").arg("-o").arg("-")
           .arg(&format!("--src-prefix={}", src_prefix.as_ref().display()));

    for file in files {
        command.arg(&format!("{}", file.as_ref().display()));
    }

    command.stdout(::std::process::Stdio::piped());
    command.stderr(::std::process::Stdio::inherit());

    run_command(command).map_err(|error| {
        ::capnp::Error::failed(format!("Error while trying to execute `capnp compile`: {}.  \
                                       Perhaps the capnp executable is not installed \
                                       on your system? See https://capnproto.org/install.html",
                                       error))})
}
<|endoftext|>


<commit_before>extern crate "boxdraw-rs" as boxdraw;

use boxdraw::{Undraw, Script};
use boxdraw::grid::Grid;

pub struct SimpleSearch;

impl Undraw for SimpleSearch {
    fn undraw(&self, picture: &str) -> Script {
        let mut grid = Grid::from_str(picture).unwrap();
        let w = grid.width();
        let h = grid.height();

        let mut s = Script::new(w, h);

        for x in range(0, w) {
            for y in range(0, h) {
                // Found a left-corner; find the extent of the box.
                println!("inspecting ({},{})", x, y);
                println!("char at: ({},{}): '{}'", x, y, grid.get(x, y));
                if grid.get(x, y) == '+' {
                    let mut box_w = 1;
                    for i in range(x+1, w) {
                        let c = grid.get(i, y);
                        println!("scanning across, c: '{}'", c);
                        if c == '-' {
                            continue;
                        }
                        if c == '+' {
                            box_w = i - x + 1;
                            break;
                        }
                    }

                    let mut box_h = 1;
                    for j in range(y+1, h) {
                        assert!(j < h);
                        let left = grid.get(x, j);
                        assert!(j < h);
                        let right = grid.get(x + box_w - 1, j);
                        println!("scanning down, left: '{}' right: '{}'",
                                 left, right);
                        if left == '|' && right == '|' {
                            continue
                        }
                        if left == '+' && right == '+' {
                            box_h = j - y + 1;
                            break;
                        }
                    }

                    assert!(y+1 < h);
                    let fill = grid.get(x+1, y+1);
                    let cmd = boxdraw::rect(x, y, box_w, box_h, fill);
                    s.add_end_command(cmd);

                    // Now, clear the matched area.
                    println!("clearing matched area ({},{}) of w:{} h:{}",
                             x, y, box_w, box_h);
                    for i in range(x, x+box_w) {
                        for j in range(y, y+box_h) {
                            grid.set(i, j, '?');
                        }
                    }
                }
            }
        }

        s
    }
}

#[test]
fn check_simple() {
    boxdraw::check_undraw("...\n", &SimpleSearch).unwrap();

    boxdraw::check_undraw(".....\n\
                           .+-+.\n\
                           .|b|.\n\
                           .+-+.\n\
                          ",
                          &SimpleSearch).unwrap();

    boxdraw::check_undraw(".............\n\
                           .......+--+..\n\
                           .+-+...|cc|..\n\
                           .|b|...|cc|..\n\
                           .+-+...+--+..\n\
                           .............\n\
                          ",
                          &SimpleSearch).unwrap();

    boxdraw::check_undraw(".........\n\
                           .........\n\
                           .+-+.....\n\
                           .|b|.....\n\
                           .+-+.....\n\
                           .+--+....\n\
                           .|cc|....\n\
                           .|cc|....\n\
                           .+--+....\n\
                           .........\n\
                          ",
                          &SimpleSearch).unwrap();
}

#[test]
#[should_fail]
fn too_naive_to_pass_this_yet() {
    boxdraw::check_undraw(".............\n\
                           ....+---+....\n\
                           ....|bbb|....\n\
                           ....|bb+--+..\n\
                           ....|bb|cc|..\n\
                           ....+--|cc|..\n\
                           .......+--+..\n\
                           .............\n\
                          ",
                          &SimpleSearch).unwrap();

}
<commit_msg>an improved naive undraw impl.<commit_after>#![feature(phase)]

extern crate "boxdraw-rs" as boxdraw;

#[phase(plugin)]
extern crate log;
extern crate log;

use boxdraw::{Undraw, Script};
use boxdraw::grid::Grid;

use std::char::from_u32;

pub struct SimpleSearch;

impl Undraw for SimpleSearch {
    fn undraw(&self, picture: &str) -> Script {
        debug!("undraw:\n{}", picture);

        let unused_char = self.find_unused_char(picture);

        let mut grid = Grid::from_str(picture).unwrap();
        let w = grid.width();
        let h = grid.height();

        let mut s = Script::new(w, h);

        // We find the commands in reverse order.
        let mut rev_commands = vec![];
        let mut cleared_some;
        loop {
            cleared_some = false;
            for y in range(0, h) {
                for x in range(0, w) {

                    match self.try_upper_left(&grid, unused_char, x, y) {
                        Some(cmd) => {
                            rev_commands.push(cmd);

                            // Now, clear the matched area.
                            debug!("clearing matched area ({},{}) of w:{} h:{}",
                                   x, y, cmd.w, cmd.h);
                            for i in range(x, x+cmd.w) {
                                for j in range(y, y+cmd.h) {
                                    grid.set(i, j, unused_char);
                                    cleared_some = true;
                                }
                            }
                        }

                        None => {
                            continue;
                        }
                    }

                }
            }
            if !cleared_some {
                break;
            }
        }
        let commands = {
            rev_commands.as_mut_slice().reverse();
            rev_commands
        };

        for cmd in commands.into_iter() {
            s.add_end_command(cmd);
        }

        s
    }
}

#[deriving(Show)]
enum MatchBox {
    ExactMatch(boxdraw::Command),
    PartialMatch,

    NonMatch(WhyNonMatch),
}

#[deriving(PartialEq, Show)]
struct WhyNonMatch {
    reason: String,
}

fn non_match(why: String) -> MatchBox {
    NonMatch(WhyNonMatch { reason: why })
}

impl PartialEq for MatchBox {
    fn eq(&self, that: &MatchBox) -> bool {
        match (self, that) {
            (&ExactMatch(c1), &ExactMatch(c2)) => {
                c1.x == c2.x &&
                    c1.y == c2.y &&
                    c1.w == c2.w &&
                    c1.h == c2.h &&
                    c1.fill == c2.fill
            }
            (&PartialMatch, &PartialMatch) => true,
            (&NonMatch(_), &NonMatch(_)) => true,
            _ => false
        }
    }
}

impl SimpleSearch {
    fn find_unused_char(&self, picture: &str) -> char {
        static AVOID : [char, ..5] = ['.', '+', '-', '|', '\n'];
        let mut guess = '?' as u32;
        loop {
            match from_u32(guess) {
                Some(char_guess) if !AVOID.contains(&char_guess) && !picture.contains_char(char_guess) => {
                    return char_guess;
                }
                _ => {
                    guess += 1;
                }
            }
        }
    }

    /// Attempts to match a box at `(x,y)`, using `hidden` as a marker
    /// for spaces that were overwritten by a later command.
    fn try_upper_left(&self, grid: &Grid, hidden: char, x: u32, y: u32) -> Option<boxdraw::Command> {

        let w = grid.width();
        let h = grid.height();

        // Found a left-corner; find the extent of the box.
        // println!("inspecting ({},{})", x, y);
        // println!("char at: ({},{}): '{}'", x, y, grid.get(x, y));

        let mut saw_partial = false;
        assert!(x < w); assert!(y < h);
        let c = grid.get(x,y);
        if c == '+' {
            'next_width:
            for i in range(x+1, w) {
                for j in range(y+1, h) {
                    let match_at = TryMatchAt {
                        grid: grid,
                        hidden: hidden,
                        x: x,
                        y: y,
                    };
                    match match_at.try(i, j) {
                        ExactMatch(cmd) => return Some(cmd),
                        PartialMatch => {
                            saw_partial = true;
                            continue;
                        }
                        NonMatch(ref why) => {
                            if saw_partial {
                                debug!("nonmatch for {}-{} because {}", (x,y), (i,j), why.reason);
                            }
                            continue 'next_width;
                        }
                    }
                }
            }
            None
        } else {
            None
        }
    }
}

struct TryMatchAt<'a> {
    grid: &'a Grid,
    hidden: char,
    x: u32,
    y: u32,
}

impl<'a> TryMatchAt<'a> {

    /// Attempts to match a box at `(self.x, self.y)` extending to `(right, below)`
    /// using `self.hidden` as a marker for spaces
    /// that were overwritten by a later command.
    fn try(&self, right: u32, below: u32) -> MatchBox {
        let x = self.x;
        let y = self.y;
        let grid = self.grid;
        let w = grid.width();
        let h = grid.height();

        let box_w = right - x + 1;
        let box_h = below - y + 1;

        let trial = (x, y, box_w, box_h);

        debug!("try: x {} y {} box_w {} box_h {} right {} below {} w {} h {}",
               x, y, box_w, box_h, right, below, w, h);

        assert!(x < w); assert!(y < h);
        let upper_left = grid.get(x, y);
        assert!(x < w); assert!(below < h);
        let lower_left = grid.get(x, below);
        assert!(right < w); assert!(y < h);
        let upper_right = grid.get(right, y);
        assert!(right < w); assert!(below < h);
        let lower_right = grid.get(right, below);

        let mut extends_right = false;
        let mut extends_down = false;

        // Tracks the character to use for the box interior, which we
        // do not necessarily know until scanning deep into the box.
        let mut interior = None;

        if !self.matches_corner(upper_left) {
            return non_match(format!("failed to match upper_left corner: {}", upper_left));
        }
        if !self.matches_corner(lower_left) {
            if lower_left == '|' {
                extends_down = true;
            } else {
                return non_match(format!("failed to match lower_left corner: {}", lower_left));
            }
        }

        if !self.matches_corner(upper_right) {
            if upper_right == '-' {
                extends_right = true;
            } else {
                return non_match(format!("failed to match upper_right corner: {}", upper_right));
            }
        }

        if !self.matches_corner(lower_right) {
            if extends_down && lower_right == '|' {
                // okay
            } else if extends_right && lower_right == '-' {
                // okay
            } else if extends_down && extends_right {
                if lower_right != self.hidden {
                    interior = Some(lower_right);
                }
            } else {
                return non_match(format!("failed to match lower_right corner: {}", lower_right));
            }
        }

        // Check that walls of box are in place.
        for i in range(x + 1, right) { // across
            assert!(i < w); assert!(y < h);
            let c = grid.get(i, y);
            if !self.matches_horizontal_wall(c) {
                return non_match(format!("failed to match top horizontal wall at {}: {}", (i, y), c));
            }
            assert!(i < w); assert!(below < h);
            let c = grid.get(i, below);
            if !extends_down {
                if !self.matches_horizontal_wall(c) {
                    return non_match(format!("failed to match bot horizontal wall at {}: {}", (i, below), c));
                }
            } else if c == self.hidden {
                // keep going
            } else {
                if interior.is_none() {
                    interior = Some(c);
                }
                if interior.is_some() && Some(c) != interior {
                    return non_match(format!("failed to match bot interior {} at {}: {}", interior, (i, below), c));
                }
            }
        }
        for j in range(y + 1, below) { // down
            assert!(x < w); assert!(j < h);
            let c = grid.get(x, j);
            if !self.matches_vertical_wall(c) {
                return non_match(format!("failed to match left vertical wall at {}: {}", (x, j), c));
            }
            assert!(right < w); assert!(j < h);
            let c = grid.get(right, j);
            if !extends_right {
                if !self.matches_vertical_wall(c) {
                    return non_match(format!("failed to match right vertical wall at {}: {}", (right, j), c));
                }
            } else if c == self.hidden {
                // keep going
            } else {
                if interior.is_none() {
                    interior = Some(c);
                }
                if interior.is_some() && Some(c) != interior {
                    return non_match(format!("failed to match right interior {} at {}: {}", interior, (right, j), c));
                }
            }
        }

        // Check that the interior is sound
        for i in range(x + 1, right) {
            for j in range(y + 1, below) {
                assert!(i < w); assert!(j < h);
                match (interior, grid.get(i, j)) {
                    (None, c) => {
                        if c == self.hidden {
                            // Okay, clean match and we still do not know
                            // what the interior is.
                            continue;
                        } else {
                            // finally, a non-hidden marker.  Assume
                            // that this is the interior.
                            interior = Some(c);
                            continue;
                        }
                    }
                    (Some(c1), c2) => {
                        if c1 == c2 || c2 == self.hidden {
                            // the color c2 matches the interior c1; keep
                            // going.
                            continue;
                        } else {
                            return non_match(format!("failed to match interior {} at {}: {}", c1, (i, j), c2));
                        }
                    }
                }
            }
        }

        // got this far; return either full or partial box, as
        // appropriate.

        if extends_down || extends_right {
            debug!("partial match {} interior: {}", trial, interior);
            PartialMatch
        } else {
            assert!(x+1 < w); assert!(y+1 < h);
            let fill = grid.get(x+1, y+1);
            let cmd = boxdraw::rect(x, y, box_w, box_h, fill);

            debug!("exact match: {}", cmd);
            ExactMatch(cmd)
        }
    }

    fn matches_corner(&self, c: char) -> bool {
        c == '+' || c == self.hidden
    }

    fn matches_horizontal_wall(&self, c: char) -> bool {
        c == '-' || c == self.hidden
    }

    fn matches_vertical_wall(&self, c: char) -> bool {
        c == '|' || c == self.hidden
    }
}

#[test]
fn check_simple() {
    boxdraw::check_undraw("...\n", &SimpleSearch).unwrap();

    boxdraw::check_undraw(".....\n\
                           .+-+.\n\
                           .|b|.\n\
                           .+-+.\n\
                          ",
                          &SimpleSearch).unwrap();

    boxdraw::check_undraw(".............\n\
                           .......+--+..\n\
                           .+-+...|cc|..\n\
                           .|b|...|cc|..\n\
                           .+-+...+--+..\n\
                           .............\n\
                          ",
                          &SimpleSearch).unwrap();

    boxdraw::check_undraw(".........\n\
                           .........\n\
                           .+-+.....\n\
                           .|b|.....\n\
                           .+-+.....\n\
                           .+--+....\n\
                           .|cc|....\n\
                           .|cc|....\n\
                           .+--+....\n\
                           .........\n\
                          ",
                          &SimpleSearch).unwrap();
}

#[test]
fn check_that_hidden_char_works() {
    fn check_for_1x1_picture(picture: &str) {
        let grid = Grid::from_str(picture).unwrap();
        let match_at = TryMatchAt {
            grid: &grid,
            hidden: '?',
            x: 1,
            y: 1,
        };
        assert_eq!(match_at.try(3,3), ExactMatch(boxdraw::rect(1, 1, 3, 3, 'b')));
    }

    check_for_1x1_picture(".....\n\
                           .+-+.\n\
                           .|b|.\n\
                           .+-+.\n\
                          ");

    check_for_1x1_picture(".....\n\
                           .+-+.\n\
                           .|b|.\n\
                           .+-?.\n\
                          ");

    check_for_1x1_picture(".....\n\
                           .+-+.\n\
                           .|b?.\n\
                           .+-+.\n\
                          ");

    check_for_1x1_picture(".....\n\
                           .+-+.\n\
                           .|b|.\n\
                           .+?+.\n\
                          ");

    check_for_1x1_picture(".....\n\
                           .+-+.\n\
                           .|b?.\n\
                           .+?+.\n\
                          ");

    check_for_1x1_picture(".....\n\
                           .+-+.\n\
                           .|b?.\n\
                           .+??.\n\
                          ");

    check_for_1x1_picture(".....\n\
                           .+-?.\n\
                           .|b?.\n\
                           .+?+.\n\
                          ");

    check_for_1x1_picture(".....\n\
                           .+-?.\n\
                           .?b?.\n\
                           .??+.\n\
                          ");

}

#[test]
fn check_specific_expected_case_from_overlapping_test() {
    let picture = ".............\n\
                   ....+---+....\n\
                   ....|bbb|....\n\
                   ....|bb????..\n\
                   ....|bb????..\n\
                   ....+--????..\n\
                   .......????..\n\
                   .............\n\
                  ";
    let grid = Grid::from_str(picture).unwrap();
    let match_at = TryMatchAt {
        grid: &grid,
        hidden: '?',
        x: 4,
        y: 1,
    };
    assert_eq!(match_at.try(8,5), ExactMatch(boxdraw::rect(4, 1, 5, 5, 'b')));

}

#[test]
fn overlapping_boxes() {
    boxdraw::check_undraw(".............\n\
                           ....+---+....\n\
                           ....|bbb|....\n\
                           ....|bb+--+..\n\
                           ....|bb|cc|..\n\
                           ....+--|cc|..\n\
                           .......+--+..\n\
                           .............\n\
                          ",
                          &SimpleSearch).unwrap();

}

#[test]
fn nested() {
    boxdraw::check_undraw(".............\n\
                           ..+--------+.\n\
                           ..|aaaaaaaa|.\n\
                           ..|aaaaaaaa|.\n\
                           ..|aa+--+aa|.\n\
                           ..|aa|bb|aa|.\n\
                           ..|aa|bb|aa|.\n\
                           ..|aa+--+aa|.\n\
                           ..|aaaaaaaa|.\n\
                           ..|aaaaaaaa|.\n\
                           ..+--------+.\n\
                           .............\n\
                          ",
                          &SimpleSearch).unwrap();
}

#[test]
fn three_by_three() {
    boxdraw::check_undraw(".............\n\
                           ..+--+--+--+.\n\
                           ..|aa|bb|cc|.\n\
                           ..|aa|bb|cc|.\n\
                           ..+--+--+--+.\n\
                           ..|dd|ee|ff|.\n\
                           ..|dd|ee|ff|.\n\
                           ..+--+--+--+.\n\
                           ..|gg|hh|ii|.\n\
                           ..|gg|hh|ii|.\n\
                           ..+--+--+--+.\n\
                           .............\n\
                          ",
                          &SimpleSearch).unwrap();

}
<|endoftext|>


<commit_before>/*!

[Sidekiq](https://github.com/mperham/sidekiq) client allowing to push jobs.
Using the [Sidekiq job
format](https://github.com/mperham/sidekiq/wiki/Job-Format) as reference.

# Default environment variables

* REDIS_URL="redis://127.0.0.1/"
*/
#![deny(warnings)]
#![cfg_attr(feature = "clippy", feature(plugin))]
#![cfg_attr(feature = "clippy", plugin(clippy))]

#![crate_name = "sidekiq"]

extern crate serde;
extern crate serde_json;
extern crate rand;
extern crate r2d2;
extern crate r2d2_redis;

mod sidekiq;
pub use serde_json::value::Value;
pub use sidekiq::{Job, JobOpts, Client, ClientOpts, RedisPool, RedisPooledConnection,
                  create_redis_pool};
<commit_msg>Put REDIS_URL between ticks in the documentation<commit_after>/*!

[Sidekiq](https://github.com/mperham/sidekiq) client allowing to push jobs.
Using the [Sidekiq job
format](https://github.com/mperham/sidekiq/wiki/Job-Format) as reference.

# Default environment variables

* `REDIS_URL`="redis://127.0.0.1/"
*/
#![deny(warnings)]
#![cfg_attr(feature = "clippy", feature(plugin))]
#![cfg_attr(feature = "clippy", plugin(clippy))]

#![crate_name = "sidekiq"]

extern crate serde;
extern crate serde_json;
extern crate rand;
extern crate r2d2;
extern crate r2d2_redis;

mod sidekiq;
pub use serde_json::value::Value;
pub use sidekiq::{Job, JobOpts, Client, ClientOpts, RedisPool, RedisPooledConnection,
                  create_redis_pool};
<|endoftext|>


<commit_before>extern crate byteorder;

use std::error;
use std::fmt;
use std::io;
use std::io::{Read, Seek, SeekFrom};
use std::result;

use byteorder::{LittleEndian, ReadBytesExt};

// MARK: Error types

/// Represents an error that occurred while reading a wave file.
#[derive(Debug)]
pub enum ReadError {
    /// The file format is incorrect or unsupported.
    Format(FormatErrorKind),
    /// An IO error occurred.
    Io(io::Error),
}

/// Represents a result when reading a wave file.
pub type ReadResult<T> = result::Result<T, ReadError>;

impl fmt::Display for ReadError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            ReadError::Format(ref err_kind) => write!(f, "Format error: {}", err_kind),
            ReadError::Io(ref err) => write!(f, "IO error: {}", err),
        }
    }
}

/// Represents a file format error, when the wave file is incorrect or unsupported.
#[derive(Debug)]
pub enum FormatErrorKind {
    /// The file does not start with a "RIFF" tag and chunk size.
    NotARiffFile,
    /// The file doesn't continue with "WAVE" after the RIFF chunk header.
    NotAWaveFile,
}

impl FormatErrorKind {
    fn to_string(&self) -> &str {
        match *self {
            FormatErrorKind::NotARiffFile => "not a RIFF file",
            FormatErrorKind::NotAWaveFile => "not a WAVE file",
        }
    }
}

impl fmt::Display for FormatErrorKind {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.to_string())
    }
}

impl error::Error for ReadError {
    fn description(&self) -> &str {
        match *self {
            ReadError::Format(ref kind) => kind.to_string(),
            ReadError::Io(ref err) => err.description(),
        }
    }

    fn cause(&self) -> Option<&error::Error> {
        match *self {
            ReadError::Format(_) => None,
            ReadError::Io(ref err) => Some(err),
        }
    }
}

impl From<io::Error> for ReadError {
    fn from(err: io::Error) -> ReadError {
        ReadError::Io(err)
    }
}

// MARK: Validation and parsing functions

trait WaveReader: Read + Seek {
    fn validate_is_riff_file(&mut self) -> ReadResult<()> {
        try!(self.validate_tag(b"RIFF", FormatErrorKind::NotARiffFile));
        // The next four bytes represent the chunk size. We're not going to
        // validate it, so that we can still try to read files that might have
        // an incorrect chunk size, so let's skip over it.
        let _ = try!(self.read_chunk_size());
        Ok(())
    }

    fn validate_is_wave_file(&mut self) -> ReadResult<()> {
        try!(self.validate_tag(b"WAVE", FormatErrorKind::NotAWaveFile));
        Ok(())
    }

    fn validate_tag(&mut self,
                    expected_tag: &[u8; 4],
                    err_kind: FormatErrorKind)
                    -> ReadResult<()> {
        let tag = try!(self.read_tag());
        if &tag != expected_tag {
            return Err(ReadError::Format(err_kind));
        }
        Ok(())
    }

    fn skip_until_subchunk(&mut self, matching_tag: &[u8; 4]) -> ReadResult<u32> {
        loop {
            let tag = try!(self.read_tag());
            let subchunk_size = try!(self.read_chunk_size());

            if &tag == matching_tag {
                return Ok(subchunk_size);
            } else {
                try!(self.seek(SeekFrom::Current(subchunk_size.into())));
            }
        }
    }

    fn read_tag(&mut self) -> ReadResult<[u8; 4]> {
        let mut tag: [u8; 4] = [0; 4];
        try!(self.read_exact(&mut tag));
        Ok(tag)
    }

    fn read_chunk_size(&mut self) -> ReadResult<u32> {
        Ok(try!(self.read_u32::<LittleEndian>()))
    }
}

impl<T> WaveReader for T where T: Read + Seek {}

// MARK: Tests

#[cfg(test)]
mod tests {
    use std::io::Cursor;

    use {FormatErrorKind, ReadError, WaveReader};

    // This is a helper macro that helps us validate results in our tests.
    // Thank you bluss and durka42!
    macro_rules! assert_matches {
        ($expected:pat $(if $guard:expr)*, $value:expr) => {
            match $value {
                $expected $(if $guard)* => {},
                ref actual => {
                    panic!("assertion failed: `(left matches right)` (left: `{}`, right: `{:?}`",
                        stringify!($expected), actual);
                },
            }
        };
    }

    // RIFF header tests

    #[test]
    fn test_validate_is_riff_file_ok() {
        let mut data = Cursor::new(b"RIFF    ");
        assert_matches!(Ok(()), data.validate_is_riff_file());
    }

    #[test]
    fn test_validate_is_riff_file_err_incomplete() {
        let mut data = Cursor::new(b"RIF     ");
        assert_matches!(Err(ReadError::Format(FormatErrorKind::NotARiffFile)),
                        data.validate_is_riff_file());
    }

    #[test]
    fn test_validate_is_riff_file_err_something_else() {
        let mut data = Cursor::new(b"JPEG     ");
        assert_matches!(Err(ReadError::Format(FormatErrorKind::NotARiffFile)),
                        data.validate_is_riff_file());
    }

    // Wave tag tests

    #[test]
    fn test_validate_is_wave_file_ok() {
        let mut data = Cursor::new(b"WAVE");
        assert_matches!(Ok(()), data.validate_is_wave_file());
    }

    #[test]
    fn test_validate_is_wave_file_err_incomplete() {
        let mut data = Cursor::new(b"WAV ");
        assert_matches!(Err(ReadError::Format(FormatErrorKind::NotAWaveFile)),
                        data.validate_is_wave_file());
    }

    #[test]
    fn test_validate_is_wave_file_err_something_else() {
        let mut data = Cursor::new(b"JPEG");
        assert_matches!(Err(ReadError::Format(FormatErrorKind::NotAWaveFile)),
                        data.validate_is_wave_file());
    }

    // Skipping to subchunk tests
    // After reading in the file header, we also need to read in the "fmt " subchunk.
    // The file might contain other subchunks that we don't currently support, so
    // we'll need to skip over them.

    #[test]
    fn test_skip_until_subchunk() {
        // A size of 0.
        let mut data = Cursor::new(b"RIFF    WAVEfmt \x00\x00\x00\x00");
        let _ = data.validate_is_riff_file();
        let _ = data.validate_is_wave_file();
        let size = data.skip_until_subchunk(b"fmt ");
        assert_eq!(0, size.unwrap());
    }

    #[test]
    fn test_skip_until_second_subchunk() {
        // A size of 0.
        let mut data = Cursor::new(b"RIFF    WAVEfmt \x00\x00\x00\x00data\x00\x00\x00\x00");
        let _ = data.validate_is_riff_file();
        let _ = data.validate_is_wave_file();
        let _ = data.skip_until_subchunk(b"fmt ");
        let size = data.skip_until_subchunk(b"data");
        assert_eq!(0, size.unwrap());
    }

    #[test]
    #[should_panic]
    fn test_cant_read_first_subchunk_after_second() {
        // A size of 0.
        let mut data = Cursor::new(b"RIFF    WAVEdata\x00\x00\x00\x00fmt \x00\x00\x00\x00");
        let _ = data.validate_is_riff_file();
        let _ = data.validate_is_wave_file();
        let _ = data.skip_until_subchunk(b"fmt ");
        let size = data.skip_until_subchunk(b"data");
        assert_eq!(0, size.unwrap());
    }
}
<commit_msg>Validate the PCM format. We'll start off by only supporting uncompressed formats: The regular PCM file format and the "extended" format (of which we'll also only support uncompressed PCM files).<commit_after>extern crate byteorder;

use std::error;
use std::fmt;
use std::io;
use std::io::{Read, Seek, SeekFrom};
use std::result;

use byteorder::{LittleEndian, ReadBytesExt};

// MARK: Error types

/// Represents an error that occurred while reading a wave file.
#[derive(Debug)]
pub enum ReadError {
    /// The file format is incorrect or unsupported.
    Format(FormatErrorKind),
    /// An IO error occurred.
    Io(io::Error),
}

/// Represents a result when reading a wave file.
pub type ReadResult<T> = result::Result<T, ReadError>;

impl fmt::Display for ReadError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            ReadError::Format(ref err_kind) => write!(f, "Format error: {}", err_kind),
            ReadError::Io(ref err) => write!(f, "IO error: {}", err),
        }
    }
}

/// Represents a file format error, when the wave file is incorrect or unsupported.
#[derive(Debug)]
pub enum FormatErrorKind {
    /// The file does not start with a "RIFF" tag and chunk size.
    NotARiffFile,
    /// The file doesn't continue with "WAVE" after the RIFF chunk header.
    NotAWaveFile,
    /// This file is not an uncompressed PCM wave file. Only uncompressed files are supported.
    NotAnUncompressedPcmWaveFile(u16),
}

impl FormatErrorKind {
    fn to_string(&self) -> &str {
        match *self {
            FormatErrorKind::NotARiffFile => "not a RIFF file",
            FormatErrorKind::NotAWaveFile => "not a WAVE file",
            FormatErrorKind::NotAnUncompressedPcmWaveFile(_) => "Not an uncompressed wave file",
        }
    }
}

impl fmt::Display for FormatErrorKind {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.to_string())
    }
}

impl error::Error for ReadError {
    fn description(&self) -> &str {
        match *self {
            ReadError::Format(ref kind) => kind.to_string(),
            ReadError::Io(ref err) => err.description(),
        }
    }

    fn cause(&self) -> Option<&error::Error> {
        match *self {
            ReadError::Format(_) => None,
            ReadError::Io(ref err) => Some(err),
        }
    }
}

impl From<io::Error> for ReadError {
    fn from(err: io::Error) -> ReadError {
        ReadError::Io(err)
    }
}

// MARK: Validation and parsing functions

const FORMAT_UNCOMPRESSED_PCM: u16 = 1;
const FORMAT_EXTENDED: u16 = 65534;

#[derive(Debug)]
enum Format {
    UncompressedPcm,
    ExtendedWave,
}

fn validate_pcm_format(format: u16) -> ReadResult<Format> {
    match format {
        FORMAT_UNCOMPRESSED_PCM => Ok(Format::UncompressedPcm),
        FORMAT_EXTENDED => Ok(Format::ExtendedWave),
        _ => Err(ReadError::Format(FormatErrorKind::NotAnUncompressedPcmWaveFile(format))),
    }
}

trait WaveReader: Read + Seek {
    fn validate_is_riff_file(&mut self) -> ReadResult<()> {
        try!(self.validate_tag(b"RIFF", FormatErrorKind::NotARiffFile));
        // The next four bytes represent the chunk size. We're not going to
        // validate it, so that we can still try to read files that might have
        // an incorrect chunk size, so let's skip over it.
        let _ = try!(self.read_chunk_size());
        Ok(())
    }

    fn validate_is_wave_file(&mut self) -> ReadResult<()> {
        try!(self.validate_tag(b"WAVE", FormatErrorKind::NotAWaveFile));
        Ok(())
    }

    fn validate_tag(&mut self,
                    expected_tag: &[u8; 4],
                    err_kind: FormatErrorKind)
                    -> ReadResult<()> {
        let tag = try!(self.read_tag());
        if &tag != expected_tag {
            return Err(ReadError::Format(err_kind));
        }
        Ok(())
    }

    fn skip_until_subchunk(&mut self, matching_tag: &[u8; 4]) -> ReadResult<u32> {
        loop {
            let tag = try!(self.read_tag());
            let subchunk_size = try!(self.read_chunk_size());

            if &tag == matching_tag {
                return Ok(subchunk_size);
            } else {
                try!(self.seek(SeekFrom::Current(subchunk_size.into())));
            }
        }
    }

    fn read_tag(&mut self) -> ReadResult<[u8; 4]> {
        let mut tag: [u8; 4] = [0; 4];
        try!(self.read_exact(&mut tag));
        Ok(tag)
    }

    fn read_chunk_size(&mut self) -> ReadResult<u32> {
        Ok(try!(self.read_u32::<LittleEndian>()))
    }
}

impl<T> WaveReader for T where T: Read + Seek {}

// MARK: Tests

#[cfg(test)]
mod tests {
    use std::io::Cursor;

    use {FORMAT_UNCOMPRESSED_PCM, FORMAT_EXTENDED};
    use {Format, FormatErrorKind, ReadError, WaveReader};
    use validate_pcm_format;

    // This is a helper macro that helps us validate results in our tests.
    // Thank you bluss and durka42!
    macro_rules! assert_matches {
        ($expected:pat $(if $guard:expr)*, $value:expr) => {
            match $value {
                $expected $(if $guard)* => {},
                ref actual => {
                    panic!("assertion failed: `(left matches right)` (left: `{}`, right: `{:?}`",
                        stringify!($expected), actual);
                },
            }
        };
    }

    // RIFF header tests

    #[test]
    fn test_validate_is_riff_file_ok() {
        let mut data = Cursor::new(b"RIFF    ");
        assert_matches!(Ok(()), data.validate_is_riff_file());
    }

    #[test]
    fn test_validate_is_riff_file_err_incomplete() {
        let mut data = Cursor::new(b"RIF     ");
        assert_matches!(Err(ReadError::Format(FormatErrorKind::NotARiffFile)),
                        data.validate_is_riff_file());
    }

    #[test]
    fn test_validate_is_riff_file_err_something_else() {
        let mut data = Cursor::new(b"JPEG     ");
        assert_matches!(Err(ReadError::Format(FormatErrorKind::NotARiffFile)),
                        data.validate_is_riff_file());
    }

    // Wave tag tests

    #[test]
    fn test_validate_is_wave_file_ok() {
        let mut data = Cursor::new(b"WAVE");
        assert_matches!(Ok(()), data.validate_is_wave_file());
    }

    #[test]
    fn test_validate_is_wave_file_err_incomplete() {
        let mut data = Cursor::new(b"WAV ");
        assert_matches!(Err(ReadError::Format(FormatErrorKind::NotAWaveFile)),
                        data.validate_is_wave_file());
    }

    #[test]
    fn test_validate_is_wave_file_err_something_else() {
        let mut data = Cursor::new(b"JPEG");
        assert_matches!(Err(ReadError::Format(FormatErrorKind::NotAWaveFile)),
                        data.validate_is_wave_file());
    }

    // Skipping to subchunk tests
    // After reading in the file header, we also need to read in the "fmt " subchunk.
    // The file might contain other subchunks that we don't currently support, so
    // we'll need to skip over them.

    #[test]
    fn test_skip_until_subchunk() {
        // A size of 0.
        let mut data = Cursor::new(b"RIFF    WAVEfmt \x00\x00\x00\x00");
        let _ = data.validate_is_riff_file();
        let _ = data.validate_is_wave_file();
        let size = data.skip_until_subchunk(b"fmt ");
        assert_eq!(0, size.unwrap());
    }

    #[test]
    fn test_skip_until_second_subchunk() {
        // A size of 0.
        let mut data = Cursor::new(b"RIFF    WAVEfmt \x00\x00\x00\x00data\x00\x00\x00\x00");
        let _ = data.validate_is_riff_file();
        let _ = data.validate_is_wave_file();
        let _ = data.skip_until_subchunk(b"fmt ");
        let size = data.skip_until_subchunk(b"data");
        assert_eq!(0, size.unwrap());
    }

    #[test]
    #[should_panic]
    fn test_cant_read_first_subchunk_after_second() {
        // A size of 0.
        let mut data = Cursor::new(b"RIFF    WAVEdata\x00\x00\x00\x00fmt \x00\x00\x00\x00");
        let _ = data.validate_is_riff_file();
        let _ = data.validate_is_wave_file();
        let _ = data.skip_until_subchunk(b"fmt ");
        let size = data.skip_until_subchunk(b"data");
        assert_eq!(0, size.unwrap());
    }

    // Wave format validation tests

    #[test]
    fn test_validate_pcm_format_ok_uncompressed() {
        assert_matches!(Ok(Format::UncompressedPcm),
                        validate_pcm_format(FORMAT_UNCOMPRESSED_PCM));
    }

    #[test]
    fn test_validate_pcm_format_ok_extended() {
        assert_matches!(Ok(Format::ExtendedWave),
                        validate_pcm_format(FORMAT_EXTENDED));
    }

    #[test]
    fn test_validate_pcm_format_err_not_uncompressed() {
        assert_matches!(Err(ReadError::Format(FormatErrorKind::NotAnUncompressedPcmWaveFile(_))),
        				validate_pcm_format(12345));
    }
}
<|endoftext|>