<commit_before>#[cfg(target_os = "windows")]
extern crate shell32;
#[cfg(target_os = "windows")]
extern crate winapi;
#[cfg(target_os = "windows")]
extern crate ole32;

#[cfg(not(target_os = "windows"))]
use std::env;
use std::path::PathBuf;

#[cfg(target_os = "macos")]
fn home_dir_relative(rel: &str, app: Option<&str>) -> PathBuf {
    let mut data_dir = env::home_dir().unwrap();
    data_dir.push(rel);
    if app.is_some() {
        data_dir.push(app.unwrap());
    }
    data_dir
}

#[cfg(target_os = "macos")]
pub fn user_data_dir(app: Option<&str>, _: Option<&str>, _: bool) -> PathBuf {
    home_dir_relative("Library/Application Support", app)
}

#[cfg(target_os = "macos")]
pub fn site_data_dir(app: Option<&str>, _: Option<&str>) -> PathBuf {
    let mut data_dir = PathBuf::new();
    data_dir.push("/Library/Application Support");
    if app.is_some() {
        data_dir.push(app.unwrap());
    }
    data_dir
}

#[cfg(target_os = "macos")]
pub fn user_config_dir(app: Option<&str>, author: Option<&str>, roaming: bool) -> PathBuf {
    user_data_dir(app, author, roaming)
}

#[cfg(target_os = "macos")]
pub fn site_config_dir(app: Option<&str>, author: Option<&str>) -> PathBuf {
    site_data_dir(app, author)
}

#[cfg(target_os = "macos")]
pub fn user_cache_dir(app: Option<&str>, _: Option<&str>) -> PathBuf {
    home_dir_relative("Library/Caches", app)
}

#[cfg(target_os = "macos")]
pub fn user_log_dir(app: Option<&str>, _: Option<&str>) -> PathBuf {
    home_dir_relative("Library/Logs", app)
}

#[cfg(all(unix, not(target_os = "macos"), not(target_os = "ios"), not(target_os = "android")))]
pub fn user_data_dir(app: Option<&str>, _: Option<&str>, _: bool) -> PathBuf {
    let mut data_dir = PathBuf::new();
    match env::var_os("XDG_DATA_HOME") {
        Some(dir) => { data_dir.push(dir); },
        None => {
            data_dir.push(env::home_dir().unwrap());
            data_dir.push(".local/share");
        },
    };
    if app.is_some() {
        data_dir.push(app.unwrap());
    }
    data_dir
}

#[cfg(all(unix, not(target_os = "macos"), not(target_os = "ios"), not(target_os = "android")))]
pub fn site_data_dir(app: Option<&str>, _: Option<&str>) -> PathBuf {
    let mut data_dir = PathBuf::new();
    let default = "/usr/local/share";
    match env::var_os("XDG_DATA_DIRS") {
        Some(joined) => {
            let first = env::split_paths(&joined).next();
            match first {
                Some(dir) => { data_dir.push(dir); },
                None => { data_dir.push(default); },
            };
        },
        None => { data_dir.push(default); },
    };
    if app.is_some() {
        data_dir.push(app.unwrap());
    }
    data_dir
}

#[cfg(all(unix, not(target_os = "macos"), not(target_os = "ios"), not(target_os = "android")))]
pub fn user_config_dir(app: Option<&str>, _: Option<&str>, _: bool) -> PathBuf {
    let mut config_dir = PathBuf::new();
    match env::var_os("XDG_CONFIG_HOME") {
        Some(dir) => { config_dir.push(dir); },
        None => {
            config_dir.push(env::home_dir().unwrap());
            config_dir.push(".config");
        },
    };
    if app.is_some() {
        config_dir.push(app.unwrap());
    }
    config_dir
}

#[cfg(all(unix, not(target_os = "macos"), not(target_os = "ios"), not(target_os = "android")))]
pub fn site_config_dir(app: Option<&str>, _: Option<&str>) -> PathBuf {
    let mut data_dir = PathBuf::new();
    let default = "/etc/xdg";
    match env::var_os("XDG_CONFIG_DIRS") {
        Some(joined) => {
            let first = env::split_paths(&joined).next();
            match first {
                Some(dir) => { data_dir.push(dir); },
                None => { data_dir.push(default); },
            };
        },
        None => { data_dir.push(default); },
    };
    if app.is_some() {
        data_dir.push(app.unwrap());
    }
    data_dir
}

#[cfg(all(unix, not(target_os = "macos"), not(target_os = "ios"), not(target_os = "android")))]
pub fn user_cache_dir(app: Option<&str>, _: Option<&str>) -> PathBuf {
    let mut cache_dir = PathBuf::new();
    match env::var_os("XDG_CACHE_HOME") {
        Some(dir) => { cache_dir.push(dir); },
        None => {
            cache_dir.push(env::home_dir().unwrap());
            cache_dir.push(".cache");
        },
    };
    if app.is_some() {
        cache_dir.push(app.unwrap());
    }
    cache_dir
}

#[cfg(all(unix, not(target_os = "macos"), not(target_os = "ios"), not(target_os = "android")))]
pub fn user_log_dir(app: Option<&str>, author: Option<&str>) -> PathBuf {
    let mut log_dir = user_cache_dir(app, author);
    log_dir.push("log");
    log_dir
}

#[cfg(target_os = "windows")]
static APPDATA_GUID: winapi::shtypes::KNOWNFOLDERID = winapi::shtypes::KNOWNFOLDERID {
    Data1: 1052149211,
    Data2: 26105,
    Data3: 19702,
    Data4: [160, 58, 227, 239, 101, 114, 159, 61],
};

#[cfg(target_os = "windows")]
static COMMON_APPDATA_GUID: winapi::shtypes::KNOWNFOLDERID = winapi::shtypes::KNOWNFOLDERID {
    Data1: 1655397762,
    Data2: 64961,
    Data3: 19907,
    Data4: [169, 221, 7, 13, 29, 73, 93, 151],
};

#[cfg(target_os = "windows")]
static LOCAL_APPDATA_GUID: winapi::shtypes::KNOWNFOLDERID = winapi::shtypes::KNOWNFOLDERID {
    Data1: 4055050117,
    Data2: 28602,
    Data3: 20431,
    Data4: [157, 85, 123, 142, 127, 21, 112, 145],
};

#[cfg(target_os = "windows")]
use std::ptr;

#[cfg(target_os = "windows")]
use std::ffi::OsString;

#[cfg(target_os = "windows")]
use std::os::windows::ffi::OsStringExt;

#[cfg(target_os = "windows")]
use std::slice;

#[cfg(target_os = "windows")]
fn get_dir(id: &winapi::shtypes::KNOWNFOLDERID) -> Result<OsString, ()> {
    let mut result: winapi::PWSTR = ptr::null_mut();
    let error;
    unsafe {
        error = shell32::SHGetKnownFolderPath(id, 0, ptr::null_mut(),
                                              &mut result);
    }
    if error != winapi::S_OK {
        //let _ = io::stderr().write(format!("error: {}\n", error));
        return Err(());
    }
    unsafe {
        let mut len = 0;
        let mut cur = result;
        while *cur != 0 {
            len += 1;
            cur = cur.offset(1);
        }
        let os_string: OsString =
            OsStringExt::from_wide(slice::from_raw_parts(result, len));
        ole32::CoTaskMemFree(result as *mut _);
        Ok(os_string)
    }
}

#[cfg(target_os = "windows")]
pub fn user_data_dir(app: Option<&str>, author: Option<&str>, roaming: bool) -> PathBuf {
    let dir_id = if roaming { APPDATA_GUID } else { LOCAL_APPDATA_GUID };
    let mut data_dir = PathBuf::new();
    data_dir.push(get_dir(&dir_id).unwrap());
    if author.is_some() {
        data_dir.push(author.unwrap());
    }
    if app.is_some() {
        data_dir.push(app.unwrap());
    }
    data_dir
}

#[cfg(target_os = "windows")]
pub fn site_data_dir(app: Option<&str>, author: Option<&str>) -> PathBuf {
    let mut data_dir = PathBuf::new();
    data_dir.push(get_dir(&COMMON_APPDATA_GUID).unwrap());
    if author.is_some() {
        data_dir.push(author.unwrap());
    }
    if app.is_some() {
        data_dir.push(app.unwrap());
    }
    data_dir
}

#[cfg(target_os = "windows")]
pub fn user_config_dir(app: Option<&str>, author: Option<&str>, roaming: bool) -> PathBuf {
    user_data_dir(app, author, roaming)
}

#[cfg(target_os = "windows")]
pub fn site_config_dir(app: Option<&str>, author: Option<&str>) -> PathBuf {
    site_data_dir(app, author)
}

#[cfg(target_os = "windows")]
pub fn user_cache_dir(app: Option<&str>, author: Option<&str>) -> PathBuf {
    let mut cache_dir = user_data_dir(app, author, false);
    cache_dir.push("Cache");
    cache_dir
}

#[cfg(target_os = "windows")]
pub fn user_log_dir(app: Option<&str>, author: Option<&str>) -> PathBuf {
    let mut log_dir = user_data_dir(app, author, false);
    log_dir.push("Logs");
    log_dir
}

#[cfg(test)]
mod tests {

    use std::io::{self, Write};
    use std::path::PathBuf;

    fn to_stderr(name: &str, value: PathBuf) {
        let _ = io::stderr().write(format!("{}: {}\n", name,
                                           value.to_str().unwrap()).as_bytes());
    }

    #[test]
    fn output_dirs() {
        to_stderr("user data dir",
                  super::user_data_dir(Some("AppDirs"), Some("djc"), false));
        to_stderr("site data dir",
                  super::site_data_dir(Some("AppDirs"), Some("djc")));
        to_stderr("user config dir",
                  super::user_config_dir(Some("AppDirs"), Some("djc"), false));
        to_stderr("site config dir",
                  super::site_config_dir(Some("AppDirs"), Some("djc")));
        to_stderr("user cache dir",
                  super::user_cache_dir(Some("AppDirs"), Some("djc")));
        to_stderr("user log dir",
                  super::user_log_dir(Some("AppDirs"), Some("djc")));
    }

}
<commit_msg>Add helper function for Unix variants<commit_after>#[cfg(target_os = "windows")]
extern crate shell32;
#[cfg(target_os = "windows")]
extern crate winapi;
#[cfg(target_os = "windows")]
extern crate ole32;

#[cfg(not(target_os = "windows"))]
use std::env;
use std::path::PathBuf;

#[cfg(target_os = "macos")]
fn home_dir_relative(rel: &str, app: Option<&str>) -> PathBuf {
    let mut data_dir = env::home_dir().unwrap();
    data_dir.push(rel);
    if app.is_some() {
        data_dir.push(app.unwrap());
    }
    data_dir
}

#[cfg(target_os = "macos")]
pub fn user_data_dir(app: Option<&str>, _: Option<&str>, _: bool) -> PathBuf {
    home_dir_relative("Library/Application Support", app)
}

#[cfg(target_os = "macos")]
pub fn site_data_dir(app: Option<&str>, _: Option<&str>) -> PathBuf {
    let mut data_dir = PathBuf::new();
    data_dir.push("/Library/Application Support");
    if app.is_some() {
        data_dir.push(app.unwrap());
    }
    data_dir
}

#[cfg(target_os = "macos")]
pub fn user_config_dir(app: Option<&str>, author: Option<&str>, roaming: bool) -> PathBuf {
    user_data_dir(app, author, roaming)
}

#[cfg(target_os = "macos")]
pub fn site_config_dir(app: Option<&str>, author: Option<&str>) -> PathBuf {
    site_data_dir(app, author)
}

#[cfg(target_os = "macos")]
pub fn user_cache_dir(app: Option<&str>, _: Option<&str>) -> PathBuf {
    home_dir_relative("Library/Caches", app)
}

#[cfg(target_os = "macos")]
pub fn user_log_dir(app: Option<&str>, _: Option<&str>) -> PathBuf {
    home_dir_relative("Library/Logs", app)
}

