<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, 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)]

use std::path::PathBuf;

#[cfg(target_os = "windows")]                                                     mod win;
#[cfg(target_os = "macos")]                                                       mod mac;
#[cfg(target_os = "redox")]                                                       mod redox;
#[cfg(not(any(target_os = "windows", target_os = "macos", target_os = "redox")))] mod lin;
#[cfg(unix)]                                                                      mod unix;

#[cfg(target_os = "windows")]                                                     use win as sys;
#[cfg(target_os = "macos")]                                                       use mac as sys;
#[cfg(target_os = "redox")]                                                       use redox as sys;
#[cfg(not(any(target_os = "windows", target_os = "macos", target_os = "redox")))] 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 missing backticks to source code documentation<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, 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)]

use std::path::PathBuf;

#[cfg(target_os = "windows")]                                                     mod win;
#[cfg(target_os = "macos")]                                                       mod mac;
#[cfg(target_os = "redox")]                                                       mod redox;
#[cfg(not(any(target_os = "windows", target_os = "macos", target_os = "redox")))] mod lin;
#[cfg(unix)]                                                                      mod unix;

#[cfg(target_os = "windows")]                                                     use win as sys;
#[cfg(target_os = "macos")]                                                       use mac as sys;
#[cfg(target_os = "redox")]                                                       use redox as sys;
#[cfg(not(any(target_os = "windows", target_os = "macos", target_os = "redox")))] 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>//! Write-only Memory for Rust
//!
//! This is a wrapper type to disallow reading from the wrapped type

use std::ops::{Deref, DerefMut};
use std::convert::{AsRef, AsMut};

/// Make `T` Write-Only
pub struct Wom<T> {
    #[doc(hidden)]
    _inner: T
}

impl<T> Wom<T> {
    /// Transmute this value into the wrapped value
    ///
    /// # Examples
    ///
    /// ```
    ///# use wom::wom;
    /// assert_eq!(1, wom(1u32).into_inner());
    /// ```
    pub fn into_inner(self) -> T {
        self._inner
    }
}

/// Create a Wom handle on our `T`.
pub fn wom<T>(t: T) -> Wom<T> {
    Wom { _inner: t }
}

impl<T: Sized> AsRef<T> for Wom<T> {
    /// Getting an immutable value out should panic.
    /// # Examples
    ///
    /// ```should_panic
    ///# use wom::wom;
    /// wom(1u32).as_ref();
    /// ```
    fn as_ref(&self) -> &T {
        panic!("readably referencing write-only memory");
    }
}

impl<T: Sized> Deref for Wom<T> {
    type Target = T;

    /// Getting an immutable value out should panic.
    /// # Examples
    ///
    /// ```should_panic
    ///# use wom::wom;
    /// *wom(1u32);
    /// ```
    fn deref(&self) -> &T {
        panic!("readably referencing write-only memory");
    }
}

impl<T: Sized> DerefMut for Wom<T> {
    /// Dereference into the inner value
    ///
    /// # Examples
    ///
    /// ```
    ///# use wom::wom;
    /// let mut w = wom(1u32);
    /// *w = 2u32;
    /// assert_eq!(2, w.into_inner());
    /// ```
    fn deref_mut(&mut self) -> &mut T {
        return &mut self._inner;
    }
}

impl<T: Sized> AsMut<T> for Wom<T> {
    /// Transmute this value into the wrapped value
    ///
    /// # Examples
    ///
    /// ```
    ///# use wom::wom;
    /// let x = [1u32];
    /// let mut w = wom(x);
    /// w.as_mut()[0] = 2;
    /// assert_eq!(2, w.into_inner()[0]);
    /// ```
    fn as_mut(&mut self) -> &mut T {
        &mut self._inner
    }
}

//TODO: Index, IndexMut
<commit_msg>first attempt at closure-based API<commit_after>//! Write-only Memory for Rust
//!
//! This is a wrapper type to disallow reading from the wrapped type

use std::ops::{Deref, DerefMut};
use std::convert::{AsRef, AsMut};

/// Make `T` Write-Only
pub struct Wom<T> {
    #[doc(hidden)]
    _inner: T
}

impl<T> Wom<T> {
    /// Transmute this value into the wrapped value
    ///
    /// # Examples
    ///
    /// ```
    ///# use wom::wom;
    /// assert_eq!(1, wom(1u32).into_inner());
    /// ```
    pub fn into_inner(self) -> T {
        self._inner
    }
}

/// Run a function over a write-only wrapped value
///
/// # Examples
///
/// ```
///# use wom::with_wom;
/// let mut x = 1u32;
/// let mut y : u32 = with_wom(x, |ref mut w| ***w = 2u32);
/// assert_eq!(2, y);
/// ```
pub fn with_wom<F, T: Sized>(t: T, f: F) -> T
where F: FnOnce(&mut Wom<T>) {
    let mut w : Wom<T> = wom(t);
    {
        let wref = &mut w;
        f(wref);
    }
    w.into_inner()
}

/// Create a Wom handle on our `T`.
pub fn wom<T>(t: T) -> Wom<T> {
    Wom { _inner: t }
}

impl<T: Sized> AsRef<T> for Wom<T> {
    /// Getting an immutable value out should panic.
    /// # Examples
    ///
    /// ```should_panic
    ///# use wom::wom;
    /// wom(1u32).as_ref();
    /// ```
    fn as_ref(&self) -> &T {
        panic!("readably referencing write-only memory");
    }
}

impl<T: Sized> Deref for Wom<T> {
    type Target = T;

    /// Getting an immutable value out should panic.
    /// # Examples
    ///
    /// ```should_panic
    ///# use wom::wom;
    /// *wom(1u32);
    /// ```
    fn deref(&self) -> &T {
        panic!("readably referencing write-only memory");
    }
}

impl<T: Sized> DerefMut for Wom<T> {
    /// Dereference into the inner value
    ///
    /// # Examples
    ///
    /// ```
    ///# use wom::wom;
    /// let mut w = wom(1u32);
    /// *w = 2u32;
    /// assert_eq!(2, w.into_inner());
    /// ```
    fn deref_mut(&mut self) -> &mut T {
        return &mut self._inner;
    }
}

impl<T: Sized> AsMut<T> for Wom<T> {
    /// Transmute this value into the wrapped value
    ///
    /// # Examples
    ///
    /// ```
    ///# use wom::wom;
    /// let x = [1u32];
    /// let mut w = wom(x);
    /// w.as_mut()[0] = 2;
    /// assert_eq!(2, w.into_inner()[0]);
    /// ```
    fn as_mut(&mut self) -> &mut T {
        &mut self._inner
    }
}

//TODO: Index, IndexMut
<|endoftext|>


<commit_before>//! A macro for defining #[cfg] if-else statements.
//!
//! The macro provided by this crate, `cfg_if`, is similar to the `if/elif` C
//! preprocessor macro by allowing definition of a cascade of `#[cfg]` cases,
//! emitting the implementation which matches first.
//!
//! This allows you to conveniently provide a long list #[cfg]'d blocks of code
//! without having to rewrite each clause multiple times.
//!
//! # Example
//!
//! ```
//! #[macro_use]
//! extern crate cfg_if;
//!
//! cfg_if! {
//!     if #[cfg(unix)] {
//!         fn foo() { /* unix specific functionality */ }
//!     } else if #[cfg(target_pointer_width = "32")] {
//!         fn foo() { /* non-unix, 32-bit functionality */ }
//!     } else {
//!         fn foo() { /* fallback implementation */ }
//!     }
//! }
//!
//! # fn main() {}
//! ```

#![no_std]

#![doc(html_root_url = "https://docs.rs/cfg-if")]
#![deny(missing_docs)]
#![cfg_attr(test, deny(warnings))]

#[macro_export]
macro_rules! cfg_if {
    ($(
        if #[cfg($($meta:meta),*)] { $($it:item)* }
    ) else * else {
        $($it2:item)*
    }) => {
        __cfg_if_items! {
            () ;
            $( ( ($($meta),*) ($($it)*) ), )*
            ( () ($($it2)*) ),
        }
    };
    (
        if #[cfg($($i_met:meta),*)] { $($i_it:item)* }
        $(
            else if #[cfg($($e_met:meta),*)] { $($e_it:item)* }
        )*
    ) => {
        __cfg_if_items! {
            () ;
            ( ($($i_met),*) ($($i_it)*) ),
            $( ( ($($e_met),*) ($($e_it)*) ), )*
            ( () () ),
        }
    }
}

#[macro_export]
#[doc(hidden)]
macro_rules! __cfg_if_items {
    (($($not:meta,)*) ; ) => {};
    (($($not:meta,)*) ; ( ($($m:meta),*) ($($it:item)*) ), $($rest:tt)*) => {
        __cfg_if_apply! { cfg(all($($m,)* not(any($($not),*)))), $($it)* }
        __cfg_if_items! { ($($not,)* $($m,)*) ; $($rest)* }
    }
}

#[macro_export]
#[doc(hidden)]
macro_rules! __cfg_if_apply {
    ($m:meta, $($it:item)*) => {
        $(#[$m] $it)*
    }
}

#[cfg(test)]
mod tests {
    cfg_if! {
        if #[cfg(test)] {
            use core::option::Option as Option2;
            fn works1() -> Option2<u32> { Some(1) }
        } else {
            fn works1() -> Option<u32> { None }
        }
    }

    cfg_if! {
        if #[cfg(foo)] {
            fn works2() -> bool { false }
        } else if #[cfg(test)] {
            fn works2() -> bool { true }
        } else {
            fn works2() -> bool { false }
        }
    }

    cfg_if! {
        if #[cfg(foo)] {
            fn works3() -> bool { false }
        } else {
            fn works3() -> bool { true }
        }
    }

    cfg_if! {
        if #[cfg(test)] {
            use core::option::Option as Option3;
            fn works4() -> Option3<u32> { Some(1) }
        }
    }

    cfg_if! {
        if #[cfg(foo)] {
            fn works5() -> bool { false }
        } else if #[cfg(test)] {
            fn works5() -> bool { true }
        }
    }

    #[test]
    fn it_works() {
        assert!(works1().is_some());
        assert!(works2());
        assert!(works3());
        assert!(works4().is_some());
        assert!(works5());
    }
}
<commit_msg>Fix rustdoc intra-link failures<commit_after>//! A macro for defining `#[cfg]` if-else statements.
//!
//! The macro provided by this crate, `cfg_if`, is similar to the `if/elif` C
//! preprocessor macro by allowing definition of a cascade of `#[cfg]` cases,
//! emitting the implementation which matches first.
//!
//! This allows you to conveniently provide a long list `#[cfg]`'d blocks of code
//! without having to rewrite each clause multiple times.
//!
//! # Example
//!
//! ```
//! #[macro_use]
//! extern crate cfg_if;
//!
//! cfg_if! {
//!     if #[cfg(unix)] {
//!         fn foo() { /* unix specific functionality */ }
//!     } else if #[cfg(target_pointer_width = "32")] {
//!         fn foo() { /* non-unix, 32-bit functionality */ }
//!     } else {
//!         fn foo() { /* fallback implementation */ }
//!     }
//! }
//!
//! # fn main() {}
//! ```

#![no_std]

#![doc(html_root_url = "https://docs.rs/cfg-if")]
#![deny(missing_docs)]
#![cfg_attr(test, deny(warnings))]

#[macro_export]
macro_rules! cfg_if {
    ($(
        if #[cfg($($meta:meta),*)] { $($it:item)* }
    ) else * else {
        $($it2:item)*
    }) => {
        __cfg_if_items! {
            () ;
            $( ( ($($meta),*) ($($it)*) ), )*
            ( () ($($it2)*) ),
        }
    };
    (
        if #[cfg($($i_met:meta),*)] { $($i_it:item)* }
        $(
            else if #[cfg($($e_met:meta),*)] { $($e_it:item)* }
        )*
    ) => {
        __cfg_if_items! {
            () ;
            ( ($($i_met),*) ($($i_it)*) ),
            $( ( ($($e_met),*) ($($e_it)*) ), )*
            ( () () ),
        }
    }
}

#[macro_export]
#[doc(hidden)]
macro_rules! __cfg_if_items {
    (($($not:meta,)*) ; ) => {};
    (($($not:meta,)*) ; ( ($($m:meta),*) ($($it:item)*) ), $($rest:tt)*) => {
        __cfg_if_apply! { cfg(all($($m,)* not(any($($not),*)))), $($it)* }
        __cfg_if_items! { ($($not,)* $($m,)*) ; $($rest)* }
    }
}

#[macro_export]
#[doc(hidden)]
macro_rules! __cfg_if_apply {
    ($m:meta, $($it:item)*) => {
        $(#[$m] $it)*
    }
}

#[cfg(test)]
mod tests {
    cfg_if! {
        if #[cfg(test)] {
            use core::option::Option as Option2;
            fn works1() -> Option2<u32> { Some(1) }
        } else {
            fn works1() -> Option<u32> { None }
        }
    }

    cfg_if! {
        if #[cfg(foo)] {
            fn works2() -> bool { false }
        } else if #[cfg(test)] {
            fn works2() -> bool { true }
        } else {
            fn works2() -> bool { false }
        }
    }

    cfg_if! {
        if #[cfg(foo)] {
            fn works3() -> bool { false }
        } else {
            fn works3() -> bool { true }
        }
    }

    cfg_if! {
        if #[cfg(test)] {
            use core::option::Option as Option3;
            fn works4() -> Option3<u32> { Some(1) }
        }
    }

    cfg_if! {
        if #[cfg(foo)] {
            fn works5() -> bool { false }
        } else if #[cfg(test)] {
            fn works5() -> bool { true }
        }
    }

    #[test]
    fn it_works() {
        assert!(works1().is_some());
        assert!(works2());
        assert!(works3());
        assert!(works4().is_some());
        assert!(works5());
    }
}
<|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 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;

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

use std::path::Path;

pub fn compile<P1, P2>(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={}", 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());
    try!(::codegen::main(p.stdout.take().unwrap(),
                         ::std::path::Path::new(&::std::env::var("OUT_DIR").unwrap())));
    try!(p.wait());
    return Ok(());
}

<commit_msg>More helpful error message when the 'capnp' executable if not installed.<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 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;

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

use std::path::Path;

pub fn compile<P1, P2>(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={}", 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(());
}