#[cfg(all(unix, not(target_os = "macos"), not(target_os = "ios"), not(target_os = "android")))]
fn home_dir_relative(xdg_key: &str, rel: &str, app: Option<&str>) -> PathBuf {
    let mut data_dir = PathBuf::new();
    match env::var_os(xdg_key) {
        Some(dir) => { data_dir.push(dir); },
        None => {
            data_dir.push(env::home_dir().unwrap());
            data_dir.push(rel);
        },
    };
    if app.is_some() {
        data_dir.push(app.unwrap());
    }
    data_dir
}

#[cfg(all(unix, not(target_os = "macos"), not(target_os = "ios"), not(target_os = "android")))]
pub fn user_data_dir(app: Option<&str>, _: Option<&str>, _: bool) -> PathBuf {
    home_dir_relative("XDG_DATA_HOME", ".local/share", app)
}

#[cfg(all(unix, not(target_os = "macos"), not(target_os = "ios"), not(target_os = "android")))]
pub fn site_data_dir(app: Option<&str>, _: Option<&str>) -> PathBuf {
    let mut data_dir = PathBuf::new();
    let default = "/usr/local/share";
    match env::var_os("XDG_DATA_DIRS") {
        Some(joined) => {
            let first = env::split_paths(&joined).next();
            match first {
                Some(dir) => { data_dir.push(dir); },
                None => { data_dir.push(default); },
            };
        },
        None => { data_dir.push(default); },
    };
    if app.is_some() {
        data_dir.push(app.unwrap());
    }
    data_dir
}

#[cfg(all(unix, not(target_os = "macos"), not(target_os = "ios"), not(target_os = "android")))]
pub fn user_config_dir(app: Option<&str>, _: Option<&str>, _: bool) -> PathBuf {
    home_dir_relative("XDG_CONFIG_HOME", ".config", app)
}

#[cfg(all(unix, not(target_os = "macos"), not(target_os = "ios"), not(target_os = "android")))]
pub fn site_config_dir(app: Option<&str>, _: Option<&str>) -> PathBuf {
    let mut data_dir = PathBuf::new();
    let default = "/etc/xdg";
    match env::var_os("XDG_CONFIG_DIRS") {
        Some(joined) => {
            let first = env::split_paths(&joined).next();
            match first {
                Some(dir) => { data_dir.push(dir); },
                None => { data_dir.push(default); },
            };
        },
        None => { data_dir.push(default); },
    };
    if app.is_some() {
        data_dir.push(app.unwrap());
    }
    data_dir
}

#[cfg(all(unix, not(target_os = "macos"), not(target_os = "ios"), not(target_os = "android")))]
pub fn user_cache_dir(app: Option<&str>, _: Option<&str>) -> PathBuf {
    home_dir_relative("XDG_CACHE_HOME", ".cache", app)
}

#[cfg(all(unix, not(target_os = "macos"), not(target_os = "ios"), not(target_os = "android")))]
pub fn user_log_dir(app: Option<&str>, author: Option<&str>) -> PathBuf {
    let mut log_dir = user_cache_dir(app, author);
    log_dir.push("log");
    log_dir
}

#[cfg(target_os = "windows")]
static APPDATA_GUID: winapi::shtypes::KNOWNFOLDERID = winapi::shtypes::KNOWNFOLDERID {
    Data1: 1052149211,
    Data2: 26105,
    Data3: 19702,
    Data4: [160, 58, 227, 239, 101, 114, 159, 61],
};

#[cfg(target_os = "windows")]
static COMMON_APPDATA_GUID: winapi::shtypes::KNOWNFOLDERID = winapi::shtypes::KNOWNFOLDERID {
    Data1: 1655397762,
    Data2: 64961,
    Data3: 19907,
    Data4: [169, 221, 7, 13, 29, 73, 93, 151],
};

#[cfg(target_os = "windows")]
static LOCAL_APPDATA_GUID: winapi::shtypes::KNOWNFOLDERID = winapi::shtypes::KNOWNFOLDERID {
    Data1: 4055050117,
    Data2: 28602,
    Data3: 20431,
    Data4: [157, 85, 123, 142, 127, 21, 112, 145],
};

#[cfg(target_os = "windows")]
use std::ptr;

#[cfg(target_os = "windows")]
use std::ffi::OsString;

#[cfg(target_os = "windows")]
use std::os::windows::ffi::OsStringExt;

#[cfg(target_os = "windows")]
use std::slice;

#[cfg(target_os = "windows")]
fn get_dir(id: &winapi::shtypes::KNOWNFOLDERID) -> Result<OsString, ()> {
    let mut result: winapi::PWSTR = ptr::null_mut();
    let error;
    unsafe {
        error = shell32::SHGetKnownFolderPath(id, 0, ptr::null_mut(),
                                              &mut result);
    }
    if error != winapi::S_OK {
        //let _ = io::stderr().write(format!("error: {}\n", error));
        return Err(());
    }
    unsafe {
        let mut len = 0;
        let mut cur = result;
        while *cur != 0 {
            len += 1;
            cur = cur.offset(1);
        }
        let os_string: OsString =
            OsStringExt::from_wide(slice::from_raw_parts(result, len));
        ole32::CoTaskMemFree(result as *mut _);
        Ok(os_string)
    }
}

#[cfg(target_os = "windows")]
pub fn user_data_dir(app: Option<&str>, author: Option<&str>, roaming: bool) -> PathBuf {
    let dir_id = if roaming { APPDATA_GUID } else { LOCAL_APPDATA_GUID };
    let mut data_dir = PathBuf::new();
    data_dir.push(get_dir(&dir_id).unwrap());
    if author.is_some() {
        data_dir.push(author.unwrap());
    }
    if app.is_some() {
        data_dir.push(app.unwrap());
    }
    data_dir
}

#[cfg(target_os = "windows")]
pub fn site_data_dir(app: Option<&str>, author: Option<&str>) -> PathBuf {
    let mut data_dir = PathBuf::new();
    data_dir.push(get_dir(&COMMON_APPDATA_GUID).unwrap());
    if author.is_some() {
        data_dir.push(author.unwrap());
    }
    if app.is_some() {
        data_dir.push(app.unwrap());
    }
    data_dir
}

#[cfg(target_os = "windows")]
pub fn user_config_dir(app: Option<&str>, author: Option<&str>, roaming: bool) -> PathBuf {
    user_data_dir(app, author, roaming)
}

#[cfg(target_os = "windows")]
pub fn site_config_dir(app: Option<&str>, author: Option<&str>) -> PathBuf {
    site_data_dir(app, author)
}

#[cfg(target_os = "windows")]
pub fn user_cache_dir(app: Option<&str>, author: Option<&str>) -> PathBuf {
    let mut cache_dir = user_data_dir(app, author, false);
    cache_dir.push("Cache");
    cache_dir
}

#[cfg(target_os = "windows")]
pub fn user_log_dir(app: Option<&str>, author: Option<&str>) -> PathBuf {
    let mut log_dir = user_data_dir(app, author, false);
    log_dir.push("Logs");
    log_dir
}

#[cfg(test)]
mod tests {

    use std::io::{self, Write};
    use std::path::PathBuf;

    fn to_stderr(name: &str, value: PathBuf) {
        let _ = io::stderr().write(format!("{}: {}\n", name,
                                           value.to_str().unwrap()).as_bytes());
    }

    #[test]
    fn output_dirs() {
        to_stderr("user data dir",
                  super::user_data_dir(Some("AppDirs"), Some("djc"), false));
        to_stderr("site data dir",
                  super::site_data_dir(Some("AppDirs"), Some("djc")));
        to_stderr("user config dir",
                  super::user_config_dir(Some("AppDirs"), Some("djc"), false));
        to_stderr("site config dir",
                  super::site_config_dir(Some("AppDirs"), Some("djc")));
        to_stderr("user cache dir",
                  super::user_cache_dir(Some("AppDirs"), Some("djc")));
        to_stderr("user log dir",
                  super::user_log_dir(Some("AppDirs"), Some("djc")));
    }

}
<|endoftext|>


<commit_before>//! Wrapper types to enable optimized handling of `&[u8]` and `Vec<u8>`.
//!
//! Without specialization, Rust forces Serde to treat `&[u8]` just like any
//! other slice and `Vec<u8>` just like any other vector. In reality this
//! particular slice and vector can often be serialized and deserialized in a
//! more efficient, compact representation in many formats.
//!
//! When working with such a format, you can opt into specialized handling of
//! `&[u8]` by wrapping it in `serde_bytes::Bytes` and `Vec<u8>` by wrapping it
//! in `serde_bytes::ByteBuf`.
//!
//! This crate supports the Serde `with` attribute to enable efficient handling
//! of `&[u8]` and `Vec<u8>` in structs without needing a wrapper type.
//!
//! ```
//! # use serde_derive::{Serialize, Deserialize};
//! use serde::{Serialize, Deserialize};
//!
//! #[derive(Serialize)]
//! struct Efficient<'a> {
//!     #[serde(with = "serde_bytes")]
//!     bytes: &'a [u8],
//!
//!     #[serde(with = "serde_bytes")]
//!     byte_buf: Vec<u8>,
//! }
//!
//! #[derive(Serialize, Deserialize)]
//! struct Packet {
//!     #[serde(with = "serde_bytes")]
//!     payload: Vec<u8>,
//! }
//! ```

#![doc(html_root_url = "https://docs.rs/serde_bytes/0.10.5")]
#![cfg_attr(not(feature = "std"), no_std)]
#![cfg_attr(feature = "alloc", feature(alloc))]
#![deny(missing_docs)]

mod bytes;
mod de;
mod ser;

#[cfg(any(feature = "std", feature = "alloc"))]
mod bytebuf;

#[cfg(feature = "alloc")]
extern crate alloc;

#[cfg(any(feature = "std", feature = "alloc"))]
use serde::Deserializer;

use serde::Serializer;

pub use crate::bytes::Bytes;
pub use crate::de::Deserialize;
pub use crate::ser::Serialize;

#[cfg(any(feature = "std", feature = "alloc"))]
pub use crate::bytebuf::ByteBuf;

/// Serde `serialize_with` function to serialize bytes efficiently.
///
/// This function can be used with either of the following Serde attributes:
///
/// - `#[serde(with = "serde_bytes")]`
/// - `#[serde(serialize_with = "serde_bytes::serialize")]`
///
/// ```
/// # use serde_derive::Serialize;
/// use serde::Serialize;
///
/// #[derive(Serialize)]
/// struct Efficient<'a> {
///     #[serde(with = "serde_bytes")]
///     bytes: &'a [u8],
///
///     #[serde(with = "serde_bytes")]
///     byte_buf: Vec<u8>,
/// }
/// ```
pub fn serialize<T, S>(bytes: &T, serializer: S) -> Result<S::Ok, S::Error>
where
    T: Serialize,
    S: Serializer,
{
    Serialize::serialize(bytes, serializer)
}

/// Serde `deserialize_with` function to deserialize bytes efficiently.
///
/// This function can be used with either of the following Serde attributes:
///
/// - `#[serde(with = "serde_bytes")]`
/// - `#[serde(deserialize_with = "serde_bytes::deserialize")]`
///
/// ```
/// # use serde_derive::Deserialize;
/// use serde::Deserialize;
///
/// #[derive(Deserialize)]
/// struct Packet {
///     #[serde(with = "serde_bytes")]
///     payload: Vec<u8>,
/// }
/// ```
#[cfg(any(feature = "std", feature = "alloc"))]
pub fn deserialize<'de, T, D>(deserializer: D) -> Result<T, D::Error>
where
    T: Deserialize<'de>,
    D: Deserializer<'de>,
{
    Deserialize::deserialize(deserializer)
}
<commit_msg>Bring crate-level documentation up to date with readme<commit_after>//! Wrapper types to enable optimized handling of `&[u8]` and `Vec<u8>`.
//!
//! Without specialization, Rust forces Serde to treat `&[u8]` just like any
//! other slice and `Vec<u8>` just like any other vector. In reality this
//! particular slice and vector can often be serialized and deserialized in a
//! more efficient, compact representation in many formats.
//!
//! When working with such a format, you can opt into specialized handling of
//! `&[u8]` by wrapping it in `serde_bytes::Bytes` and `Vec<u8>` by wrapping it
//! in `serde_bytes::ByteBuf`.
//!
//! Additionally this crate supports the Serde `with` attribute to enable
//! efficient handling of `&[u8]` and `Vec<u8>` in structs without needing a
//! wrapper type.
//!
//! ```
//! # use serde_derive::{Deserialize, Serialize};
//! use serde::{Deserialize, Serialize};
//!
//! #[derive(Deserialize, Serialize)]
//! struct Efficient<'a> {
//!     #[serde(with = "serde_bytes")]
//!     bytes: &'a [u8],
//!
//!     #[serde(with = "serde_bytes")]
//!     byte_buf: Vec<u8>,
//! }
//! ```