<|endoftext|>


<commit_before>#![warn(missing_docs)]
//! # ulid-rs
//!
//! This is a Rust implementation of the [ulid][ulid] project which provides
//! Universally Unique Lexicographically Sortable Identifiers.
//!
//! [ulid]: https://github.com/alizain/ulid
//!
//!
//! ## Quickstart
//!
//! ```rust
//! # use ulid::Ulid;
//! // Generate a ulid
//! let ulid = Ulid::new();
//!
//! // Generate a string for a ulid
//! let s = ulid.to_string();
//!
//! // Create from a String
//! let res = Ulid::from_string(&s);
//! assert_eq!(ulid, res.unwrap());
//!
//! // Or using FromStr
//! let res = s.parse();
//! assert_eq!(ulid, res.unwrap());
//!
//! ```

use rand;

mod base32;

use std::str::FromStr;
use chrono::prelude::{DateTime, TimeZone, Utc};
use std::fmt;

pub use crate::base32::EncodingError;

/// A Ulid is a unique 128-bit lexicographically sortable identifier
///
/// Canonically, it is represented as a 26 character Crockford Base32 encoded
/// string.
///
/// Of the 128-bits, the first 48 are a unix timestamp in milliseconds. The
/// remaining 80 are random. The first 48 provide for lexicographic sorting and
/// the remaining 80 ensure that the identifier is unique.
#[derive(Debug, PartialOrd, PartialEq, Clone, Copy)]
pub struct Ulid(pub u128);

impl Ulid {
    /// Creates a new Ulid with the current time
    pub fn new() -> Ulid {
        Ulid::from_datetime(Utc::now())
    }

    /// Creates a new Ulid using data from the given random number generator
    pub fn with_source<R: rand::Rng>(source: &mut R) -> Ulid {
        Ulid::from_datetime_with_source(Utc::now(), source)
    }

    /// Creates a new Ulid with the given datetime
    ///
    /// This can be useful when migrating data to use Ulid identifiers
    pub fn from_datetime<T: TimeZone>(datetime: DateTime<T>) -> Ulid {
        Ulid::from_datetime_with_source(datetime, &mut rand::thread_rng())
    }

    /// Creates a new Ulid with the given datetime and random number generator
    pub fn from_datetime_with_source<T, R>(datetime: DateTime<T>, source: &mut R) -> Ulid
    where
        T: TimeZone,
        R: rand::Rng,
    {
        let timestamp = datetime.timestamp_millis();
        let timebits = (timestamp & ((1 << 48) - 1)) as u64;

        let msb = timebits << 16 | u64::from(source.gen::<u16>());
        let lsb = source.gen::<u64>();
        Ulid::from((msb, lsb))
    }

    /// Creates a Ulid from a Crockford Base32 encoded string
    ///
    /// An EncodingError will be returned when the given string is not formated
    /// properly.
    pub fn from_string(encoded: &str) -> Result<Ulid, EncodingError> {
        base32::decode(encoded).map(Ulid)
    }

    /// The 'nil Ulid'.
    ///
    /// The nil Ulid is special form of Ulid that is specified to have
    /// all 128 bits set to zero.
    ///
    /// # Examples
    ///
    /// ```rust
    /// use ulid::Ulid;
    ///
    /// let ulid = Ulid::nil();
    ///
    /// assert_eq!(
    ///     ulid.to_string(),
    ///     "00000000000000000000000000"
    /// );
    /// ```
    pub fn nil() -> Ulid {
        Ulid(0)
    }

    /// Gets the datetime of when this Ulid was created accurate to 1ms
    pub fn datetime(&self) -> DateTime<Utc> {
        let stamp = self.timestamp_ms();
        let secs = stamp / 1000;
        let millis = stamp % 1000;
        Utc.timestamp(secs as i64, (millis * 1_000_000) as u32)
    }

    /// Gets the timestamp section of this ulid
    pub fn timestamp_ms(&self) -> u64 {
        (self.0 >> 80) as u64
    }

    /// Creates a Crockford Base32 encoded string that represents this Ulid
    pub fn to_string(&self) -> String {
        base32::encode(self.0)
    }

    /// Test if the Ulid is nil
    ///
    /// # Examples
    ///
    /// ```rust
    /// use ulid::Ulid;
    ///
    /// let nil = Ulid::nil();
    ///
    /// assert!(nil.is_nil());
    /// ```
    pub fn is_nil(&self) -> bool {
        self.0 == 0u128
    }

    /// increment the random number, make sure that the ts millis stays the same
    fn increment(&self) -> Option<Ulid> {
        const MAX_RANDOM: u128 = (1 << 80) - 1;

        if (self.0 & MAX_RANDOM) == MAX_RANDOM {
            None
        } else {
            Some(Ulid(self.0 + 1))
        }
    }
}

impl Default for Ulid {
    fn default() -> Self {
        Ulid::nil()
    }
}

impl<'a> Into<String> for &'a Ulid {
    fn into(self) -> String {
        self.to_string()
    }
}

impl From<(u64, u64)> for Ulid {
    fn from((msb, lsb): (u64, u64)) -> Self {
        Ulid(u128::from(msb) << 64 | u128::from(lsb))
    }
}

impl Into<(u64, u64)> for Ulid {
    fn into(self) -> (u64, u64) {
        (
            (self.0 >> 64) as u64,
            (self.0 & 0xffff_ffff_ffff_ffff) as u64,
        )
    }
}

impl From<u128> for Ulid {
    fn from(value: u128) -> Ulid {
        Ulid(value)
    }
}

impl Into<u128> for Ulid {
    fn into(self) -> u128 {
        self.0
    }
}

impl FromStr for Ulid {
    type Err = EncodingError;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        Ulid::from_string(s)
    }
}

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

/// generator for monotonic ulids
pub struct Generator {
    previous: Option<Ulid>
}

/// error while trying to generate a monotonic increment in the same millisecond
#[derive(Debug, PartialEq)]
pub enum MonotonicError {
    /// would overflow into the next millisecond
    Overflow,
}

impl Generator {
    /// create a new ulid generator for monotonically ordered ulids
    pub fn new() -> Generator { Generator { previous: None } }

    /// use Utc::now to generate a monotonically ordered ulid
    pub fn generate(&mut self) -> Result<Ulid, MonotonicError> {
        let now = Utc::now();
        self.generate_from_datetime(now)
    }

    /// generate a new monotonically ordered ulid. will use previous calls timestamp to
    /// compare and make sure that each subsequent call is monotonically increasing
    ///
    /// # Example
    /// ```rust
    /// extern crate chrono;
    /// use chrono::Utc;
    /// use ulid::Generator;
    ///
    /// let dt = Utc::now();
    /// let mut gen = Generator::new();
    /// let ulid1 = gen.generate_from_datetime(dt).unwrap();
    /// let ulid2 = gen.generate_from_datetime(dt).unwrap();
    ///
    /// assert!(ulid1 < ulid2);
    /// ```
    pub fn generate_from_datetime<T: TimeZone>(&mut self, datetime: DateTime<T>) -> Result<Ulid, MonotonicError> {
        if let Some(prev) = self.previous {
            let last_ms = prev.timestamp_ms() as i64;
            // maybe time went backward, or it is the same ms.
            // increment instead of generating a new random so that it is monotonic
            if datetime.timestamp_millis() <= last_ms {
                if let Some(next) = prev.increment() {
                    self.previous = Some(next);
                    return Ok(next)
                } else {
                    return Err(MonotonicError::Overflow)
                }
            }
        }
        let next = Ulid::from_datetime(datetime);
        self.previous = Some(next);
        Ok(next)
    }
}

#[cfg(test)]
mod tests {
    use super::Ulid;
    use chrono::prelude::*;
    use chrono::Duration;
    use super::Generator;

    #[test]
    fn test_dynamic() {
        let ulid = Ulid::new();
        let encoded = ulid.to_string();
        let ulid2 = Ulid::from_string(&encoded).expect("failed to deserialize");

        println!("{}", encoded);
        println!("{:?}", ulid);
        println!("{:?}", ulid2);
        assert_eq!(ulid, ulid2);
    }

    #[test]
    fn test_static() {
        let s = Ulid(0x41414141414141414141414141414141).to_string();
        let u = Ulid::from_string(&s).unwrap();
        assert_eq!(&s, "21850M2GA1850M2GA1850M2GA1");
        assert_eq!(u.0, 0x41414141414141414141414141414141);
    }

    #[test]
    fn test_source() {
        use rand::rngs::OsRng;
        let mut source = OsRng::new().expect("could not create OS Rng");

        let u1 = Ulid::with_source(&mut source);
        let dt = Utc::now() + Duration::milliseconds(1);
        let u2 = Ulid::from_datetime_with_source(dt, &mut source);
        let u3 = Ulid::from_datetime_with_source(dt, &mut source);

        assert!(u1 < u2);
        assert!(u2 != u3);
    }

    #[test]
    fn test_order() {
        let dt = Utc::now();
        let ulid1 = Ulid::from_datetime(dt);
        let ulid2 = Ulid::from_datetime(dt + Duration::milliseconds(1));
        assert!(ulid1 < ulid2);
    }

    #[test]
    fn test_order_monotonic() {
        let dt = Utc::now();
        let mut gen = Generator::new();
        let ulid1 = gen.generate_from_datetime(dt).unwrap();
        let ulid2 = gen.generate_from_datetime(dt).unwrap();
        let ulid3 = Ulid::from_datetime(dt + Duration::milliseconds(1));
        assert_eq!(ulid1.0 + 1, ulid2.0);
        assert!(ulid2 < ulid3);
        assert!(ulid2.timestamp_ms() < ulid3.timestamp_ms())
    }

    #[test]
    fn test_increment() {
        let ulid = Ulid::from_string("01BX5ZZKBKZZZZZZZZZZZZZZZX").unwrap();
        let ulid = ulid.increment().unwrap();
        assert_eq!("01BX5ZZKBKZZZZZZZZZZZZZZZY", ulid.to_string());
        let ulid = ulid.increment().unwrap();
        assert_eq!("01BX5ZZKBKZZZZZZZZZZZZZZZZ", ulid.to_string());
        assert!(ulid.increment().is_none());
    }

    #[test]
    fn test_increment_overflow() {
        let ulid = Ulid(u128::max_value());
        assert!(ulid.increment().is_none());
    }

    #[test]
    fn test_datetime() {
        let dt = Utc::now();
        let ulid = Ulid::from_datetime(dt);

        println!("{:?}, {:?}", dt, ulid.datetime());
        assert!(ulid.datetime() <= dt);
        assert!(ulid.datetime() + Duration::milliseconds(1) >= dt);
    }

    #[test]
    fn test_timestamp() {
        let dt = Utc::now();
        let ulid = Ulid::from_datetime(dt);
        let ts = dt.timestamp() as u64 * 1000 + dt.timestamp_subsec_millis() as u64;

        assert_eq!(ulid.timestamp_ms(), ts);
    }
}
<commit_msg>Add with_source constructor to Generator<commit_after>#![warn(missing_docs)]
//! # ulid-rs
//!
//! This is a Rust implementation of the [ulid][ulid] project which provides
//! Universally Unique Lexicographically Sortable Identifiers.
//!
//! [ulid]: https://github.com/alizain/ulid
//!
//!
//! ## Quickstart
//!
//! ```rust
//! # use ulid::Ulid;
//! // Generate a ulid
//! let ulid = Ulid::new();
//!
//! // Generate a string for a ulid
//! let s = ulid.to_string();
//!
//! // Create from a String
//! let res = Ulid::from_string(&s);
//! assert_eq!(ulid, res.unwrap());
//!
//! // Or using FromStr
//! let res = s.parse();
//! assert_eq!(ulid, res.unwrap());
//!
//! ```

use rand;

mod base32;

use chrono::prelude::{DateTime, TimeZone, Utc};
use std::fmt;
use std::str::FromStr;

pub use crate::base32::EncodingError;

/// A Ulid is a unique 128-bit lexicographically sortable identifier
///
/// Canonically, it is represented as a 26 character Crockford Base32 encoded
/// string.
///
/// Of the 128-bits, the first 48 are a unix timestamp in milliseconds. The
/// remaining 80 are random. The first 48 provide for lexicographic sorting and
/// the remaining 80 ensure that the identifier is unique.
#[derive(Debug, PartialOrd, PartialEq, Clone, Copy)]
pub struct Ulid(pub u128);

impl Ulid {
    /// Creates a new Ulid with the current time
    pub fn new() -> Ulid {
        Ulid::from_datetime(Utc::now())
    }

    /// Creates a new Ulid using data from the given random number generator
    pub fn with_source<R: rand::Rng>(source: &mut R) -> Ulid {
        Ulid::from_datetime_with_source(Utc::now(), source)
    }

    /// Creates a new Ulid with the given datetime
    ///
    /// This can be useful when migrating data to use Ulid identifiers
    pub fn from_datetime<T: TimeZone>(datetime: DateTime<T>) -> Ulid {
        Ulid::from_datetime_with_source(datetime, &mut rand::thread_rng())
    }

    /// Creates a new Ulid with the given datetime and random number generator
    pub fn from_datetime_with_source<T, R>(datetime: DateTime<T>, source: &mut R) -> Ulid
    where
        T: TimeZone,
        R: rand::Rng,
    {
        let timestamp = datetime.timestamp_millis();
        let timebits = (timestamp & ((1 << 48) - 1)) as u64;

        let msb = timebits << 16 | u64::from(source.gen::<u16>());
        let lsb = source.gen::<u64>();
        Ulid::from((msb, lsb))
    }

    /// Creates a Ulid from a Crockford Base32 encoded string
    ///
    /// An EncodingError will be returned when the given string is not formated
    /// properly.
    pub fn from_string(encoded: &str) -> Result<Ulid, EncodingError> {
        base32::decode(encoded).map(Ulid)
    }

    /// The 'nil Ulid'.
    ///
    /// The nil Ulid is special form of Ulid that is specified to have
    /// all 128 bits set to zero.
    ///
    /// # Examples
    ///
    /// ```rust
    /// use ulid::Ulid;
    ///
    /// let ulid = Ulid::nil();
    ///
    /// assert_eq!(
    ///     ulid.to_string(),
    ///     "00000000000000000000000000"
    /// );
    /// ```
    pub fn nil() -> Ulid {
        Ulid(0)
    }