#![doc(html_root_url = "https://docs.rs/serde_bytes/0.10.5")]
#![cfg_attr(not(feature = "std"), no_std)]
#![cfg_attr(feature = "alloc", feature(alloc))]
#![deny(missing_docs)]

mod bytes;
mod de;
mod ser;

#[cfg(any(feature = "std", feature = "alloc"))]
mod bytebuf;

#[cfg(feature = "alloc")]
extern crate alloc;

#[cfg(any(feature = "std", feature = "alloc"))]
use serde::Deserializer;

use serde::Serializer;

pub use crate::bytes::Bytes;
pub use crate::de::Deserialize;
pub use crate::ser::Serialize;

#[cfg(any(feature = "std", feature = "alloc"))]
pub use crate::bytebuf::ByteBuf;

/// Serde `serialize_with` function to serialize bytes efficiently.
///
/// This function can be used with either of the following Serde attributes:
///
/// - `#[serde(with = "serde_bytes")]`
/// - `#[serde(serialize_with = "serde_bytes::serialize")]`
///
/// ```
/// # use serde_derive::Serialize;
/// use serde::Serialize;
///
/// #[derive(Serialize)]
/// struct Efficient<'a> {
///     #[serde(with = "serde_bytes")]
///     bytes: &'a [u8],
///
///     #[serde(with = "serde_bytes")]
///     byte_buf: Vec<u8>,
/// }
/// ```
pub fn serialize<T, S>(bytes: &T, serializer: S) -> Result<S::Ok, S::Error>
where
    T: Serialize,
    S: Serializer,
{
    Serialize::serialize(bytes, serializer)
}

/// Serde `deserialize_with` function to deserialize bytes efficiently.
///
/// This function can be used with either of the following Serde attributes:
///
/// - `#[serde(with = "serde_bytes")]`
/// - `#[serde(deserialize_with = "serde_bytes::deserialize")]`
///
/// ```
/// # use serde_derive::Deserialize;
/// use serde::Deserialize;
///
/// #[derive(Deserialize)]
/// struct Packet {
///     #[serde(with = "serde_bytes")]
///     payload: Vec<u8>,
/// }
/// ```
#[cfg(any(feature = "std", feature = "alloc"))]
pub fn deserialize<'de, T, D>(deserializer: D) -> Result<T, D::Error>
where
    T: Deserialize<'de>,
    D: Deserializer<'de>,
{
    Deserialize::deserialize(deserializer)
}
<|endoftext|>


<commit_before>extern crate crypto;
extern crate hyper;
extern crate rustc_serialize;
extern crate time;

pub mod hook;
pub mod rep;

use crypto::mac::Mac;
use crypto::hmac::Hmac;
use crypto::sha1::Sha1;
use hook::Hook;
use hyper::server::{Handler, Server, Request, Response};
use rep::Payload;
use rustc_serialize::json;
use std::collections::HashMap;
use std::thread;
use std::io::Read;
use std::sync::Mutex;
use std::sync::mpsc::{channel, Receiver, Sender};

/// Raw, unparsed representation of an inbound github event
#[derive(Clone, Debug, Default)]
pub struct Event {
  pub name: String,
  pub payload: String
}

/// A hub is a handler for github event requests
struct Hub {
  secret: Option<String>,
  deliveries: Mutex<Sender<Event>>,
  hooks: Vec<Hook>
}

impl Hub {
  pub fn authenticate(secret: &String, payload: &String, signature: &[u8]) -> bool {
    let sbytes = secret.as_bytes();
    let pbytes = payload.as_bytes();
    let mut mac = Hmac::new(Sha1::new(), &sbytes);
    mac.input(&pbytes);
    mac.result().code().to_vec() == signature
  }
}

impl Handler for Hub {
  fn handle(&self, mut req: Request, res: Response) {
    let mut payload = String::new();
    if let Ok(_) = req.read_to_string(&mut payload) {
      if let Some(es) = req.headers.get_raw("X-Github-Event") {
        let event = String::from_utf8_lossy(&(*es[0])).to_string();
        println!("recv {} event", event);
        let deliver = || {
          let _ = self.deliveries.lock().unwrap().send(Event {
            name: event,
            payload: payload.clone()
          });
        };
        if let Some(ref secret) = self.secret {
           match req.headers.get_raw("X-Hub-Signature") {
              Some(sig) => {
                 if Hub::authenticate(&secret, &payload, &(*sig[0])) {
                   deliver()
                 } else {
                   println!("recv invalid signature for payload");
                 }
              },
                     _  => println!("recv unsigned request recieved")
           }
        } else {
          deliver()
        }
      }
    }
    let _ = res.send(b"ok");
    ()
  }
}

/// Filters filter inbound events, invoking interested hooks
struct Filter { hooks: Vec<Hook> }

impl Filter {

  /// filters hooks based on event name
  /// `*` will match any event
  pub fn filter(&self, ev: &Event, payload: &Payload) -> Vec<&Hook> {
    (*self.hooks).into_iter()
      .filter(|h| h.targets(&ev.name, payload))
      .collect::<Vec<&Hook>>()
  }

  /// recv's github events from rx and sends them
  /// to interested hooks.
  /// a thread will be spawned once for each hook
  /// before awaiting the reciept of events
  pub fn recv(&self, rx: Receiver<Event>) {
    let mut lookup     = HashMap::new();
    let mut deliveries = HashMap::new();
    for hook in (&self.hooks).iter() {
      lookup.insert((*hook).clone().name(), (*hook).clone());
    }
    for (name, hook) in lookup.into_iter() {
      let (tx, rx) = channel();
      deliveries.insert(name.clone(), tx);
      thread::spawn(move || {
        hook.recv(rx);
      });
    }
    while let Ok(ev) = rx.recv() {
      match json::decode::<Payload>(&ev.payload) {
        Ok(payload) => {
          println!("rec {} event", ev.name);
          let hooks = self.filter(&ev, &payload);
          for h in hooks {
            let name = h.clone().name();
            if let Err(e) = deliveries.get(&name).unwrap().send(ev.clone()) {
              println!("{} delivery to {} failed: {}", ev.name, name, e.to_string())
            }
          }
        }, _ => println!("rec unparsable payload {:?}", ev.payload)
      }
    }
  }
}

/// A Service serves inbound requests for github events
#[derive(Debug, RustcEncodable, RustcDecodable)]
pub struct Service {
  pub secret: Option<String>,
  pub port: Option<u16>,
  pub hooks: Vec<Hook>
}

impl Service {

  /// return the configured port or 4567
  pub fn port(&self) -> u16 {
    self.port.unwrap_or(4567)
  }

  /// sets the current list of hooks in memory
  pub fn hooks(&mut self, hooks: Vec<Hook>) {
    self.hooks = hooks;
  }

  /// starts listening on the configured port
  pub fn run(self) {
    let (tx, rx) = channel();
    let hooks = self.hooks.clone();
    thread::spawn(move || {
      let filter = Filter { hooks: hooks };
      filter.recv(rx)
    });
    let addr = format!("0.0.0.0:{}", self.port());
    let srvc = Server::http(&addr[..]).unwrap()
      .handle(Hub {
         secret: self.secret,
         deliveries: Mutex::new(tx),
         hooks: self.hooks
      });
    println!("listening on {}", addr);
    srvc.unwrap();
  }
}

#[cfg(test)]
mod tests {
  use rustc_serialize::json;
  use super::{Event, Filter, Service};
  use super::hook::Hook;
  use super::rep::Payload;

  #[test]
  fn test_filter() {
    let hooks = vec![
      Hook {
        events: vec![
          "a".to_owned(),
          "b".to_owned()
        ],
        ..Default::default()
      },
      Hook {
        events: vec![
          "a".to_owned(),
          "c".to_owned()
        ],
        ..Default::default()
      },
      Hook {
        events: vec!["*".to_owned()],
        ..Default::default()
      }
    ];
    let filter = Filter { hooks: hooks };

    assert_eq!(3, filter.filter(&Event {
      name: "a".to_owned(),
      ..Default::default()
    }, &Payload {
       ..Default::default()
    }).len());

    assert_eq!(2, filter.filter(&Event {
      name: "c".to_owned(),
      ..Default::default()
    }, &Payload {
      ..Default::default()
    }).len())
  }

  #[test]
  fn test_service_config() {
    match json::decode::<Service>(&r#"{
     "hooks": [{
       "cmd": "ls",
       "events": ["test"]
     }]
    }"#) {
      Ok(svc) => {
         assert_eq!(4567, svc.port());
         assert_eq!(1, svc.hooks.len());
      },
      Err(e) => panic!("failed to decode service {}", e)
    }
  }
}
<commit_msg>use proper header<commit_after>
extern crate crypto;
#[macro_use] extern crate hyper;
extern crate rustc_serialize;
extern crate time;

pub mod hook;
pub mod rep;

use crypto::mac::Mac;
use crypto::hmac::Hmac;
use crypto::sha1::Sha1;
use hook::Hook;

use hyper::server::{Handler, Server, Request, Response};
use rep::Payload;
use rustc_serialize::json;
use std::collections::HashMap;
use std::thread;
use std::io::Read;
use std::sync::Mutex;
use std::sync::mpsc::{channel, Receiver, Sender};

/// signature for request
/// see [this document](https://developer.github.com/webhooks/securing/) for more information
header! {(XHubSignature, "X-Hub-Signature") => [String]}

/// name of Github event
/// see [this document](https://developer.github.com/webhooks/#events) for available types
header! {(XGithubEvent, "X-Github-Event") => [String]}

/// unique id for each delivery
header! {(XGithubDelivery, "X-Github-Deliver") => [String]}

/// Raw, unparsed representation of an inbound github event
#[derive(Clone, Debug, Default)]
pub struct Event {
  pub name: String,
  pub payload: String
}

/// A hub is a handler for github event requests
struct Hub {
  secret: Option<String>,
  deliveries: Mutex<Sender<Event>>,
  hooks: Vec<Hook>
}

impl Hub {
  pub fn authenticate(secret: &String, payload: &String, signature: &[u8]) -> bool {
    let sbytes = secret.as_bytes();
    let pbytes = payload.as_bytes();
    let mut mac = Hmac::new(Sha1::new(), &sbytes);
    mac.input(&pbytes);
    mac.result().code().to_vec() == signature
  }
}

impl Handler for Hub {
  fn handle(&self, mut req: Request, res: Response) {
    let mut payload = String::new();
    if let Ok(_) = req.read_to_string(&mut payload) {
      if let Some(&XGithubEvent(ref event)) = req.headers.get::<XGithubEvent>() {
        println!("recv '{}' event", event);
        let deliver = || {
          let _ = self.deliveries.lock().unwrap().send(Event {
            name: event.clone(),
            payload: payload.clone()
          });
        };
        if let Some(ref secret) = self.secret {
           match req.headers.get::<XHubSignature>() {
              Some(sig) => {
                 if Hub::authenticate(&secret, &payload, &sig.as_bytes()) {
                   deliver()
                 } else {
                   println!("recv invalid signature for payload");
                 }
              },
                     _  => println!("recv unsigned request recieved")
           }
        } else {
          deliver()
        }
      }
    }
    let _ = res.send(b"ok");
    ()
  }
}