    /// Gets the datetime of when this Ulid was created accurate to 1ms
    pub fn datetime(&self) -> DateTime<Utc> {
        let stamp = self.timestamp_ms();
        let secs = stamp / 1000;
        let millis = stamp % 1000;
        Utc.timestamp(secs as i64, (millis * 1_000_000) as u32)
    }

    /// Gets the timestamp section of this ulid
    pub fn timestamp_ms(&self) -> u64 {
        (self.0 >> 80) as u64
    }

    /// Creates a Crockford Base32 encoded string that represents this Ulid
    pub fn to_string(&self) -> String {
        base32::encode(self.0)
    }

    /// Test if the Ulid is nil
    ///
    /// # Examples
    ///
    /// ```rust
    /// use ulid::Ulid;
    ///
    /// let nil = Ulid::nil();
    ///
    /// assert!(nil.is_nil());
    /// ```
    pub fn is_nil(&self) -> bool {
        self.0 == 0u128
    }

    /// increment the random number, make sure that the ts millis stays the same
    fn increment(&self) -> Option<Ulid> {
        const MAX_RANDOM: u128 = (1 << 80) - 1;

        if (self.0 & MAX_RANDOM) == MAX_RANDOM {
            None
        } else {
            Some(Ulid(self.0 + 1))
        }
    }
}

impl Default for Ulid {
    fn default() -> Self {
        Ulid::nil()
    }
}

impl<'a> Into<String> for &'a Ulid {
    fn into(self) -> String {
        self.to_string()
    }
}

impl From<(u64, u64)> for Ulid {
    fn from((msb, lsb): (u64, u64)) -> Self {
        Ulid(u128::from(msb) << 64 | u128::from(lsb))
    }
}

impl Into<(u64, u64)> for Ulid {
    fn into(self) -> (u64, u64) {
        (
            (self.0 >> 64) as u64,
            (self.0 & 0xffff_ffff_ffff_ffff) as u64,
        )
    }
}

impl From<u128> for Ulid {
    fn from(value: u128) -> Ulid {
        Ulid(value)
    }
}

impl Into<u128> for Ulid {
    fn into(self) -> u128 {
        self.0
    }
}

impl FromStr for Ulid {
    type Err = EncodingError;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        Ulid::from_string(s)
    }
}

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

/// error while trying to generate a monotonic increment in the same millisecond
#[derive(Debug, PartialEq)]
pub enum MonotonicError {
    /// would overflow into the next millisecond
    Overflow,
}

/// A Ulid generator that provides monotonically increasing Ulids
pub struct Generator {
    previous: Ulid,
    source: Box<rand::RngCore>,
}

impl Generator {
    /// Create a new ulid generator for monotonically ordered ulids
    pub fn new() -> Generator {
        Self::with_source(rand::thread_rng())
    }

    /// Create a new ulid generator for monotonically ordered ulids using the given rng
    ///
    /// ```rust
    /// # use ulid::Generator;
    /// use rand::rngs::SmallRng;
    /// use rand::FromEntropy;
    ///
    /// let mut gen = Generator::with_source(rand::rngs::SmallRng::from_entropy());
    ///
    /// let ulid1 = gen.generate().unwrap();
    /// let ulid2 = gen.generate().unwrap();
    ///
    /// assert!(ulid1 < ulid2);
    /// ```
    pub fn with_source<R: rand::RngCore + 'static>(source: R) -> Generator {
        Generator {
            previous: Ulid::nil(),
            source: Box::new(source),
        }
    }

    /// Generate a new Ulid. Each call is guaranteed to provide a Ulid with a larger value than the
    /// last call. If the random bits would overflow, this method will return an error.
    pub fn generate(&mut self) -> Result<Ulid, MonotonicError> {
        let now = Utc::now();
        self.generate_from_datetime(now)
    }

    /// Generate a new Ulid matching the given DateTime. Each call is guaranteed to provide a Ulid
    /// with a larger value than the last call. If the random bits would overflow, this method will
    /// return an error.
    ///
    /// # Example
    /// ```rust
    /// # use ulid::Generator;
    /// use chrono::Utc;
    ///
    /// let dt = Utc::now();
    /// let mut gen = Generator::new();
    /// let ulid1 = gen.generate_from_datetime(dt).unwrap();
    /// let ulid2 = gen.generate_from_datetime(dt).unwrap();
    ///
    /// assert!(ulid1 < ulid2);
    /// ```
    pub fn generate_from_datetime<T: TimeZone>(
        &mut self,
        datetime: DateTime<T>,
    ) -> Result<Ulid, MonotonicError> {
        let last_ms = self.previous.timestamp_ms() as i64;
        // maybe time went backward, or it is the same ms.
        // increment instead of generating a new random so that it is monotonic
        if datetime.timestamp_millis() <= last_ms {
            if let Some(next) = self.previous.increment() {
                self.previous = next;
                return Ok(next);
            } else {
                return Err(MonotonicError::Overflow);
            }
        }
        let next = Ulid::from_datetime_with_source(datetime, &mut self.source);
        self.previous = next;
        Ok(next)
    }
}

impl Default for Generator {
    fn default() -> Self {
        Self::new()
    }
}

#[cfg(test)]
mod tests {
    use super::Generator;
    use super::Ulid;
    use chrono::prelude::*;
    use chrono::Duration;

    #[test]
    fn test_dynamic() {
        let ulid = Ulid::new();
        let encoded = ulid.to_string();
        let ulid2 = Ulid::from_string(&encoded).expect("failed to deserialize");

        println!("{}", encoded);
        println!("{:?}", ulid);
        println!("{:?}", ulid2);
        assert_eq!(ulid, ulid2);
    }

    #[test]
    fn test_static() {
        let s = Ulid(0x41414141414141414141414141414141).to_string();
        let u = Ulid::from_string(&s).unwrap();
        assert_eq!(&s, "21850M2GA1850M2GA1850M2GA1");
        assert_eq!(u.0, 0x41414141414141414141414141414141);
    }

    #[test]
    fn test_source() {
        use rand::rngs::mock::StepRng;
        let mut source = StepRng::new(123, 0);

        let u1 = Ulid::with_source(&mut source);
        let dt = Utc::now() + Duration::milliseconds(1);
        let u2 = Ulid::from_datetime_with_source(dt, &mut source);
        let u3 = Ulid::from_datetime_with_source(dt, &mut source);

        assert!(u1 < u2);
        assert!(u2 == u3);
    }

    #[test]
    fn test_order() {
        let dt = Utc::now();
        let ulid1 = Ulid::from_datetime(dt);
        let ulid2 = Ulid::from_datetime(dt + Duration::milliseconds(1));
        assert!(ulid1 < ulid2);
    }

    #[test]
    fn test_order_monotonic() {
        let dt = Utc::now();
        let mut gen = Generator::new();
        let ulid1 = gen.generate_from_datetime(dt).unwrap();
        let ulid2 = gen.generate_from_datetime(dt).unwrap();
        let ulid3 = Ulid::from_datetime(dt + Duration::milliseconds(1));
        assert_eq!(ulid1.0 + 1, ulid2.0);
        assert!(ulid2 < ulid3);
        assert!(ulid2.timestamp_ms() < ulid3.timestamp_ms())
    }

    #[test]
    fn test_increment() {
        let ulid = Ulid::from_string("01BX5ZZKBKZZZZZZZZZZZZZZZX").unwrap();
        let ulid = ulid.increment().unwrap();
        assert_eq!("01BX5ZZKBKZZZZZZZZZZZZZZZY", ulid.to_string());
        let ulid = ulid.increment().unwrap();
        assert_eq!("01BX5ZZKBKZZZZZZZZZZZZZZZZ", ulid.to_string());
        assert!(ulid.increment().is_none());
    }

    #[test]
    fn test_increment_overflow() {
        let ulid = Ulid(u128::max_value());
        assert!(ulid.increment().is_none());
    }

    #[test]
    fn test_datetime() {
        let dt = Utc::now();
        let ulid = Ulid::from_datetime(dt);

        println!("{:?}, {:?}", dt, ulid.datetime());
        assert!(ulid.datetime() <= dt);
        assert!(ulid.datetime() + Duration::milliseconds(1) >= dt);
    }

    #[test]
    fn test_timestamp() {
        let dt = Utc::now();
        let ulid = Ulid::from_datetime(dt);
        let ts = dt.timestamp() as u64 * 1000 + dt.timestamp_subsec_millis() as u64;

        assert_eq!(ulid.timestamp_ms(), ts);
    }
}
<|endoftext|>


<commit_before>extern crate rustc_serialize;
extern crate regex;

// mod image_base64 {
use std::fs::File;
use rustc_serialize::base64::{FromBase64, ToBase64, MIME};
use rustc_serialize::hex::{ToHex};
use regex::Regex;
use std::io::Read;
use std::string::String;
use std::path::Path;
use std::io::Write;

fn get_file_type(hex: &str) -> &str {
    if Regex::new(r"^ffd8ffe0").unwrap().is_match(hex) {
        return "jpeg"
    } else if Regex::new(r"^89504e47").unwrap().is_match(hex) {
        return "png"
    } else if Regex::new(r"^47494638").unwrap().is_match(hex) {
        return "gif"
    }
    panic!("invalid file type")
}

 fn to_base64(path: &str) -> String {
    let mut file = File::open(path).unwrap();
    let mut vec = Vec::new();
    let _ = file.read_to_end(&mut vec);
    let base64 = vec.to_base64(MIME);
    let hex = vec.to_hex();
    return format!("data:image/{};base64,{}", get_file_type(&hex), base64.replace("\r\n", ""));
}

 fn from_base64(base64: String) -> Vec<u8> {
    let offset = base64.find(',').unwrap_or(base64.len())+1;
    let mut value = base64;
    value.drain(..offset);
    return value.from_base64().unwrap();
}

#[cfg(test)]
mod test {
    use super::*;
    use std::fs::File;
    use std::io::Read;
    use std::io::Error;

    #[test]
    fn jpg_to_base64() {
        image_to_base64("jpg");
    }

    #[test]
    fn gif_to_base64() {
        image_to_base64("gif");
    }

    #[test]
    fn png_to_base64() {
        image_to_base64("png");
    }

    fn image_to_base64(file_type : &str) {
        let mut file = match File::open(format!("res/{}_data", file_type)) {
            Err(why) => panic!("couldn't open {}", why),
            Ok(file) => file,
        };
        let mut buffer = String::new();
        match file.read_to_string(&mut buffer) {
            Err(why) => panic!("couldn't read {}", why),
            Ok(_) => {},
        }
        let base64 = to_base64(&format!("res/nyan.{}", file_type));
        assert_eq!(base64, buffer);
    }
}<commit_msg>add test converting base64 to image<commit_after>extern crate rustc_serialize;
extern crate regex;

// mod image_base64 {
use std::fs::File;
use rustc_serialize::base64::{FromBase64, ToBase64, MIME};
use rustc_serialize::hex::{ToHex};
use regex::Regex;
use std::io::Read;
use std::string::String;
use std::path::Path;
use std::io::Write;

fn get_file_type(hex: &str) -> &str {
    if Regex::new(r"^ffd8ffe0").unwrap().is_match(hex) {
        return "jpeg"
    } else if Regex::new(r"^89504e47").unwrap().is_match(hex) {
        return "png"
    } else if Regex::new(r"^47494638").unwrap().is_match(hex) {
        return "gif"
    }
    panic!("invalid file type")
}

 fn to_base64(path: &str) -> String {
    let mut file = File::open(path).unwrap();
    let mut vec = Vec::new();
    let _ = file.read_to_end(&mut vec);
    let base64 = vec.to_base64(MIME);
    let hex = vec.to_hex();
    return format!("data:image/{};base64,{}", get_file_type(&hex), base64.replace("\r\n", ""));
}

 fn from_base64(base64: String) -> Vec<u8> {
    let offset = base64.find(',').unwrap_or(base64.len())+1;
    let mut value = base64;
    value.drain(..offset);
    return value.from_base64().unwrap();
}

#[cfg(test)]
mod test {
    use super::*;
    use std::fs::File;
    use std::io::Read;
    use std::io::Error;

    #[test]
    fn jpg_to_base64() {
        image_to_base64("jpg");
    }

    #[test]
    fn gif_to_base64() {
        image_to_base64("gif");
    }

    #[test]
    fn png_to_base64() {
        image_to_base64("png");
    }

    fn image_to_base64(file_type : &str) {
        let mut file = match File::open(format!("res/{}_data", file_type)) {
            Err(why) => panic!("couldn't open {}", why),
            Ok(file) => file,
        };
        let mut buffer = String::new();
        match file.read_to_string(&mut buffer) {
            Err(why) => panic!("couldn't read {}", why),
            Ok(_) => {},
        }
        let base64 = to_base64(&format!("res/nyan.{}", file_type));
        assert_eq!(base64, buffer);
    }

    #[test]
    fn base64_to_jpg() {
        base64_to_image("jpg");
    }

    #[test]
    fn base64_to_gif() {
        base64_to_image("gif");
    }

    #[test]
    fn base64_to_png() {
        base64_to_image("png");
    }

    fn base64_to_image(file_type : &str) {
        let mut file = match File::open(format!("res/{}_data", file_type)) {
            Err(why) => panic!("couldn't open {}", why),
            Ok(file) => file,
        };
        let mut base64 = String::new();
        match file.read_to_string(&mut base64) {
            Err(why) => panic!("couldn't read {}", why),
            Ok(_) => {},
        }
        let img = from_base64(base64);
        let mut file = File::create(&Path::new(&format!("output/test.{}", file_type))).unwrap();
        file.write_all(img.as_slice()).unwrap();
    }
}<|endoftext|>


<commit_before>#![feature(plugin_registrar, box_syntax, rustc_private, custom_derive, quote)]

#[macro_use]
extern crate rustc;
extern crate rustc_front;
extern crate rustc_plugin;
#[macro_use]
extern crate syntax;
extern crate syntax_ext;

use rustc_plugin::Registry;
use syntax::parse::token::intern;
use syntax::ext::base::MultiDecorator;

const INFIX_OPS: &'static [&'static str] = &["Add", "Sub", "Mul", "Div", "Rem", "BitAnd", "BitOr", "BitXor"];