/// Filters filter inbound events, invoking interested hooks
struct Filter { hooks: Vec<Hook> }

impl Filter {

  /// filters hooks based on event name
  /// `*` will match any event
  pub fn filter(&self, ev: &Event, payload: &Payload) -> Vec<&Hook> {
    (*self.hooks).into_iter()
      .filter(|h| h.targets(&ev.name, payload))
      .collect::<Vec<&Hook>>()
  }

  /// recv's github events from rx and sends them
  /// to interested hooks.
  /// a thread will be spawned once for each hook
  /// before awaiting the reciept of events
  pub fn recv(&self, rx: Receiver<Event>) {
    let mut lookup     = HashMap::new();
    let mut deliveries = HashMap::new();
    for hook in (&self.hooks).iter() {
      lookup.insert((*hook).clone().name(), (*hook).clone());
    }
    for (name, hook) in lookup.into_iter() {
      let (tx, rx) = channel();
      deliveries.insert(name.clone(), tx);
      thread::spawn(move || {
        hook.recv(rx);
      });
    }
    while let Ok(ev) = rx.recv() {
      match json::decode::<Payload>(&ev.payload) {
        Ok(payload) => {
          println!("rec {} event", ev.name);
          let hooks = self.filter(&ev, &payload);
          for h in hooks {
            let name = h.clone().name();
            if let Err(e) = deliveries.get(&name).unwrap().send(ev.clone()) {
              println!("{} delivery to {} failed: {}", ev.name, name, e.to_string())
            }
          }
        }, _ => println!("rec unparsable payload {:?}", ev.payload)
      }
    }
  }
}

/// A Service serves inbound requests for github events
#[derive(Debug, RustcEncodable, RustcDecodable)]
pub struct Service {
  pub secret: Option<String>,
  pub port: Option<u16>,
  pub hooks: Vec<Hook>
}

impl Service {

  /// return the configured port or 4567
  pub fn port(&self) -> u16 {
    self.port.unwrap_or(4567)
  }

  /// sets the current list of hooks in memory
  pub fn hooks(&mut self, hooks: Vec<Hook>) {
    self.hooks = hooks;
  }

  /// starts listening on the configured port
  pub fn run(self) {
    let (tx, rx) = channel();
    let hooks = self.hooks.clone();
    thread::spawn(move || {
      let filter = Filter { hooks: hooks };
      filter.recv(rx)
    });
    let addr = format!("0.0.0.0:{}", self.port());
    let srvc = Server::http(&addr[..]).unwrap()
      .handle(Hub {
         secret: self.secret,
         deliveries: Mutex::new(tx),
         hooks: self.hooks
      });
    println!("listening on {}", addr);
    srvc.unwrap();
  }
}

#[cfg(test)]
mod tests {
  use rustc_serialize::json;
  use super::{Event, Filter, Service};
  use super::hook::Hook;
  use super::rep::Payload;

  #[test]
  fn test_filter() {
    let hooks = vec![
      Hook {
        events: vec![
          "a".to_owned(),
          "b".to_owned()
        ],
        ..Default::default()
      },
      Hook {
        events: vec![
          "a".to_owned(),
          "c".to_owned()
        ],
        ..Default::default()
      },
      Hook {
        events: vec!["*".to_owned()],
        ..Default::default()
      }
    ];
    let filter = Filter { hooks: hooks };

    assert_eq!(3, filter.filter(&Event {
      name: "a".to_owned(),
      ..Default::default()
    }, &Payload {
       ..Default::default()
    }).len());

    assert_eq!(2, filter.filter(&Event {
      name: "c".to_owned(),
      ..Default::default()
    }, &Payload {
      ..Default::default()
    }).len())
  }

  #[test]
  fn test_service_config() {
    match json::decode::<Service>(&r#"{
     "hooks": [{
       "cmd": "ls",
       "events": ["test"]
     }]
    }"#) {
      Ok(svc) => {
         assert_eq!(4567, svc.port());
         assert_eq!(1, svc.hooks.len());
      },
      Err(e) => panic!("failed to decode service {}", e)
    }
  }
}
<|endoftext|>


<commit_before>//! # `object`
//!
//! The `object` crate provides a unified interface to working with object files
//! across platforms.
//!
//! See the [`File` struct](./struct.File.html) for details.

#![deny(missing_docs)]
#![deny(missing_debug_implementations)]

extern crate goblin;

use std::fmt;
use std::io::Cursor;

mod elf;
pub use elf::*;

mod macho;
pub use macho::*;

mod pe;
pub use pe::*;

mod traits;
pub use traits::*;

/// An object file.
#[derive(Debug)]
pub struct File<'a> {
    inner: FileInternal<'a>,
}

#[derive(Debug)]
enum FileInternal<'a> {
    Elf(ElfFile<'a>),
    MachO(MachOFile<'a>),
    Pe(PeFile<'a>),
}

/// The machine type of an object file.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Machine {
    /// An unrecognized machine type.
    Other,
    /// ARM
    Arm,
    /// ARM64
    Arm64,
    /// x86
    X86,
    /// x86-64
    #[allow(non_camel_case_types)]
    X86_64,
}

/// An iterator over the segments of a `File`.
#[derive(Debug)]
pub struct SegmentIterator<'a> {
    inner: SegmentIteratorInternal<'a>,
}

#[derive(Debug)]
enum SegmentIteratorInternal<'a> {
    Elf(ElfSegmentIterator<'a>),
    MachO(MachOSegmentIterator<'a>),
    Pe(PeSegmentIterator<'a>),
}

/// A segment of a `File`.
pub struct Segment<'a> {
    inner: SegmentInternal<'a>,
}

#[derive(Debug)]
enum SegmentInternal<'a> {
    Elf(ElfSegment<'a>),
    MachO(MachOSegment<'a>),
    Pe(PeSegment<'a>),
}

/// An iterator of the sections of a `File`.
#[derive(Debug)]
pub struct SectionIterator<'a> {
    inner: SectionIteratorInternal<'a>,
}

// we wrap our enums in a struct so that they are kept private.
#[derive(Debug)]
enum SectionIteratorInternal<'a> {
    Elf(ElfSectionIterator<'a>),
    MachO(MachOSectionIterator<'a>),
    Pe(PeSectionIterator<'a>),
}

/// A Section of a File
pub struct Section<'a> {
    inner: SectionInternal<'a>,
}

enum SectionInternal<'a> {
    Elf(ElfSection<'a>),
    MachO(MachOSection<'a>),
    Pe(PeSection<'a>),
}

/// The kind of a section.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum SectionKind {
    /// The section kind is unknown.
    Unknown,
    /// An executable code section.
    Text,
    /// A data section.
    Data,
    /// A read only data section.
    ReadOnlyData,
    /// An uninitialized data section.
    UninitializedData,
    /// Some other type of text or data section.
    Other,
}

/// A symbol table entry.
#[derive(Debug)]
pub struct Symbol<'a> {
    kind: SymbolKind,
    section: usize,
    section_kind: Option<SectionKind>,
    global: bool,
    name: Option<&'a str>,
    address: u64,
    size: u64,
}

/// The kind of a symbol.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum SymbolKind {
    /// The symbol kind is unknown.
    Unknown,
    /// The symbol is for executable code.
    Text,
    /// The symbol is for a data object.
    Data,
    /// The symbol is for a section.
    Section,
    /// The symbol is the name of a file. It precedes symbols within that file.
    File,
    /// The symbol is for an uninitialized common block.
    Common,
    /// The symbol is for a thread local storage entity.
    Tls,
}

impl<'a> Object<'a> for File<'a> {
    type Segment = Segment<'a>;
    type SegmentIterator = SegmentIterator<'a>;
    type Section = Section<'a>;
    type SectionIterator = SectionIterator<'a>;

    fn parse(data: &'a [u8]) -> Result<Self, &'static str> {
        let mut cursor = Cursor::new(data);
        let inner = match goblin::peek(&mut cursor).map_err(|_| "Could not parse file magic")? {
            goblin::Hint::Elf(_) => FileInternal::Elf(ElfFile::parse(data)?),
            goblin::Hint::Mach(_) => FileInternal::MachO(MachOFile::parse(data)?),
            goblin::Hint::PE => FileInternal::Pe(PeFile::parse(data)?),
            _ => return Err("Unknown file magic"),
        };
        Ok(File { inner })
    }

    fn machine(&self) -> Machine {
        match self.inner {
            FileInternal::Elf(ref elf) => elf.machine(),
            FileInternal::MachO(ref macho) => macho.machine(),
            FileInternal::Pe(ref pe) => pe.machine(),
        }
    }

    fn segments(&'a self) -> SegmentIterator<'a> {
        match self.inner {
            FileInternal::Elf(ref elf) => SegmentIterator {
                inner: SegmentIteratorInternal::Elf(elf.segments()),
            },
            FileInternal::MachO(ref macho) => SegmentIterator {
                inner: SegmentIteratorInternal::MachO(macho.segments()),
            },
            FileInternal::Pe(ref pe) => SegmentIterator {
                inner: SegmentIteratorInternal::Pe(pe.segments()),
            },
        }
    }

    fn section_data_by_name(&self, section_name: &str) -> Option<&'a [u8]> {
        match self.inner {
            FileInternal::Elf(ref elf) => elf.section_data_by_name(section_name),
            FileInternal::MachO(ref macho) => macho.section_data_by_name(section_name),
            FileInternal::Pe(ref pe) => pe.section_data_by_name(section_name),
        }
    }

    fn sections(&'a self) -> SectionIterator<'a> {
        match self.inner {
            FileInternal::Elf(ref elf) => SectionIterator {
                inner: SectionIteratorInternal::Elf(elf.sections()),
            },
            FileInternal::MachO(ref macho) => SectionIterator {
                inner: SectionIteratorInternal::MachO(macho.sections()),
            },
            FileInternal::Pe(ref pe) => SectionIterator {
                inner: SectionIteratorInternal::Pe(pe.sections()),
            },
        }
    }

    fn symbols(&self) -> Vec<Symbol<'a>> {
        match self.inner {
            FileInternal::Elf(ref elf) => elf.symbols(),
            FileInternal::MachO(ref macho) => macho.symbols(),
            FileInternal::Pe(ref pe) => pe.symbols(),
        }
    }

    fn is_little_endian(&self) -> bool {
        match self.inner {
            FileInternal::Elf(ref elf) => elf.is_little_endian(),
            FileInternal::MachO(ref macho) => macho.is_little_endian(),
            FileInternal::Pe(ref pe) => pe.is_little_endian(),
        }
    }
}

impl<'a> Iterator for SegmentIterator<'a> {
    type Item = Segment<'a>;

    fn next(&mut self) -> Option<Self::Item> {
        match self.inner {
            SegmentIteratorInternal::Elf(ref mut elf) => elf.next().map(|x| {
                Segment {
                    inner: SegmentInternal::Elf(x),
                }
            }),
            SegmentIteratorInternal::MachO(ref mut macho) => macho.next().map(|x| {
                Segment {
                    inner: SegmentInternal::MachO(x),
                }
            }),
            SegmentIteratorInternal::Pe(ref mut pe) => pe.next().map(|x| {
                Segment {
                    inner: SegmentInternal::Pe(x),
                }
            }),
        }
    }
}

impl<'a> fmt::Debug for Segment<'a> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        // It's painful to do much better than this
        f.debug_struct("Segment")
            .field("name", &self.name().unwrap_or("<unnamed>"))
            .field("address", &self.address())
            .field("size", &self.data().len())
            .finish()
    }
}

impl<'a> Segment<'a> {
    fn inner(&self) -> &ObjectSegment<'a> {
        match self.inner {
            SegmentInternal::Elf(ref elf) => elf,
            SegmentInternal::MachO(ref macho) => macho,
            SegmentInternal::Pe(ref pe) => pe,
        }
    }
}

impl<'a> ObjectSegment<'a> for Segment<'a> {
    fn address(&self) -> u64 {
        self.inner().address()
    }

    fn size(&self) -> u64 {
        self.inner().size()
    }

    fn data(&self) -> &'a [u8] {
        self.inner().data()
    }

    fn name(&self) -> Option<&str> {
        self.inner().name()
    }
}

impl<'a> Iterator for SectionIterator<'a> {
    type Item = Section<'a>;

    fn next(&mut self) -> Option<Self::Item> {
        match self.inner {
            SectionIteratorInternal::Elf(ref mut elf) => elf.next().map(|x| {
                Section {
                    inner: SectionInternal::Elf(x),
                }
            }),
            SectionIteratorInternal::MachO(ref mut macho) => macho.next().map(|x| {
                Section {
                    inner: SectionInternal::MachO(x),
                }
            }),
            SectionIteratorInternal::Pe(ref mut pe) => pe.next().map(|x| {
                Section {
                    inner: SectionInternal::Pe(x),
                }
            }),
        }
    }
}

impl<'a> fmt::Debug for Section<'a> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        // It's painful to do much better than this
        f.debug_struct("Section")
            .field("name", &self.name().unwrap_or("<invalid name>"))
            .field("address", &self.address())
            .field("size", &self.data().len())
            .finish()
    }
}

impl<'a> Section<'a> {
    fn inner(&self) -> &ObjectSection<'a> {
        match self.inner {
            SectionInternal::Elf(ref elf) => elf,
            SectionInternal::MachO(ref macho) => macho,
            SectionInternal::Pe(ref pe) => pe,
        }
    }
}

impl<'a> ObjectSection<'a> for Section<'a> {
    fn address(&self) -> u64 {
        self.inner().address()
    }

    fn size(&self) -> u64 {
        self.inner().size()
    }

    fn data(&self) -> &'a [u8] {
        self.inner().data()
    }

    fn name(&self) -> Option<&str> {
        self.inner().name()
    }

    fn segment_name(&self) -> Option<&str> {
        self.inner().segment_name()
    }
}

impl<'a> Symbol<'a> {
    /// Return the kind of this symbol.
    #[inline]
    pub fn kind(&self) -> SymbolKind {
        self.kind
    }

    /// Returns the section kind for the symbol, or `None` if the symbol is undefnined.
    #[inline]
    pub fn section_kind(&self) -> Option<SectionKind> {
        self.section_kind
    }

    /// Return true if the symbol is undefined.
    #[inline]
    pub fn is_undefined(&self) -> bool {
        self.section_kind.is_none()
    }

    /// Return true if the symbol is global.
    #[inline]
    pub fn is_global(&self) -> bool {
        self.global
    }

    /// Return true if the symbol is local.
    #[inline]
    pub fn is_local(&self) -> bool {
        !self.global
    }

    /// The name of the symbol.
    #[inline]
    pub fn name(&self) -> Option<&'a str> {
        self.name
    }

    /// The address of the symbol. May be zero if the address is unknown.
    #[inline]
    pub fn address(&self) -> u64 {
        self.address
    }

    /// The size of the symbol. May be zero if the size is unknown.
    #[inline]
    pub fn size(&self) -> u64 {
        self.size
    }
}
<commit_msg>Avoid virtual calls<commit_after>//! # `object`
//!
//! The `object` crate provides a unified interface to working with object files
//! across platforms.
//!
//! See the [`File` struct](./struct.File.html) for details.

#![deny(missing_docs)]
#![deny(missing_debug_implementations)]

extern crate goblin;

use std::fmt;
use std::io::Cursor;

mod elf;
pub use elf::*;

mod macho;
pub use macho::*;

mod pe;
pub use pe::*;

mod traits;
pub use traits::*;

/// An object file.
#[derive(Debug)]
pub struct File<'a> {
    inner: FileInternal<'a>,
}

#[derive(Debug)]
enum FileInternal<'a> {
    Elf(ElfFile<'a>),
    MachO(MachOFile<'a>),
    Pe(PeFile<'a>),
}

/// The machine type of an object file.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Machine {
    /// An unrecognized machine type.
    Other,
    /// ARM
    Arm,
    /// ARM64
    Arm64,
    /// x86
    X86,
    /// x86-64
    #[allow(non_camel_case_types)]
    X86_64,
}

/// An iterator over the segments of a `File`.
#[derive(Debug)]
pub struct SegmentIterator<'a> {
    inner: SegmentIteratorInternal<'a>,
}

#[derive(Debug)]
enum SegmentIteratorInternal<'a> {
    Elf(ElfSegmentIterator<'a>),
    MachO(MachOSegmentIterator<'a>),
    Pe(PeSegmentIterator<'a>),
}

/// A segment of a `File`.
pub struct Segment<'a> {
    inner: SegmentInternal<'a>,
}

#[derive(Debug)]
enum SegmentInternal<'a> {
    Elf(ElfSegment<'a>),
    MachO(MachOSegment<'a>),
    Pe(PeSegment<'a>),
}

/// An iterator of the sections of a `File`.
#[derive(Debug)]
pub struct SectionIterator<'a> {
    inner: SectionIteratorInternal<'a>,
}

// we wrap our enums in a struct so that they are kept private.
#[derive(Debug)]
enum SectionIteratorInternal<'a> {
    Elf(ElfSectionIterator<'a>),
    MachO(MachOSectionIterator<'a>),
    Pe(PeSectionIterator<'a>),
}

/// A Section of a File
pub struct Section<'a> {
    inner: SectionInternal<'a>,
}

enum SectionInternal<'a> {
    Elf(ElfSection<'a>),
    MachO(MachOSection<'a>),
    Pe(PeSection<'a>),
}

/// The kind of a section.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum SectionKind {
    /// The section kind is unknown.
    Unknown,
    /// An executable code section.
    Text,
    /// A data section.
    Data,
    /// A read only data section.
    ReadOnlyData,
    /// An uninitialized data section.
    UninitializedData,
    /// Some other type of text or data section.
    Other,
}

/// A symbol table entry.
#[derive(Debug)]
pub struct Symbol<'a> {
    kind: SymbolKind,
    section: usize,
    section_kind: Option<SectionKind>,
    global: bool,
    name: Option<&'a str>,
    address: u64,
    size: u64,
}

/// The kind of a symbol.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum SymbolKind {
    /// The symbol kind is unknown.
    Unknown,
    /// The symbol is for executable code.
    Text,
    /// The symbol is for a data object.
    Data,
    /// The symbol is for a section.
    Section,
    /// The symbol is the name of a file. It precedes symbols within that file.
    File,
    /// The symbol is for an uninitialized common block.
    Common,
    /// The symbol is for a thread local storage entity.
    Tls,
}

/// Evaluate an expression on the contents of a file format enum.
///
/// This is a hack to avoid virtual calls.
macro_rules! with_inner {
    ($inner:expr, $enum:ident, |$var:ident| $body:expr) => {
        match $inner {
            &$enum::Elf(ref $var) => { $body }
            &$enum::MachO(ref $var) => { $body }
            &$enum::Pe(ref $var) => { $body }
        }
    }
}

/// Like `with_inner!`, but wraps the result in another enum.
macro_rules! map_inner {
    ($inner:expr, $from:ident, $to:ident, |$var:ident| $body:expr) => {
        match $inner {
            &$from::Elf(ref $var) => $to::Elf($body),
            &$from::MachO(ref $var) => $to::MachO($body),
            &$from::Pe(ref $var) => $to::Pe($body),
        }
    }
}

/// Call `next` for a file format iterator.
macro_rules! next_inner {
    ($inner:expr, $from:ident, $to:ident) => {
        match $inner {
            &mut $from::Elf(ref mut iter) => iter.next().map(|x| $to::Elf(x)),
            &mut $from::MachO(ref mut iter) => iter.next().map(|x| $to::MachO(x)),
            &mut $from::Pe(ref mut iter) => iter.next().map(|x| $to::Pe(x)),
        }
    }
}

impl<'a> Object<'a> for File<'a> {
    type Segment = Segment<'a>;
    type SegmentIterator = SegmentIterator<'a>;
    type Section = Section<'a>;
    type SectionIterator = SectionIterator<'a>;

    fn parse(data: &'a [u8]) -> Result<Self, &'static str> {
        let mut cursor = Cursor::new(data);
        let inner = match goblin::peek(&mut cursor).map_err(|_| "Could not parse file magic")? {
            goblin::Hint::Elf(_) => FileInternal::Elf(ElfFile::parse(data)?),
            goblin::Hint::Mach(_) => FileInternal::MachO(MachOFile::parse(data)?),
            goblin::Hint::PE => FileInternal::Pe(PeFile::parse(data)?),
            _ => return Err("Unknown file magic"),
        };
        Ok(File { inner })
    }

    fn machine(&self) -> Machine {
        with_inner!(&self.inner, FileInternal, |x| x.machine())
    }

    fn segments(&'a self) -> SegmentIterator<'a> {
        SegmentIterator {
            inner: map_inner!(
                &self.inner,
                FileInternal,
                SegmentIteratorInternal,
                |x| x.segments()
            ),
        }
    }

    fn section_data_by_name(&self, section_name: &str) -> Option<&'a [u8]> {
        with_inner!(
            &self.inner,
            FileInternal,
            |x| x.section_data_by_name(section_name)
        )
    }

    fn sections(&'a self) -> SectionIterator<'a> {
        SectionIterator {
            inner: map_inner!(
                &self.inner,
                FileInternal,
                SectionIteratorInternal,
                |x| x.sections()
            ),
        }
    }

    fn symbols(&self) -> Vec<Symbol<'a>> {
        with_inner!(&self.inner, FileInternal, |x| x.symbols())
    }

    fn is_little_endian(&self) -> bool {
        with_inner!(&self.inner, FileInternal, |x| x.is_little_endian())
    }
}

impl<'a> Iterator for SegmentIterator<'a> {
    type Item = Segment<'a>;

    fn next(&mut self) -> Option<Self::Item> {
        next_inner!(&mut self.inner, SegmentIteratorInternal, SegmentInternal)
            .map(|inner| Segment { inner })
    }
}

impl<'a> fmt::Debug for Segment<'a> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        // It's painful to do much better than this
        f.debug_struct("Segment")
            .field("name", &self.name().unwrap_or("<unnamed>"))
            .field("address", &self.address())
            .field("size", &self.data().len())
            .finish()
    }
}

impl<'a> ObjectSegment<'a> for Segment<'a> {
    fn address(&self) -> u64 {
        with_inner!(&self.inner, SegmentInternal, |x| x.address())
    }

    fn size(&self) -> u64 {
        with_inner!(&self.inner, SegmentInternal, |x| x.size())
    }

    fn data(&self) -> &'a [u8] {
        with_inner!(&self.inner, SegmentInternal, |x| x.data())
    }

    fn name(&self) -> Option<&str> {
        with_inner!(&self.inner, SegmentInternal, |x| x.name())
    }
}

impl<'a> Iterator for SectionIterator<'a> {
    type Item = Section<'a>;

    fn next(&mut self) -> Option<Self::Item> {
        next_inner!(&mut self.inner, SectionIteratorInternal, SectionInternal)
            .map(|inner| Section { inner })
    }
}

impl<'a> fmt::Debug for Section<'a> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        // It's painful to do much better than this
        f.debug_struct("Section")
            .field("name", &self.name().unwrap_or("<invalid name>"))
            .field("address", &self.address())
            .field("size", &self.data().len())
            .finish()
    }
}

impl<'a> ObjectSection<'a> for Section<'a> {
    fn address(&self) -> u64 {
        with_inner!(&self.inner, SectionInternal, |x| x.address())
    }

    fn size(&self) -> u64 {
        with_inner!(&self.inner, SectionInternal, |x| x.size())
    }

    fn data(&self) -> &'a [u8] {
        with_inner!(&self.inner, SectionInternal, |x| x.data())
    }

    fn name(&self) -> Option<&str> {
        with_inner!(&self.inner, SectionInternal, |x| x.name())
    }

    fn segment_name(&self) -> Option<&str> {
        with_inner!(&self.inner, SectionInternal, |x| x.segment_name())
    }
}