#[plugin_registrar]
pub fn plugin_registrar(reg: &mut Registry) {
    reg.register_syntax_extension(intern("derive_From"), MultiDecorator(box expand_derive_from));
    for op in INFIX_OPS {
        let expand = move |cx: &mut ExtCtxt, span: Span, _: &MetaItem, item: &Annotatable, push: &mut FnMut(Annotatable)| {
            expand_derive_infix_op(cx, span, item, push, op)
        };
        reg.register_syntax_extension(intern(&format!("derive_{}", op)), MultiDecorator(box expand));
    }
}

use std::collections::HashMap;

use syntax::ast::*;
use syntax::codemap::Span;
use syntax::ext::base::{Annotatable, ExtCtxt};
use syntax::ext::build::AstBuilder;
use syntax::ext::quote::rt::ExtParseUtils;
use syntax::ptr::P;
use syntax::print::pprust::ty_to_string;

/// Provides the hook to expand `#[derive(From)]` into an implementation of `From`
fn expand_derive_from(cx: &mut ExtCtxt, span: Span, _: &MetaItem,
                          item: &Annotatable, push: &mut FnMut(Annotatable)) {

    // Get the that is wrapped by the newtype and do some checks
    let failed = match *item {
        Annotatable::Item(ref x) => {
            match x.node {
                ItemKind::Struct(VariantData::Tuple(ref structs, _), _) => {
                    if structs.len() == 1 {
                        newtype_from(cx, x.ident, structs[0].node.ty.clone(), push);
                        false
                    }
                    else {
                        true
                    }
                },
                ItemKind::Enum(ref definition, _) => {
                    enum_from(cx, x.ident, definition, push);
                    false

                }
                _ => true,
            }
        },
        _ => true,
    };

    if failed {
        cx.span_bug(span, "only newtype structs can use `derive(From)`");
    }
}

fn newtype_from(cx: &mut ExtCtxt, ident: Ident, old_type: P<Ty>,
                push: &mut FnMut(Annotatable)) {
    let code = quote_item!(cx,
        impl ::std::convert::From<$old_type> for $ident {
            fn from(a: $old_type) -> $ident {
                $ident(a)
            }
        }
    ).unwrap();

    push(Annotatable::Item(code));
}

fn enum_from(cx: &mut ExtCtxt, enum_ident: Ident, definition: &EnumDef,
             push: &mut FnMut(Annotatable)) {
    let mut types = vec![];
    let mut idents = vec![];
    let mut type_counts = HashMap::new();

    for variant in &definition.variants {
        match variant.node.data {
            VariantData::Tuple(ref structs, _) => {
                if structs.len() == 1 {
                    let ty = structs[0].node.ty.clone();
                    idents.push(variant.node.name);
                    types.push(ty.clone());
                    let counter = type_counts.entry(ty_to_string(&*ty)).or_insert(0);
                    *counter += 1;
                }
            }
            _ => (),
        }
    }

    for (ident, old_type) in idents.iter().zip(types) {
        if *type_counts.get(&ty_to_string(&*old_type)).unwrap() != 1 {
            // If more than one newtype is present don't add automatic From, since it is
            // ambiguous.
            continue
        }

        let code = quote_item!(cx,
            impl ::std::convert::From<$old_type> for $enum_ident {
                fn from(a: $old_type) -> $enum_ident {
                    $enum_ident::$ident(a)
                }
            }
        ).unwrap();

        push(Annotatable::Item(code));
    }
}