impl<'a> Symbol<'a> {
    /// Return the kind of this symbol.
    #[inline]
    pub fn kind(&self) -> SymbolKind {
        self.kind
    }

    /// Returns the section kind for the symbol, or `None` if the symbol is undefnined.
    #[inline]
    pub fn section_kind(&self) -> Option<SectionKind> {
        self.section_kind
    }

    /// Return true if the symbol is undefined.
    #[inline]
    pub fn is_undefined(&self) -> bool {
        self.section_kind.is_none()
    }

    /// Return true if the symbol is global.
    #[inline]
    pub fn is_global(&self) -> bool {
        self.global
    }

    /// Return true if the symbol is local.
    #[inline]
    pub fn is_local(&self) -> bool {
        !self.global
    }

    /// The name of the symbol.
    #[inline]
    pub fn name(&self) -> Option<&'a str> {
        self.name
    }

    /// The address of the symbol. May be zero if the address is unknown.
    #[inline]
    pub fn address(&self) -> u64 {
        self.address
    }

    /// The size of the symbol. May be zero if the size is unknown.
    #[inline]
    pub fn size(&self) -> u64 {
        self.size
    }
}
<|endoftext|>


<commit_before>// Copyright 2016 Hroi Sigurdsson
//
// Licensed under the MIT license <LICENSE-MIT or http://opensource.org/licenses/MIT>.
// This file may not be copied, modified, or distributed except according to those terms.

//! # Fast IP lookup table for IPv4/IPv6 prefixes
//!
//! This crate provides a datastructure for fast IP address lookups.
//! It aims at fast lookup times, and a small memory footprint.
//! A full IPv4 BGP table of more than 600k entries fits in less than 5 MB. A
//! full IPv6 BGP table of more than 25k entries fits in less than 1 MB.
//!
//! Longest match lookups on full BGP IP tables take on the order of 100ns.
//!
//! The internal datastructure is based on the Tree-bitmap algorithm described
//! by W. Eatherton, Z. Dittia, G. Varghes.
//!
#![cfg_attr(feature = "alloc", no_std)]
#![cfg_attr(feature = "alloc", feature(alloc))]

#[cfg(feature = "alloc")]
extern crate alloc;
#[cfg(feature = "alloc")]
use core as std;

use std::marker::PhantomData;

mod tree_bitmap;
use tree_bitmap::TreeBitmap;

mod address;
use address::Address;

/// A fast, compressed IP lookup table.
pub struct IpLookupTable<A, T> {
    inner: TreeBitmap<T>,
    _addrtype: PhantomData<A>,
}

impl<A, T> IpLookupTable<A, T>
where
    A: Address,
{
    /// Initialize an empty lookup table with no preallocation.
    pub fn new() -> Self {
        IpLookupTable {
            inner: TreeBitmap::new(),
            _addrtype: PhantomData,
        }
    }

    /// Initialize an empty lookup table with pre-allocated buffers.
    pub fn with_capacity(n: usize) -> Self {
        IpLookupTable {
            inner: TreeBitmap::with_capacity(n),
            _addrtype: PhantomData,
        }
    }

    /// Return the bytes used by nodes and results.
    pub fn mem_usage(&self) -> (usize, usize) {
        self.inner.mem_usage()
    }

    /// Return number of items inside table.
    pub fn len(&self) -> usize {
        self.inner.len()
    }

    /// Return `true` if no item is inside table.
    pub fn is_empty(&self) -> bool {
        self.len() == 0
    }

    /// Insert a value for the prefix designated by ip and masklen. If prefix
    /// existed previously, the old value is returned.
    ///
    /// # Examples
    ///
    /// ```
    /// use treebitmap::IpLookupTable;
    /// use std::net::Ipv6Addr;
    ///
    /// let mut table = IpLookupTable::new();
    /// let prefix = Ipv6Addr::new(0x2001, 0xdb8, 0xdead, 0xbeef, 0, 0, 0, 0);
    /// let masklen = 32;
    ///
    /// assert_eq!(table.insert(prefix, masklen, "foo"), None);
    /// // Insert duplicate
    /// assert_eq!(table.insert(prefix, masklen, "bar"), Some("foo"));
    /// ```
    pub fn insert(&mut self, ip: A, masklen: u32, value: T) -> Option<T> {
        self.inner.insert(&ip.nibbles().as_ref(), masklen, value)
    }

    /// Remove an entry from the lookup table. If the prefix existed previously,
    /// the value is returned.
    ///
    /// # Examples
    ///
    /// ```
    /// use treebitmap::IpLookupTable;
    /// use std::net::Ipv6Addr;
    ///
    /// let mut table = IpLookupTable::new();
    /// let prefix = Ipv6Addr::new(0x2001, 0xdb8, 0xdead, 0xbeef, 0, 0, 0, 0);
    /// let masklen = 32;
    /// table.insert(prefix, masklen, "foo");
    ///
    /// assert_eq!(table.remove(prefix, masklen), Some("foo"));
    /// // Remove non-existant
    /// assert_eq!(table.remove(prefix, masklen), None);
    /// ```
    pub fn remove(&mut self, ip: A, masklen: u32) -> Option<T> {
        self.inner.remove(&ip.nibbles().as_ref(), masklen)
    }

    /// Perform exact match lookup of `ip`/`masklen` and return the
    /// value.
    ///
    /// # Examples
    ///
    /// ```
    /// use treebitmap::IpLookupTable;
    /// use std::net::Ipv6Addr;
    ///
    /// let mut table = IpLookupTable::new();
    /// let prefix = Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0);
    /// let masklen = 32;
    /// table.insert(prefix, masklen, "foo");
    ///
    /// assert_eq!(table.exact_match(prefix, masklen), Some(&"foo"));
    /// // differing mask
    /// assert_eq!(table.exact_match(prefix, 48), None);
    /// ```
    pub fn exact_match(&self, ip: A, masklen: u32) -> Option<&T> {
        self.inner.exact_match(&ip.nibbles().as_ref(), masklen)
    }

    /// Perform longest match lookup of `ip` and return the best matching
    /// prefix, designated by ip, masklen, along with its value.
    ///
    /// # Example
    ///
    /// ```
    /// use treebitmap::IpLookupTable;
    /// use std::net::Ipv6Addr;
    ///
    /// let mut table = IpLookupTable::new();
    /// let less_specific = Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0);
    /// let more_specific = Ipv6Addr::new(0x2001, 0xdb8, 0xdead, 0, 0, 0, 0, 0);
    /// table.insert(less_specific, 32, "foo");
    /// table.insert(more_specific, 48, "bar");
    ///
    /// let lookupip = Ipv6Addr::new(0x2001, 0xdb8, 0xdead, 0xbeef,
    ///                              0xcafe, 0xbabe, 0, 1);
    /// let result = table.longest_match(lookupip);
    /// assert_eq!(result, Some((more_specific, 48, &"bar")));
    ///
    /// let lookupip = Ipv6Addr::new(0x2001, 0xdb8, 0xcafe, 0xf00,
    ///                              0xf00, 0xf00, 0, 1);
    /// let result = table.longest_match(lookupip);
    /// assert_eq!(result, Some((less_specific, 32, &"foo")));
    /// ```
    pub fn longest_match(&self, ip: A) -> Option<(A, u32, &T)> {
        match self.inner.longest_match(&ip.nibbles().as_ref()) {
            Some((bits_matched, value)) => Some((ip.mask(bits_matched), bits_matched, value)),
            None => None,
        }
    }

    /// Returns iterator over prefixes and values.
    ///
    /// # Examples
    ///
    /// ```
    /// use treebitmap::IpLookupTable;
    /// use std::net::Ipv6Addr;
    ///
    /// let mut table = IpLookupTable::new();
    /// let less_specific = Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0);
    /// let more_specific = Ipv6Addr::new(0x2001, 0xdb8, 0xdead, 0, 0, 0, 0, 0);
    /// table.insert(less_specific, 32, "foo");
    /// table.insert(more_specific, 48, "bar");
    ///
    /// let mut iter = table.iter();
    /// assert_eq!(iter.next(), Some((less_specific, 32, &"foo")));
    /// assert_eq!(iter.next(), Some((more_specific, 48, &"bar")));
    /// assert_eq!(iter.next(), None);
    /// ```
    pub fn iter(&self) -> Iter<A, T> {
        Iter {
            inner: self.inner.iter(),
            _addrtype: PhantomData,
        }
    }

    /// Mutable version of iter().
    ///
    /// # Examples
    ///
    /// ```
    /// use treebitmap::IpLookupTable;
    /// use std::net::Ipv6Addr;
    ///
    /// let x: Ipv6Addr = "2001:db8:100::".parse().unwrap();
    /// let y: Ipv6Addr = "2001:db8:100::".parse().unwrap();
    /// let z: Ipv6Addr = "2001:db8:102::".parse().unwrap();
    /// let mut table = IpLookupTable::new();
    ///
    /// table.insert(x, 48, 1);
    /// table.insert(y, 56, 2);
    /// table.insert(z, 56, 3);
    ///
    /// for (_ip, _mask, val) in table.iter_mut() {
    ///     *val += 10;
    /// }
    ///
    /// assert_eq!(table.exact_match(x, 48), Some(&11));
    /// assert_eq!(table.exact_match(y, 56), Some(&12));
    /// assert_eq!(table.exact_match(z, 56), Some(&13));
    /// ```

    pub fn iter_mut(&mut self) -> IterMut<A, T> {
        IterMut {
            inner: self.inner.iter_mut(),
            _addrtype: PhantomData,
        }
    }
}

impl<A, T> Default for IpLookupTable<A, T>
where
    A: Address,
{
    fn default() -> Self {
        Self::new()
    }
}

impl<'a, A, T: 'a> Iterator for Iter<'a, A, T>
where
    A: Address,
{
    type Item = (A, u32, &'a T);

    fn next(&mut self) -> Option<Self::Item> {
        match self.inner.next() {
            Some((nibbles, masklen, value)) => {
                Some((Address::from_nibbles(&nibbles[..]), masklen, value))
            }
            None => None,
        }
    }
}

impl<'a, A, T: 'a> Iterator for IterMut<'a, A, T>
where
    A: Address,
{
    type Item = (A, u32, &'a mut T);

    fn next(&mut self) -> Option<Self::Item> {
        match self.inner.next() {
            Some((nibbles, masklen, value)) => {
                Some((Address::from_nibbles(&nibbles[..]), masklen, value))
            }
            None => None,
        }
    }
}

impl<'a, A, T: 'a> Iterator for IntoIter<A, T>
where
    A: Address,
{
    type Item = (A, u32, T);

    fn next(&mut self) -> Option<Self::Item> {
        match self.inner.next() {
            Some((nibbles, masklen, value)) => {
                Some((Address::from_nibbles(&nibbles[..]), masklen, value))
            }
            None => None,
        }
    }
}

impl<A, T> IntoIterator for IpLookupTable<A, T>
where
    A: Address,
{
    type Item = (A, u32, T);
    type IntoIter = IntoIter<A, T>;

    fn into_iter(self) -> IntoIter<A, T> {
        IntoIter {
            inner: self.inner.into_iter(),
            _addrtype: PhantomData,
        }
    }
}

/// Iterator over prefixes and associated values. The prefixes are returned in
/// "tree"-order.
#[doc(hidden)]
pub struct Iter<'a, A, T: 'a> {
    inner: tree_bitmap::Iter<'a, T>,
    _addrtype: PhantomData<A>,
}

/// Mutable iterator over prefixes and associated values. The prefixes are
/// returned in "tree"-order.
#[doc(hidden)]
pub struct IterMut<'a, A, T: 'a> {
    inner: tree_bitmap::IterMut<'a, T>,
    _addrtype: PhantomData<A>,
}

/// Converts ```IpLookupTable``` into an iterator. The prefixes are returned in
/// "tree"-order.
#[doc(hidden)]
pub struct IntoIter<A, T> {
    inner: tree_bitmap::IntoIter<T>,
    _addrtype: PhantomData<A>,
}
<commit_msg>Export Ipv4Addr<commit_after>// Copyright 2016 Hroi Sigurdsson
//
// Licensed under the MIT license <LICENSE-MIT or http://opensource.org/licenses/MIT>.
// This file may not be copied, modified, or distributed except according to those terms.

//! # Fast IP lookup table for IPv4/IPv6 prefixes
//!
//! This crate provides a datastructure for fast IP address lookups.
//! It aims at fast lookup times, and a small memory footprint.
//! A full IPv4 BGP table of more than 600k entries fits in less than 5 MB. A
//! full IPv6 BGP table of more than 25k entries fits in less than 1 MB.
//!
//! Longest match lookups on full BGP IP tables take on the order of 100ns.
//!
//! The internal datastructure is based on the Tree-bitmap algorithm described
//! by W. Eatherton, Z. Dittia, G. Varghes.
//!
#![cfg_attr(feature = "alloc", no_std)]
#![cfg_attr(feature = "alloc", feature(alloc))]

#[cfg(feature = "alloc")]
extern crate alloc;
#[cfg(feature = "alloc")]
use core as std;

use std::marker::PhantomData;

mod tree_bitmap;
use tree_bitmap::TreeBitmap;

mod address;
use address::Address;

#[cfg(feature = "alloc")]
pub use address::addr::*;

/// A fast, compressed IP lookup table.
pub struct IpLookupTable<A, T> {
    inner: TreeBitmap<T>,
    _addrtype: PhantomData<A>,
}

impl<A, T> IpLookupTable<A, T>
where
    A: Address,
{
    /// Initialize an empty lookup table with no preallocation.
    pub fn new() -> Self {
        IpLookupTable {
            inner: TreeBitmap::new(),
            _addrtype: PhantomData,
        }
    }

    /// Initialize an empty lookup table with pre-allocated buffers.
    pub fn with_capacity(n: usize) -> Self {
        IpLookupTable {
            inner: TreeBitmap::with_capacity(n),
            _addrtype: PhantomData,
        }
    }

    /// Return the bytes used by nodes and results.
    pub fn mem_usage(&self) -> (usize, usize) {
        self.inner.mem_usage()
    }

    /// Return number of items inside table.
    pub fn len(&self) -> usize {
        self.inner.len()
    }

    /// Return `true` if no item is inside table.
    pub fn is_empty(&self) -> bool {
        self.len() == 0
    }

    /// Insert a value for the prefix designated by ip and masklen. If prefix
    /// existed previously, the old value is returned.
    ///
    /// # Examples
    ///
    /// ```
    /// use treebitmap::IpLookupTable;
    /// use std::net::Ipv6Addr;
    ///
    /// let mut table = IpLookupTable::new();
    /// let prefix = Ipv6Addr::new(0x2001, 0xdb8, 0xdead, 0xbeef, 0, 0, 0, 0);
    /// let masklen = 32;
    ///
    /// assert_eq!(table.insert(prefix, masklen, "foo"), None);
    /// // Insert duplicate
    /// assert_eq!(table.insert(prefix, masklen, "bar"), Some("foo"));
    /// ```
    pub fn insert(&mut self, ip: A, masklen: u32, value: T) -> Option<T> {
        self.inner.insert(&ip.nibbles().as_ref(), masklen, value)
    }

    /// Remove an entry from the lookup table. If the prefix existed previously,
    /// the value is returned.
    ///
    /// # Examples
    ///
    /// ```
    /// use treebitmap::IpLookupTable;
    /// use std::net::Ipv6Addr;
    ///
    /// let mut table = IpLookupTable::new();
    /// let prefix = Ipv6Addr::new(0x2001, 0xdb8, 0xdead, 0xbeef, 0, 0, 0, 0);
    /// let masklen = 32;
    /// table.insert(prefix, masklen, "foo");
    ///
    /// assert_eq!(table.remove(prefix, masklen), Some("foo"));
    /// // Remove non-existant
    /// assert_eq!(table.remove(prefix, masklen), None);
    /// ```
    pub fn remove(&mut self, ip: A, masklen: u32) -> Option<T> {
        self.inner.remove(&ip.nibbles().as_ref(), masklen)
    }

    /// Perform exact match lookup of `ip`/`masklen` and return the
    /// value.
    ///
    /// # Examples
    ///
    /// ```
    /// use treebitmap::IpLookupTable;
    /// use std::net::Ipv6Addr;
    ///
    /// let mut table = IpLookupTable::new();
    /// let prefix = Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0);
    /// let masklen = 32;
    /// table.insert(prefix, masklen, "foo");
    ///
    /// assert_eq!(table.exact_match(prefix, masklen), Some(&"foo"));
    /// // differing mask
    /// assert_eq!(table.exact_match(prefix, 48), None);
    /// ```
    pub fn exact_match(&self, ip: A, masklen: u32) -> Option<&T> {
        self.inner.exact_match(&ip.nibbles().as_ref(), masklen)
    }

    /// Perform longest match lookup of `ip` and return the best matching
    /// prefix, designated by ip, masklen, along with its value.
    ///
    /// # Example
    ///
    /// ```
    /// use treebitmap::IpLookupTable;
    /// use std::net::Ipv6Addr;
    ///
    /// let mut table = IpLookupTable::new();
    /// let less_specific = Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0);
    /// let more_specific = Ipv6Addr::new(0x2001, 0xdb8, 0xdead, 0, 0, 0, 0, 0);
    /// table.insert(less_specific, 32, "foo");
    /// table.insert(more_specific, 48, "bar");
    ///
    /// let lookupip = Ipv6Addr::new(0x2001, 0xdb8, 0xdead, 0xbeef,
    ///                              0xcafe, 0xbabe, 0, 1);
    /// let result = table.longest_match(lookupip);
    /// assert_eq!(result, Some((more_specific, 48, &"bar")));
    ///
    /// let lookupip = Ipv6Addr::new(0x2001, 0xdb8, 0xcafe, 0xf00,
    ///                              0xf00, 0xf00, 0, 1);
    /// let result = table.longest_match(lookupip);
    /// assert_eq!(result, Some((less_specific, 32, &"foo")));
    /// ```
    pub fn longest_match(&self, ip: A) -> Option<(A, u32, &T)> {
        match self.inner.longest_match(&ip.nibbles().as_ref()) {
            Some((bits_matched, value)) => Some((ip.mask(bits_matched), bits_matched, value)),
            None => None,
        }
    }

    /// Returns iterator over prefixes and values.
    ///
    /// # Examples
    ///
    /// ```
    /// use treebitmap::IpLookupTable;
    /// use std::net::Ipv6Addr;
    ///
    /// let mut table = IpLookupTable::new();
    /// let less_specific = Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0);
    /// let more_specific = Ipv6Addr::new(0x2001, 0xdb8, 0xdead, 0, 0, 0, 0, 0);
    /// table.insert(less_specific, 32, "foo");
    /// table.insert(more_specific, 48, "bar");
    ///
    /// let mut iter = table.iter();
    /// assert_eq!(iter.next(), Some((less_specific, 32, &"foo")));
    /// assert_eq!(iter.next(), Some((more_specific, 48, &"bar")));
    /// assert_eq!(iter.next(), None);
    /// ```
    pub fn iter(&self) -> Iter<A, T> {
        Iter {
            inner: self.inner.iter(),
            _addrtype: PhantomData,
        }
    }

    /// Mutable version of iter().
    ///
    /// # Examples
    ///
    /// ```
    /// use treebitmap::IpLookupTable;
    /// use std::net::Ipv6Addr;
    ///
    /// let x: Ipv6Addr = "2001:db8:100::".parse().unwrap();
    /// let y: Ipv6Addr = "2001:db8:100::".parse().unwrap();
    /// let z: Ipv6Addr = "2001:db8:102::".parse().unwrap();
    /// let mut table = IpLookupTable::new();
    ///
    /// table.insert(x, 48, 1);
    /// table.insert(y, 56, 2);
    /// table.insert(z, 56, 3);
    ///
    /// for (_ip, _mask, val) in table.iter_mut() {
    ///     *val += 10;
    /// }
    ///
    /// assert_eq!(table.exact_match(x, 48), Some(&11));
    /// assert_eq!(table.exact_match(y, 56), Some(&12));
    /// assert_eq!(table.exact_match(z, 56), Some(&13));
    /// ```

    pub fn iter_mut(&mut self) -> IterMut<A, T> {
        IterMut {
            inner: self.inner.iter_mut(),
            _addrtype: PhantomData,
        }
    }
}

impl<A, T> Default for IpLookupTable<A, T>
where
    A: Address,
{
    fn default() -> Self {
        Self::new()
    }
}

impl<'a, A, T: 'a> Iterator for Iter<'a, A, T>
where
    A: Address,
{
    type Item = (A, u32, &'a T);

    fn next(&mut self) -> Option<Self::Item> {
        match self.inner.next() {
            Some((nibbles, masklen, value)) => {
                Some((Address::from_nibbles(&nibbles[..]), masklen, value))
            }
            None => None,
        }
    }
}

impl<'a, A, T: 'a> Iterator for IterMut<'a, A, T>
where
    A: Address,
{
    type Item = (A, u32, &'a mut T);

    fn next(&mut self) -> Option<Self::Item> {
        match self.inner.next() {
            Some((nibbles, masklen, value)) => {
                Some((Address::from_nibbles(&nibbles[..]), masklen, value))
            }
            None => None,
        }
    }
}

impl<'a, A, T: 'a> Iterator for IntoIter<A, T>
where
    A: Address,
{
    type Item = (A, u32, T);

    fn next(&mut self) -> Option<Self::Item> {
        match self.inner.next() {
            Some((nibbles, masklen, value)) => {
                Some((Address::from_nibbles(&nibbles[..]), masklen, value))
            }
            None => None,
        }
    }
}

impl<A, T> IntoIterator for IpLookupTable<A, T>
where
    A: Address,
{
    type Item = (A, u32, T);
    type IntoIter = IntoIter<A, T>;

    fn into_iter(self) -> IntoIter<A, T> {
        IntoIter {
            inner: self.inner.into_iter(),
            _addrtype: PhantomData,
        }
    }
}

/// Iterator over prefixes and associated values. The prefixes are returned in
/// "tree"-order.
#[doc(hidden)]
pub struct Iter<'a, A, T: 'a> {
    inner: tree_bitmap::Iter<'a, T>,
    _addrtype: PhantomData<A>,
}

/// Mutable iterator over prefixes and associated values. The prefixes are
/// returned in "tree"-order.
#[doc(hidden)]
pub struct IterMut<'a, A, T: 'a> {
    inner: tree_bitmap::IterMut<'a, T>,
    _addrtype: PhantomData<A>,
}

/// Converts ```IpLookupTable``` into an iterator. The prefixes are returned in
/// "tree"-order.
#[doc(hidden)]
pub struct IntoIter<A, T> {
    inner: tree_bitmap::IntoIter<T>,
    _addrtype: PhantomData<A>,
}
<|endoftext|>


<commit_before>use std::io::Command;
use std::io::process::InheritFd;
use std::default::Default;

/// Extra configuration to pass to gcc.
pub struct Config {
    /// Directories where gcc will look for header files.
    pub include_directories: Vec<Path>,
    /// Additional definitions (`-DKEY` or `-DKEY=VALUE`).
    pub definitions: Vec<(String, Option<String>)>,
    /// Additional object files to link into the final archive
    pub objects: Vec<Path>,
    /// Additional flags and parameter to pass to the compiler
    pub flags: Vec<String>,
}

impl Default for Config {
    fn default() -> Config {
        Config {
            include_directories: Vec::new(),
            definitions: Vec::new(),
            objects: Vec::new(),
            flags: Vec::new(),
        }
    }
}

fn getenv(v: &str) -> Option<String> {
    use std::os::getenv;
    let r = getenv(v);
    println!("{} = {}", v, r);
    r
}

/// Compile a library from the given set of input C files.
///
/// This will simply compile all files into object files and then assemble them
/// into the output. This will read the standard environment variables to detect
/// cross compilations and such.
///
/// # Example
///
/// ```no_run
/// use std::default::Default;
/// gcc::compile_library("libfoo.a", &Default::default(), &[
///     "foo.c",
///     "bar.c",
/// ]);
/// ```
pub fn compile_library(output: &str, config: &Config, files: &[&str]) {
    assert!(output.starts_with("lib"));
    assert!(output.ends_with(".a"));

    let target = getenv("TARGET").unwrap();
    let opt_level = getenv("OPT_LEVEL").unwrap();

    let mut cmd = Command::new(gcc(target.as_slice()));
    cmd.arg(format!("-O{}", opt_level));
    cmd.arg("-c");
    cmd.arg("-ffunction-sections").arg("-fdata-sections");
    cmd.args(cflags().as_slice());

    if target.as_slice().contains("-ios") {
        cmd.args(ios_flags(target.as_slice()).as_slice());
    } else {
        if target.as_slice().contains("i686") {
            cmd.arg("-m32");
        } else if target.as_slice().contains("x86_64") {
            cmd.arg("-m64");
        }

        if !target.as_slice().contains("i686") {
            cmd.arg("-fPIC");
        }
    }

    for directory in config.include_directories.iter() {
        cmd.arg("-I").arg(directory);
    }

    for flag in config.flags.iter() {
        cmd.arg(flag);
    }

    for &(ref key, ref value) in config.definitions.iter() {
        if let &Some(ref value) = value {
            cmd.arg(format!("-D{}={}", key, value));
        } else {
            cmd.arg(format!("-D{}", key));
        }
    }

    let src = Path::new(getenv("CARGO_MANIFEST_DIR").unwrap());
    let dst = Path::new(getenv("OUT_DIR").unwrap());
    let mut objects = Vec::new();
    for file in files.iter() {
        let obj = dst.join(*file).with_extension("o");
        std::io::fs::mkdir_recursive(&obj.dir_path(), std::io::USER_RWX).unwrap();
        run(cmd.clone().arg(src.join(*file)).arg("-o").arg(&obj));
        objects.push(obj);
    }

    run(Command::new(ar(target.as_slice())).arg("crus")
                                           .arg(dst.join(output))
                                           .args(objects.as_slice())
                                           .args(config.objects.as_slice()));
    println!("cargo:rustc-flags=-L {} -l {}:static",
             dst.display(), output.slice(3, output.len() - 2));
}

fn run(cmd: &mut Command) {
    println!("running: {}", cmd);
    let status = match cmd.stdout(InheritFd(1)).stderr(InheritFd(2)).status() {
        Ok(status) => status,
        Err(e) => panic!("failed to spawn process: {}", e),
    };
    if !status.success() {
        panic!("nonzero exit status: {}", status);
    }
}

fn get_var(var_base: &str) -> Result<String, String> {
    let target = getenv("TARGET")
        .expect("Environment variable 'TARGET' is unset");
    let host = match getenv("HOST") {
            None => { return Err("Environment variable 'HOST' is unset".to_string()); }
            Some(x) => x
        };
    let kind = if host == target { "HOST" } else { "TARGET" };
    let target_u = target.split('-')
        .collect::<Vec<&str>>()
        .connect("_");
    let res = getenv(format!("{}_{}", var_base, target).as_slice())
        .or_else(|| getenv(format!("{}_{}", var_base, target_u).as_slice()))
        .or_else(|| getenv(format!("{}_{}", kind, var_base).as_slice()))
        .or_else(|| getenv(var_base));

    match res {
        Some(res) => Ok(res),
        None => Err("Could not get environment variable".to_string()),
    }
}

fn gcc(target: &str) -> String {
    let is_android = target.find_str("android").is_some();

    get_var("CC").unwrap_or(if cfg!(windows) {
        "gcc".to_string()
    } else if is_android {
        format!("{}-gcc", target)
    } else {
        "cc".to_string()
    })
}

fn ar(target: &str) -> String {
    let is_android = target.find_str("android").is_some();

    get_var("AR").unwrap_or(if is_android {
        format!("{}-ar", target)
    } else {
        "ar".to_string()
    })
}

fn cflags() -> Vec<String> {
    get_var("CFLAGS").unwrap_or(String::new())
       .as_slice().words().map(|s| s.to_string())
       .collect()
}

fn ios_flags(target: &str) -> Vec<String> {
    let mut is_device_arch = false;
    let mut res = Vec::new();

    if target.starts_with("arm-") {
        res.push("-arch");
        res.push("armv7");
        is_device_arch = true;
    } else if target.starts_with("arm64-") {
        res.push("-arch");
        res.push("arm64");
        is_device_arch = true;
    } else if target.starts_with("i386-") {
        res.push("-m32");
    } else if target.starts_with("x86_64-") {
        res.push("-m64");
    }

    let sdk = if is_device_arch {"iphoneos"} else {"iphonesimulator"};

    println!("Detecting iOS SDK path for {}", sdk);
    let sdk_path = Command::new("xcrun")
        .arg("--show-sdk-path")
        .arg("--sdk")
        .arg(sdk)
        .stderr(InheritFd(2))
        .output()
        .unwrap()
        .output;

    let sdk_path = String::from_utf8(sdk_path).unwrap();

    res.push("-isysroot");
    res.push(sdk_path.as_slice().trim());

    res.iter().map(|s| s.to_string()).collect::<Vec<_>>()
}
<commit_msg>Add -mwin32 on Windows targets<commit_after>use std::io::Command;
use std::io::process::InheritFd;
use std::default::Default;

/// Extra configuration to pass to gcc.
pub struct Config {
    /// Directories where gcc will look for header files.
    pub include_directories: Vec<Path>,
    /// Additional definitions (`-DKEY` or `-DKEY=VALUE`).
    pub definitions: Vec<(String, Option<String>)>,
    /// Additional object files to link into the final archive
    pub objects: Vec<Path>,
    /// Additional flags and parameter to pass to the compiler
    pub flags: Vec<String>,
}

impl Default for Config {
    fn default() -> Config {
        Config {
            include_directories: Vec::new(),
            definitions: Vec::new(),
            objects: Vec::new(),
            flags: Vec::new(),
        }
    }
}

fn getenv(v: &str) -> Option<String> {
    use std::os::getenv;
    let r = getenv(v);
    println!("{} = {}", v, r);
    r
}

/// Compile a library from the given set of input C files.
///
/// This will simply compile all files into object files and then assemble them
/// into the output. This will read the standard environment variables to detect
/// cross compilations and such.
///
/// # Example
///
/// ```no_run
/// use std::default::Default;
/// gcc::compile_library("libfoo.a", &Default::default(), &[
///     "foo.c",
///     "bar.c",
/// ]);
/// ```
pub fn compile_library(output: &str, config: &Config, files: &[&str]) {
    assert!(output.starts_with("lib"));
    assert!(output.ends_with(".a"));

    let target = getenv("TARGET").unwrap();
    let opt_level = getenv("OPT_LEVEL").unwrap();

    let mut cmd = Command::new(gcc(target.as_slice()));
    cmd.arg(format!("-O{}", opt_level));
    cmd.arg("-c");
    cmd.arg("-ffunction-sections").arg("-fdata-sections");
    cmd.args(cflags().as_slice());

    if target.as_slice().contains("-ios") {
        cmd.args(ios_flags(target.as_slice()).as_slice());
    } else {
        if target.contains("windows") {
            cmd.arg("-mwin32");
        }

        if target.as_slice().contains("i686") {
            cmd.arg("-m32");
        } else if target.as_slice().contains("x86_64") {
            cmd.arg("-m64");
        }

        if !target.as_slice().contains("i686") {
            cmd.arg("-fPIC");
        }
    }

    for directory in config.include_directories.iter() {
        cmd.arg("-I").arg(directory);
    }

    for flag in config.flags.iter() {
        cmd.arg(flag);
    }

    for &(ref key, ref value) in config.definitions.iter() {
        if let &Some(ref value) = value {
            cmd.arg(format!("-D{}={}", key, value));
        } else {
            cmd.arg(format!("-D{}", key));
        }
    }

    let src = Path::new(getenv("CARGO_MANIFEST_DIR").unwrap());
    let dst = Path::new(getenv("OUT_DIR").unwrap());
    let mut objects = Vec::new();
    for file in files.iter() {
        let obj = dst.join(*file).with_extension("o");
        std::io::fs::mkdir_recursive(&obj.dir_path(), std::io::USER_RWX).unwrap();
        run(cmd.clone().arg(src.join(*file)).arg("-o").arg(&obj));
        objects.push(obj);
    }

    run(Command::new(ar(target.as_slice())).arg("crus")
                                           .arg(dst.join(output))
                                           .args(objects.as_slice())
                                           .args(config.objects.as_slice()));
    println!("cargo:rustc-flags=-L {} -l {}:static",
             dst.display(), output.slice(3, output.len() - 2));
}

fn run(cmd: &mut Command) {
    println!("running: {}", cmd);
    let status = match cmd.stdout(InheritFd(1)).stderr(InheritFd(2)).status() {
        Ok(status) => status,
        Err(e) => panic!("failed to spawn process: {}", e),
    };
    if !status.success() {
        panic!("nonzero exit status: {}", status);
    }
}

fn get_var(var_base: &str) -> Result<String, String> {
    let target = getenv("TARGET")
        .expect("Environment variable 'TARGET' is unset");
    let host = match getenv("HOST") {
            None => { return Err("Environment variable 'HOST' is unset".to_string()); }
            Some(x) => x
        };
    let kind = if host == target { "HOST" } else { "TARGET" };
    let target_u = target.split('-')
        .collect::<Vec<&str>>()
        .connect("_");
    let res = getenv(format!("{}_{}", var_base, target).as_slice())
        .or_else(|| getenv(format!("{}_{}", var_base, target_u).as_slice()))
        .or_else(|| getenv(format!("{}_{}", kind, var_base).as_slice()))
        .or_else(|| getenv(var_base));

    match res {
        Some(res) => Ok(res),
        None => Err("Could not get environment variable".to_string()),
    }
}

fn gcc(target: &str) -> String {
    let is_android = target.find_str("android").is_some();

    get_var("CC").unwrap_or(if cfg!(windows) {
        "gcc".to_string()
    } else if is_android {
        format!("{}-gcc", target)
    } else {
        "cc".to_string()
    })
}

fn ar(target: &str) -> String {
    let is_android = target.find_str("android").is_some();

    get_var("AR").unwrap_or(if is_android {
        format!("{}-ar", target)
    } else {
        "ar".to_string()
    })
}

fn cflags() -> Vec<String> {
    get_var("CFLAGS").unwrap_or(String::new())
       .as_slice().words().map(|s| s.to_string())
       .collect()
}

fn ios_flags(target: &str) -> Vec<String> {
    let mut is_device_arch = false;
    let mut res = Vec::new();

    if target.starts_with("arm-") {
        res.push("-arch");
        res.push("armv7");
        is_device_arch = true;
    } else if target.starts_with("arm64-") {
        res.push("-arch");
        res.push("arm64");
        is_device_arch = true;
    } else if target.starts_with("i386-") {
        res.push("-m32");
    } else if target.starts_with("x86_64-") {
        res.push("-m64");
    }

    let sdk = if is_device_arch {"iphoneos"} else {"iphonesimulator"};

    println!("Detecting iOS SDK path for {}", sdk);
    let sdk_path = Command::new("xcrun")
        .arg("--show-sdk-path")
        .arg("--sdk")
        .arg(sdk)
        .stderr(InheritFd(2))
        .output()
        .unwrap()
        .output;

    let sdk_path = String::from_utf8(sdk_path).unwrap();

    res.push("-isysroot");
    res.push(sdk_path.as_slice().trim());

    res.iter().map(|s| s.to_string()).collect::<Vec<_>>()
}
<|endoftext|>