fn expand_derive_infix_op(cx: &mut ExtCtxt, span: Span, item: &Annotatable,
                          push: &mut FnMut(Annotatable), trait_name: &str) {
    let trait_name = trait_name.to_string();
    let method_name = trait_name.to_lowercase();
    let method_ident = cx.ident_of(&method_name);
    // Get the that is wrapped by the newtype and do some checks
    let result = match *item {
        Annotatable::Item(ref x) => {
            match x.node {
                ItemKind::Struct(VariantData::Tuple(ref fields, _), _) => {
                    Some((x.ident, cx.ty_ident(span, x.ident), tuple_infix_op_content(cx, span, x, fields, method_name)))
                },

                ItemKind::Struct(VariantData::Struct(ref fields, _), _) => {
                    Some((x.ident, cx.ty_ident(span, x.ident), struct_infix_op_content(cx, span, x, fields, method_name)))
                },

                ItemKind::Enum(ref definition, _) => {
                    let input_type = x.ident;
                    Some((x.ident, quote_ty!(cx, Result<$input_type, &'static str>), enum_infix_op_content(cx, span, x, definition, method_name)))
                },

                _ => None,
            }
        },
        _ => None,
    };

    let (input_type, output_type, block) = match result {
        Some(x) => x,
        _ => {
            cx.span_fatal(span, &format!("only structs can use `derive({})`", trait_name))
        },
    };

    let trait_path = cx.path_global(span, cx.std_path(&["ops", &trait_name]));

    let code = quote_item!(cx,
        impl $trait_path for $input_type {
            type Output = $output_type;
            fn $method_ident(self, rhs: $input_type) -> $output_type {
                $block
            }
        }
    ).unwrap();

    push(Annotatable::Item(code));

}

fn tuple_infix_op_content(cx: &mut ExtCtxt, span: Span, item: &P<Item>, fields: &Vec<StructField>, method_name: String) -> P<Expr> {
    let type_name = item.ident;
    let mut exprs: Vec<P<Expr>>= vec![];

    for i in 0..fields.len() {
        let i = &i.to_string();
        exprs.push(cx.parse_expr(format!("self.{}.{}(rhs.{})", i, method_name, i)));
    }

    cx.expr_call_ident(span, type_name, exprs)
}

fn struct_infix_op_content(cx: &mut ExtCtxt, span: Span, item: &P<Item>, fields: &Vec<StructField>, method_name: String) -> P<Expr> {
    let type_name = item.ident;
    let mut filled_fields = vec![];

    for field in fields {
        let (field_id, field_name) = match field.node.kind {
            NamedField(x, _) => (x, x.name.as_str()),
            _ => unreachable!(),

        };
        filled_fields.push(cx.field_imm(span, field_id,
                                        cx.parse_expr(format!("self.{}.{}(rhs.{})", field_name, method_name, field_name))));
    }

    cx.expr_struct_ident(span, type_name, filled_fields)
}

fn enum_infix_op_content(cx: &mut ExtCtxt, span: Span, item: &P<Item>, fields: &EnumDef, method_name: String) -> P<Expr> {
    let mut matches: Vec<Arm> = vec![];
    let enum_ident = item.ident;

    for variant in &fields.variants {
        let ident = variant.node.name;
        matches.push(quote_arm!(cx, ($enum_ident::$ident(l), $enum_ident::$ident(r)) => Ok($enum_ident::$ident(l + r)),));
    }

    matches.push(quote_arm!(cx, _ => Err("Trying to add mismatched enum types"), ));
    cx.expr_match(span, quote_expr!(cx, (self, rhs)), matches)
}
<commit_msg>Change method call to quote macro<commit_after>#![feature(plugin_registrar, box_syntax, rustc_private, custom_derive, quote)]

#[macro_use]
extern crate rustc;
extern crate rustc_front;
extern crate rustc_plugin;
#[macro_use]
extern crate syntax;
extern crate syntax_ext;

use rustc_plugin::Registry;
use syntax::parse::token::intern;
use syntax::ext::base::MultiDecorator;

const INFIX_OPS: &'static [&'static str] = &["Add", "Sub", "Mul", "Div", "Rem", "BitAnd", "BitOr", "BitXor"];

#[plugin_registrar]
pub fn plugin_registrar(reg: &mut Registry) {
    reg.register_syntax_extension(intern("derive_From"), MultiDecorator(box expand_derive_from));
    for op in INFIX_OPS {
        let expand = move |cx: &mut ExtCtxt, span: Span, _: &MetaItem, item: &Annotatable, push: &mut FnMut(Annotatable)| {
            expand_derive_infix_op(cx, span, item, push, op)
        };
        reg.register_syntax_extension(intern(&format!("derive_{}", op)), MultiDecorator(box expand));
    }
}

use std::collections::HashMap;

use syntax::ast::*;
use syntax::codemap::Span;
use syntax::ext::base::{Annotatable, ExtCtxt};
use syntax::ext::build::AstBuilder;
use syntax::ext::quote::rt::ExtParseUtils;
use syntax::ptr::P;
use syntax::print::pprust::ty_to_string;

/// Provides the hook to expand `#[derive(From)]` into an implementation of `From`
fn expand_derive_from(cx: &mut ExtCtxt, span: Span, _: &MetaItem,
                          item: &Annotatable, push: &mut FnMut(Annotatable)) {

    // Get the that is wrapped by the newtype and do some checks
    let failed = match *item {
        Annotatable::Item(ref x) => {
            match x.node {
                ItemKind::Struct(VariantData::Tuple(ref structs, _), _) => {
                    if structs.len() == 1 {
                        newtype_from(cx, x.ident, structs[0].node.ty.clone(), push);
                        false
                    }
                    else {
                        true
                    }
                },
                ItemKind::Enum(ref definition, _) => {
                    enum_from(cx, x.ident, definition, push);
                    false

                }
                _ => true,
            }
        },
        _ => true,
    };

    if failed {
        cx.span_bug(span, "only newtype structs can use `derive(From)`");
    }
}

fn newtype_from(cx: &mut ExtCtxt, ident: Ident, old_type: P<Ty>,
                push: &mut FnMut(Annotatable)) {
    let code = quote_item!(cx,
        impl ::std::convert::From<$old_type> for $ident {
            fn from(a: $old_type) -> $ident {
                $ident(a)
            }
        }
    ).unwrap();

    push(Annotatable::Item(code));
}

fn enum_from(cx: &mut ExtCtxt, enum_ident: Ident, definition: &EnumDef,
             push: &mut FnMut(Annotatable)) {
    let mut types = vec![];
    let mut idents = vec![];
    let mut type_counts = HashMap::new();

    for variant in &definition.variants {
        match variant.node.data {
            VariantData::Tuple(ref structs, _) => {
                if structs.len() == 1 {
                    let ty = structs[0].node.ty.clone();
                    idents.push(variant.node.name);
                    types.push(ty.clone());
                    let counter = type_counts.entry(ty_to_string(&*ty)).or_insert(0);
                    *counter += 1;
                }
            }
            _ => (),
        }
    }

    for (ident, old_type) in idents.iter().zip(types) {
        if *type_counts.get(&ty_to_string(&*old_type)).unwrap() != 1 {
            // If more than one newtype is present don't add automatic From, since it is
            // ambiguous.
            continue
        }

        let code = quote_item!(cx,
            impl ::std::convert::From<$old_type> for $enum_ident {
                fn from(a: $old_type) -> $enum_ident {
                    $enum_ident::$ident(a)
                }
            }
        ).unwrap();

        push(Annotatable::Item(code));
    }
}

fn expand_derive_infix_op(cx: &mut ExtCtxt, span: Span, item: &Annotatable,
                          push: &mut FnMut(Annotatable), trait_name: &str) {
    let trait_name = trait_name.to_string();
    let method_name = trait_name.to_lowercase();
    let method_ident = cx.ident_of(&method_name);
    // Get the that is wrapped by the newtype and do some checks
    let result = match *item {
        Annotatable::Item(ref x) => {
            match x.node {
                ItemKind::Struct(VariantData::Tuple(ref fields, _), _) => {
                    Some((x.ident, cx.ty_ident(span, x.ident), tuple_infix_op_content(cx, span, x, fields, method_name)))
                },

                ItemKind::Struct(VariantData::Struct(ref fields, _), _) => {
                    Some((x.ident, cx.ty_ident(span, x.ident), struct_infix_op_content(cx, span, x, fields, method_name)))
                },

                ItemKind::Enum(ref definition, _) => {
                    let input_type = x.ident;
                    Some((x.ident, quote_ty!(cx, Result<$input_type, &'static str>), enum_infix_op_content(cx, span, x, definition, method_name)))
                },

                _ => None,
            }
        },
        _ => None,
    };

    let (input_type, output_type, block) = match result {
        Some(x) => x,
        _ => {
            cx.span_fatal(span, &format!("only structs can use `derive({})`", trait_name))
        },
    };

    let trait_path = cx.path_global(span, cx.std_path(&["ops", &trait_name]));

    let code = quote_item!(cx,
        impl $trait_path for $input_type {
            type Output = $output_type;
            fn $method_ident(self, rhs: $input_type) -> $output_type {
                $block
            }
        }
    ).unwrap();

    push(Annotatable::Item(code));

}

fn tuple_infix_op_content(cx: &mut ExtCtxt, span: Span, item: &P<Item>, fields: &Vec<StructField>, method_name: String) -> P<Expr> {
    let type_name = item.ident;
    let mut exprs: Vec<P<Expr>>= vec![];

    for i in 0..fields.len() {
        let i = &i.to_string();
        exprs.push(cx.parse_expr(format!("self.{}.{}(rhs.{})", i, method_name, i)));
    }

    cx.expr_call_ident(span, type_name, exprs)
}

fn struct_infix_op_content(cx: &mut ExtCtxt, span: Span, item: &P<Item>, fields: &Vec<StructField>, method_name: String) -> P<Expr> {
    let type_name = item.ident;
    let mut filled_fields = vec![];

    for field in fields {
        let (field_id, field_name) = match field.node.kind {
            NamedField(x, _) => (x, x.name.as_str()),
            _ => unreachable!(),

        };
        filled_fields.push(cx.field_imm(span, field_id,
                                        cx.parse_expr(format!("self.{}.{}(rhs.{})", field_name, method_name, field_name))));
    }

    cx.expr_struct_ident(span, type_name, filled_fields)
}

fn enum_infix_op_content(cx: &mut ExtCtxt, span: Span, item: &P<Item>, fields: &EnumDef, method_name: String) -> P<Expr> {
    let mut matches: Vec<Arm> = vec![];
    let enum_ident = item.ident;

    for variant in &fields.variants {
        let ident = variant.node.name;
        matches.push(quote_arm!(cx, ($enum_ident::$ident(l), $enum_ident::$ident(r)) => Ok($enum_ident::$ident(l + r)),));
    }

    matches.push(quote_arm!(cx, _ => Err("Trying to add mismatched enum types"), ));
    quote_expr!(cx, match (self, rhs) { $matches })
}
<|endoftext|>