<commit_before>use std::env;
use std::fs::File;
use std::io::{BufWriter, Write};
use std::path::Path;

#[cfg(unix)]
use std::os::unix::fs::symlink;

#[cfg(all(windows, not(target_env = "msvc")))]
use std::os::windows::fs::symlink_file as symlink;

#[cfg(not(target_env = "msvc"))]
use std::fs;
#[cfg(not(target_env = "msvc"))]
use std::path::PathBuf;

fn main() {
    generate_srgb_tables();

    #[cfg(not (target_env = "msvc"))]
    generate_convenience_lib().unwrap();
}

/// Converts an sRGB color value to a linear sRGB color value (undoes the gamma correction).
///
/// The input and the output are supposed to be in the [0, 1] range.
#[inline]
fn linearize(c: f64) -> f64 {
    if c <= (12.92 * 0.0031308) {
        c / 12.92
    } else {
        ((c + 0.055) / 1.055).powf(2.4)
    }
}

/// Converts a linear sRGB color value to a normal sRGB color value (applies the gamma correction).
///
/// The input and the output are supposed to be in the [0, 1] range.
#[inline]
fn unlinearize(c: f64) -> f64 {
    if c <= 0.0031308 {
        12.92 * c
    } else {
        1.055 * c.powf(1f64 / 2.4) - 0.055
    }
}

fn compute_table<F: Fn(f64) -> f64>(f: F) -> [u8; 256] {
    let mut table = [0; 256];

    for i in 0..=255 {
        let c = i as f64 / 255.0;
        let x = f(c);
        table[i] = (x * 255.0).round() as u8;
    }

    table
}

fn print_table<W: Write>(w: &mut W, name: &str, table: &[u8]) {
    writeln!(w, "const {}: [u8; {}] = [", name, table.len()).unwrap();

    for x in table {
        writeln!(w, "    {},", x).unwrap();
    }

    writeln!(w, "];").unwrap();
}

fn generate_srgb_tables() {
    let linearize_table = compute_table(linearize);
    let unlinearize_table = compute_table(unlinearize);

    let path = Path::new(&env::var("OUT_DIR").unwrap()).join("srgb-codegen.rs");
    let mut file = BufWriter::new(File::create(&path).unwrap());

    print_table(&mut file, "LINEARIZE", &linearize_table);
    print_table(&mut file, "UNLINEARIZE", &unlinearize_table);
}

/// Generate libtool archive file librsvg_internals.la
/// From: https://docs.rs/libtool/0.1.1/libtool/
#[cfg(not (target_env = "msvc"))]
pub fn generate_convenience_lib() -> std::io::Result<()> {
    let target = env::var("TARGET").expect("TARGET was not set");
    let build_dir = env::var("LIBRSVG_BUILD_DIR").expect("LIBRSVG_BUILD_DIR was not set");
    let target_dir = env::var("LIBRSVG_TARGET_DIR").expect("LIBRSVG_TARGET_DIR was not set");
    let libs_dir = format!("{}/.libs", build_dir);
    let libs_path = PathBuf::from(&libs_dir);
    let la_path = PathBuf::from(format!("{}/librsvg_internals.la", build_dir));
    let rust_lib = if target.contains("windows") {
        /* https://github.com/rust-lang/rust/issues/43749 */
        "rsvg_internals.lib"
    } else {
        "librsvg_internals.a"
    };
    let old_lib_path = PathBuf::from(format!("{}/{}", target_dir, rust_lib));
    let new_lib_path = PathBuf::from(format!("{}/librsvg_internals.a", libs_dir));

    match fs::create_dir_all(&libs_path) {
        Ok(()) => println!("libs_path created"),
        _ => panic!("Failed to create libs_path"),
    }

    if la_path.exists() {
        fs::remove_file(&la_path)?;
    }

    /* PathBuf.exists() traverses symlinks so just try and remove it */
    match fs::remove_file(&new_lib_path) {
        Ok(_v) => {},
        Err(e) => println!("Error removing symlink: {:?}", e),
    }

    let mut file = File::create(&la_path).unwrap();
    writeln!(file, "# librsvg_internals.la - a libtool library file")?;
    writeln!(file, "# Generated by libtool-rust")?;
    writeln!(file, "dlname=''")?;
    writeln!(file, "library_names=''")?;
    writeln!(file, "old_library='librsvg_internals.a'")?;
    writeln!(file, "inherited_linker_flags=''")?;
    writeln!(file, "installed=no")?;
    writeln!(file, "shouldnotlink=no")?;
    symlink(&old_lib_path, &new_lib_path)?;
    Ok(())
}
<commit_msg>(#491): rsvg_internals: Don't require environment variables when building as rust crate<commit_after>use std::env;
use std::fs::File;
use std::io::{BufWriter, Write};
use std::path::Path;

#[cfg(all(unix, feature = "c-library"))]
use std::os::unix::fs::symlink;

#[cfg(all(windows, not(target_env = "msvc"), feature="c-library"))]
use std::os::windows::fs::symlink_file as symlink;

#[cfg(all(not(target_env = "msvc"), feature="c-library"))]
use std::fs;
#[cfg(all(not(target_env = "msvc"), feature="c-library"))]
use std::path::PathBuf;

fn main() {
    generate_srgb_tables();

    generate_convenience_lib().unwrap();
}

/// Converts an sRGB color value to a linear sRGB color value (undoes the gamma correction).
///
/// The input and the output are supposed to be in the [0, 1] range.
#[inline]
fn linearize(c: f64) -> f64 {
    if c <= (12.92 * 0.0031308) {
        c / 12.92
    } else {
        ((c + 0.055) / 1.055).powf(2.4)
    }
}

/// Converts a linear sRGB color value to a normal sRGB color value (applies the gamma correction).
///
/// The input and the output are supposed to be in the [0, 1] range.
#[inline]
fn unlinearize(c: f64) -> f64 {
    if c <= 0.0031308 {
        12.92 * c
    } else {
        1.055 * c.powf(1f64 / 2.4) - 0.055
    }
}

fn compute_table<F: Fn(f64) -> f64>(f: F) -> [u8; 256] {
    let mut table = [0; 256];

    for i in 0..=255 {
        let c = i as f64 / 255.0;
        let x = f(c);
        table[i] = (x * 255.0).round() as u8;
    }

    table
}

fn print_table<W: Write>(w: &mut W, name: &str, table: &[u8]) {
    writeln!(w, "const {}: [u8; {}] = [", name, table.len()).unwrap();

    for x in table {
        writeln!(w, "    {},", x).unwrap();
    }

    writeln!(w, "];").unwrap();
}

fn generate_srgb_tables() {
    let linearize_table = compute_table(linearize);
    let unlinearize_table = compute_table(unlinearize);

    let path = Path::new(&env::var("OUT_DIR").unwrap()).join("srgb-codegen.rs");
    let mut file = BufWriter::new(File::create(&path).unwrap());

    print_table(&mut file, "LINEARIZE", &linearize_table);
    print_table(&mut file, "UNLINEARIZE", &unlinearize_table);
}

/// Generate libtool archive file librsvg_internals.la
/// From: https://docs.rs/libtool/0.1.1/libtool/
#[cfg(all(feature = "c-library", not(target_env = "msvc")))]
pub fn generate_convenience_lib() -> std::io::Result<()> {
    let target = env::var("TARGET").expect("TARGET was not set");
    let build_dir = env::var("LIBRSVG_BUILD_DIR").expect("LIBRSVG_BUILD_DIR was not set");
    let target_dir = env::var("LIBRSVG_TARGET_DIR").expect("LIBRSVG_TARGET_DIR was not set");
    let libs_dir = format!("{}/.libs", build_dir);
    let libs_path = PathBuf::from(&libs_dir);
    let la_path = PathBuf::from(format!("{}/librsvg_internals.la", build_dir));
    let rust_lib = if target.contains("windows") {
        /* https://github.com/rust-lang/rust/issues/43749 */
        "rsvg_internals.lib"
    } else {
        "librsvg_internals.a"
    };
    let old_lib_path = PathBuf::from(format!("{}/{}", target_dir, rust_lib));
    let new_lib_path = PathBuf::from(format!("{}/librsvg_internals.a", libs_dir));

    match fs::create_dir_all(&libs_path) {
        Ok(()) => println!("libs_path created"),
        _ => panic!("Failed to create libs_path"),
    }

    if la_path.exists() {
        fs::remove_file(&la_path)?;
    }

    /* PathBuf.exists() traverses symlinks so just try and remove it */
    match fs::remove_file(&new_lib_path) {
        Ok(_v) => {},
        Err(e) => println!("Error removing symlink: {:?}", e),
    }

    let mut file = File::create(&la_path).unwrap();
    writeln!(file, "# librsvg_internals.la - a libtool library file")?;
    writeln!(file, "# Generated by libtool-rust")?;
    writeln!(file, "dlname=''")?;
    writeln!(file, "library_names=''")?;
    writeln!(file, "old_library='librsvg_internals.a'")?;
    writeln!(file, "inherited_linker_flags=''")?;
    writeln!(file, "installed=no")?;
    writeln!(file, "shouldnotlink=no")?;
    symlink(&old_lib_path, &new_lib_path)?;
    Ok(())
}

#[cfg(not(all(feature = "c-library", not(target_env = "msvc"))))]
pub fn generate_convenience_lib() -> std::io::Result<()> {
    Ok(())
}
<|endoftext|>


<commit_before>use crate::utils::{match_def_path, span_lint_and_sugg};
use if_chain::if_chain;
use rustc::declare_lint_pass;
use rustc::hir;
use rustc::hir::def::{DefKind, Res};
use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
use rustc_errors::Applicability;
use rustc_session::declare_tool_lint;

declare_clippy_lint! {
    /// **What it does:** Checks for usage of `ATOMIC_X_INIT`, `ONCE_INIT`, and
    /// `uX/iX::MIN/MAX`.
    ///
    /// **Why is this bad?** `const fn`s exist
    ///
    /// **Known problems:** None.
    ///
    /// **Example:**
    /// ```rust
    /// # use core::sync::atomic::{ATOMIC_ISIZE_INIT, AtomicIsize};
    /// static FOO: AtomicIsize = ATOMIC_ISIZE_INIT;
    /// ```
    ///
    /// Could be written:
    ///
    /// ```rust
    /// # use core::sync::atomic::AtomicIsize;
    /// static FOO: AtomicIsize = AtomicIsize::new(0);
    /// ```
    pub REPLACE_CONSTS,
    pedantic,
    "Lint usages of standard library `const`s that could be replaced by `const fn`s"
}

declare_lint_pass!(ReplaceConsts => [REPLACE_CONSTS]);

impl<'a, 'tcx> LateLintPass<'a, 'tcx> for ReplaceConsts {
    fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx hir::Expr<'_>) {
        if_chain! {
            if let hir::ExprKind::Path(ref qp) = expr.kind;
            if let Res::Def(DefKind::Const, def_id) = cx.tables.qpath_res(qp, expr.hir_id);
            then {
                for &(ref const_path, repl_snip) in &REPLACEMENTS {
                    if match_def_path(cx, def_id, const_path) {
                        span_lint_and_sugg(
                            cx,
                            REPLACE_CONSTS,
                            expr.span,
                            &format!("using `{}`", const_path.last().expect("empty path")),
                            "try this",
                            repl_snip.to_string(),
                            Applicability::MachineApplicable,
                        );
                        return;
                    }
                }
            }
        }
    }
}

const REPLACEMENTS: [([&str; 3], &str); 24] = [
    // Min
    (["core", "isize", "MIN"], "isize::min_value()"),
    (["core", "i8", "MIN"], "i8::min_value()"),
    (["core", "i16", "MIN"], "i16::min_value()"),
    (["core", "i32", "MIN"], "i32::min_value()"),
    (["core", "i64", "MIN"], "i64::min_value()"),
    (["core", "i128", "MIN"], "i128::min_value()"),
    (["core", "usize", "MIN"], "usize::min_value()"),
    (["core", "u8", "MIN"], "u8::min_value()"),
    (["core", "u16", "MIN"], "u16::min_value()"),
    (["core", "u32", "MIN"], "u32::min_value()"),
    (["core", "u64", "MIN"], "u64::min_value()"),
    (["core", "u128", "MIN"], "u128::min_value()"),
    // Max
    (["core", "isize", "MAX"], "isize::max_value()"),
    (["core", "i8", "MAX"], "i8::max_value()"),
    (["core", "i16", "MAX"], "i16::max_value()"),
    (["core", "i32", "MAX"], "i32::max_value()"),
    (["core", "i64", "MAX"], "i64::max_value()"),
    (["core", "i128", "MAX"], "i128::max_value()"),
    (["core", "usize", "MAX"], "usize::max_value()"),
    (["core", "u8", "MAX"], "u8::max_value()"),
    (["core", "u16", "MAX"], "u16::max_value()"),
    (["core", "u32", "MAX"], "u32::max_value()"),
    (["core", "u64", "MAX"], "u64::max_value()"),
    (["core", "u128", "MAX"], "u128::max_value()"),
];
<commit_msg>Auto merge of #4970 - krishna-veerareddy:fix-replace-consts-documentation, r=flip1995<commit_after>use crate::utils::{match_def_path, span_lint_and_sugg};
use if_chain::if_chain;
use rustc::declare_lint_pass;
use rustc::hir;
use rustc::hir::def::{DefKind, Res};
use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
use rustc_errors::Applicability;
use rustc_session::declare_tool_lint;

declare_clippy_lint! {
    /// **What it does:** Checks for usage of standard library
    /// `const`s that could be replaced by `const fn`s.
    ///
    /// **Why is this bad?** `const fn`s exist
    ///
    /// **Known problems:** None.
    ///
    /// **Example:**
    /// ```rust
    /// let x = std::u32::MIN;
    /// let y = std::u32::MAX;
    /// ```
    ///
    /// Could be written:
    ///
    /// ```rust
    /// let x = u32::min_value();
    /// let y = u32::max_value();
    /// ```
    pub REPLACE_CONSTS,
    pedantic,
    "Lint usages of standard library `const`s that could be replaced by `const fn`s"
}

declare_lint_pass!(ReplaceConsts => [REPLACE_CONSTS]);

impl<'a, 'tcx> LateLintPass<'a, 'tcx> for ReplaceConsts {
    fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx hir::Expr<'_>) {
        if_chain! {
            if let hir::ExprKind::Path(ref qp) = expr.kind;
            if let Res::Def(DefKind::Const, def_id) = cx.tables.qpath_res(qp, expr.hir_id);
            then {
                for &(ref const_path, repl_snip) in &REPLACEMENTS {
                    if match_def_path(cx, def_id, const_path) {
                        span_lint_and_sugg(
                            cx,
                            REPLACE_CONSTS,
                            expr.span,
                            &format!("using `{}`", const_path.last().expect("empty path")),
                            "try this",
                            repl_snip.to_string(),
                            Applicability::MachineApplicable,
                        );
                        return;
                    }
                }
            }
        }
    }
}

const REPLACEMENTS: [([&str; 3], &str); 24] = [
    // Min
    (["core", "isize", "MIN"], "isize::min_value()"),
    (["core", "i8", "MIN"], "i8::min_value()"),
    (["core", "i16", "MIN"], "i16::min_value()"),
    (["core", "i32", "MIN"], "i32::min_value()"),
    (["core", "i64", "MIN"], "i64::min_value()"),
    (["core", "i128", "MIN"], "i128::min_value()"),
    (["core", "usize", "MIN"], "usize::min_value()"),
    (["core", "u8", "MIN"], "u8::min_value()"),
    (["core", "u16", "MIN"], "u16::min_value()"),
    (["core", "u32", "MIN"], "u32::min_value()"),
    (["core", "u64", "MIN"], "u64::min_value()"),
    (["core", "u128", "MIN"], "u128::min_value()"),
    // Max
    (["core", "isize", "MAX"], "isize::max_value()"),
    (["core", "i8", "MAX"], "i8::max_value()"),
    (["core", "i16", "MAX"], "i16::max_value()"),
    (["core", "i32", "MAX"], "i32::max_value()"),
    (["core", "i64", "MAX"], "i64::max_value()"),
    (["core", "i128", "MAX"], "i128::max_value()"),
    (["core", "usize", "MAX"], "usize::max_value()"),
    (["core", "u8", "MAX"], "u8::max_value()"),
    (["core", "u16", "MAX"], "u16::max_value()"),
    (["core", "u32", "MAX"], "u32::max_value()"),
    (["core", "u64", "MAX"], "u64::max_value()"),
    (["core", "u128", "MAX"], "u128::max_value()"),
];
<|endoftext|>


<commit_before>use request::ToParams;

#[derive(Debug)]
pub enum Credentials {
    ProviderKey(String),
    ServiceToken(String),
}

impl Credentials {
    pub fn from_key(key: String) -> Self {
        Credentials::ProviderKey(key)
    }

    pub fn from_token(token: String) -> Self {
        Credentials::ServiceToken(token)
    }
}

impl ToParams for Credentials {
    fn to_params(&self) -> Vec<(&str, &str)> {
        use self::Credentials::*;

        let (field, value) = match *self {
            ProviderKey(ref key) => ("provider_key", key),
            ServiceToken(ref token) => ("service_token", token)
        };

        vec![(field, value)]
    }
}

#[derive(Debug)]
pub struct Service {
    service_id: String,
    creds: Credentials,
}

impl Service {
    pub fn new(service_id: String, creds: Credentials) -> Self {
        Self { service_id, creds }
    }
}

impl ToParams for Service {
    fn to_params(&self) -> Vec<(&str, &str)> {
        let mut res = vec![("service_id", self.service_id.as_str())];
        let creds = self.creds.to_params();
        res.extend(creds);
        res
    }
}

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

    #[test]
    fn transforms_service_id_and_key_into_params() {
        let service_id = "my_service_id";
        let provider_key = "my_provider_key";
        let creds = Credentials::from_key(provider_key.to_owned());
        let service = Service::new(service_id.to_owned(), creds);

        let result = service.to_params();

        let expected = vec![("service_id", service_id),
                            ("provider_key", provider_key)];
        assert_eq!(expected, result);
    }

    #[test]
    fn transforms_service_id_and_token_into_params() {
        let service_id = "my_service_id";
        let token = "my_token";
        let creds = Credentials::from_token(token.to_owned());
        let service = Service::new(service_id.to_owned(), creds);

        let result = service.to_params();

        let expected = vec![("service_id", service_id),
                            ("service_token", token)];
        assert_eq!(expected, result);
    }
}
<commit_msg>service: avoid stringly types by implementing several traits<commit_after>use request::ToParams;
use errors::*;

use std::str::FromStr;

#[derive(Debug)]
pub struct ProviderKey(String);
#[derive(Debug)]
pub struct ServiceToken(String);

#[derive(Debug)]
pub enum Credentials {
    ProviderKey(ProviderKey),
    ServiceToken(ServiceToken),
}

// These trait impls provide a way to reference our types as &str
impl AsRef<str> for ProviderKey {
    fn as_ref(&self) -> &str {
        self.0.as_str()
    }
}

impl AsRef<str> for ServiceToken {
    fn as_ref(&self) -> &str {
        self.0.as_str()
    }
}

// These trait impls provide a way to &str#parse()
impl FromStr for ProviderKey {
    type Err = Error;

    fn from_str(s: &str) -> Result<ProviderKey> {
        Ok(ProviderKey(s.to_owned()))
    }
}

impl FromStr for ServiceToken {
    type Err = Error;

    fn from_str(s: &str) -> Result<ServiceToken> {
        Ok(ServiceToken(s.to_owned()))
    }
}

// These trait impls are similar to FromStr (but are infallible)
impl<'a> From<&'a str> for ProviderKey where Self: FromStr {
    fn from(s: &'a str) -> ProviderKey {
        s.parse().unwrap()
    }
}

impl<'a> From<&'a str> for ServiceToken where Self: FromStr {
    fn from(s: &'a str) -> ServiceToken {
        s.parse().unwrap()
    }
}

// These trait impls take ownership of a given String
impl From<String> for ProviderKey {
    fn from(s: String) -> ProviderKey {
        ProviderKey(s)
    }
}

impl From<String> for ServiceToken {
    fn from(s: String) -> ServiceToken {
        ServiceToken(s)
    }
}

impl Into<Credentials> for ProviderKey {
    fn into(self) -> Credentials {
        Credentials::ProviderKey(self)
    }
}

impl Into<Credentials> for ServiceToken {
    fn into(self) -> Credentials {
        Credentials::ServiceToken(self)
    }
}

impl Credentials {
    pub fn from_key<T: Into<ProviderKey>>(key: T) -> Self {
        Credentials::ProviderKey(key.into())
    }

    pub fn from_token<T: Into<ServiceToken>>(token: T) -> Self {
        Credentials::ServiceToken(token.into())
    }
}

impl ToParams for Credentials {
    fn to_params(&self) -> Vec<(&str, &str)> {
        use self::Credentials::*;

        let (field, value) = match *self {
            ProviderKey(ref key) => ("provider_key", key.as_ref()),
            ServiceToken(ref token) => ("service_token", token.as_ref())
        };

        vec![(field, value)]
    }
}

#[derive(Debug)]
pub struct ServiceId(String);

#[derive(Debug)]
pub struct Service {
    service_id: ServiceId,
    creds: Credentials,
}

impl AsRef<str> for ServiceId {
    fn as_ref(&self) -> &str {
        self.0.as_str()
    }
}

impl FromStr for ServiceId {
    type Err = Error;

    fn from_str(s: &str) -> Result<ServiceId> {
        Ok(ServiceId(s.to_owned()))
    }
}

impl<'a> From<&'a str> for ServiceId where Self: FromStr {
    fn from(s: &'a str) -> ServiceId {
        s.parse().unwrap()
    }
}

impl From<String> for ServiceId {
    fn from(s: String) -> ServiceId {
        ServiceId(s)
    }
}

impl Service {
    pub fn new<T: Into<ServiceId>>(service_id: T, creds: Credentials) -> Self {
        let service_id = service_id.into();
        Self { service_id, creds }
    }
}

impl ToParams for Service {
    fn to_params(&self) -> Vec<(&str, &str)> {
        let mut res = vec![("service_id", self.service_id.as_ref())];
        let creds = self.creds.to_params();
        res.extend(creds);
        res
    }
}

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

    #[test]
    fn transforms_service_id_and_key_into_params() {
        let service_id = "my_service_id";
        let provider_key = "my_provider_key";
        let creds = Credentials::from_key(provider_key.to_owned());
        let service = Service::new(service_id.to_owned(), creds);

        let result = service.to_params();

        let expected = vec![("service_id", service_id),
                            ("provider_key", provider_key)];
        assert_eq!(expected, result);
    }

    #[test]
    fn transforms_service_id_and_token_into_params() {
        let service_id = "my_service_id";
        let token = "my_token";
        let creds = Credentials::from_token(token.to_owned());
        let service = Service::new(service_id.to_owned(), creds);

        let result = service.to_params();

        let expected = vec![("service_id", service_id),
                            ("service_token", token)];
        assert_eq!(expected, result);
    }
}
<|endoftext|>


<commit_before>/// Utilities to make it easier to maintain Janus session state between plugin callbacks.

use std::ops::Deref;
use std::sync::Arc;
use super::PluginHandle;

/// A representation of session state associated with a Janus plugin session handle.
#[derive(Debug)]
pub struct SessionHandle<T> {
    pub handle: *mut PluginHandle,
    state: T,
}

impl<T> SessionHandle<T> {

    /// Allocates a boxed, reference-counted SessionHandle associated with an opaque Janus handle
    /// (whose plugin_handle will then point to the contents of the box).
    pub fn establish(handle: *mut PluginHandle, state: T) -> Box<Arc<Self>> {
        let result = Box::new(Arc::new(Self { handle, state: state }));
        unsafe { (*handle).plugin_handle = result.as_ref() as *const _ as *mut _ };
        result
    }

    /// Retrieves the reference-counted SessionHandle pointed to by an opaque Janus handle.
    pub fn from_ptr<'a>(handle: *mut PluginHandle) -> &'a Arc<Self> {
        unsafe { &*((*handle).plugin_handle as *mut Arc<Self>) }
    }
}

impl<T> Deref for SessionHandle<T> {
    type Target = T;
    fn deref(&self) -> &T {
        &self.state
    }
}

// the pointer is opaque to Janus code, so this handle is threadsafe to the extent that the state is

unsafe impl<T: Sync> Sync for SessionHandle<T> {}
unsafe impl<T: Send> Send for SessionHandle<T> {}

#[cfg(test)]
mod tests {

    use super::*;
    use std::ptr;

    #[test]
    fn handle_round_trip() {
        struct State(i32);
        let mut handle = PluginHandle {
            gateway_handle: ptr::null_mut(),
            plugin_handle: ptr::null_mut(),
            stopped_bitfield: 0,
            __padding: Default::default()
        };
        let ptr = &mut handle as *mut _;
        let session = SessionHandle::establish(ptr, State(42));
        assert_eq!(session.as_ref() as *const _ as *mut _, handle.plugin_handle);
        assert_eq!(SessionHandle::<State>::from_ptr(ptr).state.0, 42);
    }
}
<commit_msg>Better session handle API<commit_after>/// Utilities to make it easier to maintain Janus session state between plugin callbacks.

use std::error::Error;
use std::ops::Deref;
use std::sync::Arc;
use super::PluginHandle;

/// A representation of session state associated with a Janus plugin session handle.
#[derive(Debug)]
pub struct SessionHandle<T> {
    pub handle: *mut PluginHandle,
    state: T,
}

impl<T> SessionHandle<T> {

    /// Allocates a boxed, reference-counted SessionHandle associated with an opaque Janus handle
    /// (whose plugin_handle will then point to the contents of the box).
    pub fn associate(handle: *mut PluginHandle, state: T) -> Result<Box<Arc<Self>>, Box<Error+Send+Sync>> {
        unsafe {
            match handle.as_mut() {
                Some(_) => {
                    let result = Box::new(Arc::new(Self { handle, state: state }));
                    (*handle).plugin_handle = result.as_ref() as *const _ as *mut _;
                    Ok(result)
                },
                None => Err(From::from("Null handle provided!"))
            }
        }
    }

    /// Retrieves the reference-counted SessionHandle pointed to by an opaque Janus handle.
    pub fn from_ptr<'a>(handle: *mut PluginHandle) -> Result<Arc<Self>, Box<Error+Send+Sync>> {
        unsafe {
            match handle.as_ref() {
                Some(handle) => Ok(Arc::clone((handle.plugin_handle as *mut Arc<Self>).as_ref().unwrap())),
                None => Err(From::from("Null handle provided!"))
            }
        }
    }
}

impl<T> Deref for SessionHandle<T> {
    type Target = T;
    fn deref(&self) -> &T {
        &self.state
    }
}

// the pointer is opaque to Janus code, so this handle is threadsafe to the extent that the state is

unsafe impl<T: Sync> Sync for SessionHandle<T> {}
unsafe impl<T: Send> Send for SessionHandle<T> {}

#[cfg(test)]
mod tests {

    use super::*;
    use std::ptr;

    #[test]
    fn handle_round_trip() {
        struct State(i32);
        let mut handle = PluginHandle {
            gateway_handle: ptr::null_mut(),
            plugin_handle: ptr::null_mut(),
            stopped_bitfield: 0,
            __padding: Default::default()
        };
        let ptr = &mut handle as *mut _;
        let session = SessionHandle::associate(ptr, State(42)).unwrap();
        assert_eq!(session.as_ref() as *const _ as *mut _, handle.plugin_handle);
        assert_eq!(SessionHandle::<State>::from_ptr(ptr).unwrap().state.0, 42);
    }
}
<|endoftext|>


<commit_before>
use sodiumoxide::crypto::onetimeauth::poly1305;
use sodiumoxide::crypto::hash::sha512;
use sodiumoxide::crypto::scalarmult::curve25519;
use sodiumoxide::crypto::stream::chacha20;
use sodiumoxide::crypto::box_::curve25519xsalsa20poly1305;
//use sodiumoxide::randombytes::randombytes;
use byteorder::{LittleEndian, WriteBytesExt};

macro_rules! make_fixed {
    ($t:ty, $n:expr, $v:expr) => ({
        let mut res : [$t; $n] = [0; $n];
        assert!($v.len() == $n);
        for i in 0..$n { res[i] = $v[i] }
        res
    })
}

macro_rules! concat_vec {
    ($x:expr, $($y:expr),+) => ({
        $x.iter() $(.chain($y.iter()))+ .cloned().collect::<Vec<u8>>()
    })
}

pub fn pad16(input: &[u8]) -> Vec<u8> {
    let mut out = input.iter().cloned().collect::<Vec<u8>>();
    for _ in (out.len() % 16)..16 {
        out.push(0);
    }
    out
}

pub const MAC_LEN: usize = 16;
pub const CV_LEN: usize = 48;
pub const H_LEN: usize = 64;
pub const DH_LEN: usize = 32;
// "Noise255" followed by 16 zeros
pub const SUITE_NAME: [u8; 24] = [0x4E, 0x6F, 0x69, 0x73, 0x65, 0x32, 0x35, 0x35,
                                  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                                  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00];

pub fn hmac_sha512(key: &[u8], message: &[u8]) -> sha512::Digest {
    let nkey = if key.len() > sha512::HASHBYTES {
        sha512::hash(key).0
    } else {
        let mut arr = [0u8; sha512::HASHBYTES];
        for i in 0..key.len() { arr[i] = key[i] }
        arr
    };
    let o_pad = nkey.iter().map(|x| x^0x5c).collect::<Vec<u8>>();
    let i_pad = nkey.iter().map(|x| x^0x36).collect::<Vec<u8>>();

    let in1 : sha512::Digest = sha512::hash(&concat_vec!(i_pad, message)[..]);
    sha512::hash(&concat_vec!(o_pad, in1.0)[..])
}

pub fn getkey(key: &chacha20::Key, nonce: &chacha20::Nonce) -> chacha20::Key {
    chacha20::Key(make_fixed!(u8, chacha20::KEYBYTES, chacha20::stream(chacha20::KEYBYTES, nonce, key)))
}

pub fn kdf(key: &chacha20::Key, nonce: &chacha20::Nonce, input: &[u8]) -> chacha20::Key {
    chacha20::Key(make_fixed!(u8, 32, hmac_sha512(&getkey(key, nonce).0[..], input).0[..32]))
}

pub fn dh(privkey: &[u8; DH_LEN], pubkey: &[u8; DH_LEN]) -> [u8; DH_LEN] {
    curve25519::scalarmult(&curve25519::Scalar(*privkey), &curve25519::GroupElement(*pubkey)).0
}

pub struct NoiseBody {
    ciphertext: Vec<u8>,
    mac: poly1305::Tag
}

#[derive(Clone)]
pub struct PubKey(pub [u8; DH_LEN]);
#[derive(Clone)]
pub struct PrivKey(pub [u8; DH_LEN]);

#[derive(Clone)]
pub struct KeyPair {
    pub pubkey: PubKey,
    pub privkey: PrivKey
}

pub struct Session {
    s: Option<KeyPair>,
    e: Option<KeyPair>,
    rs: Option<PubKey>,
    re: Option<PubKey>,
    k: Option<chacha20::Key>,
    n: u64,
    h: sha512::Digest
}

pub enum Descriptor {
    Ephemeral,
    Static,
    DHSS,
    DHEE,
    DHSE,
    DHES
}

pub fn gen_keypair() -> KeyPair {
    let bkp = curve25519xsalsa20poly1305::gen_keypair();
    KeyPair {
        pubkey: PubKey((bkp.0).0),
        privkey: PrivKey((bkp.1).0)
    }
}

impl Session {
    pub fn new(local: Option<KeyPair>, remote: Option<PubKey>) -> Session {
        Session {
            s: local,
            e: None,
            rs: remote,
            re: None,
            k: None,
            n: 0,
            h: sha512::Digest([0u8; 64])
        }
    }

    pub fn get_nonce(&mut self) -> chacha20::Nonce {
        let mut n = vec![];
        n.write_u64::<LittleEndian>(self.n).unwrap();
        self.n += 1;
        chacha20::Nonce::from_slice(&n[..]).unwrap()
    }

    pub fn derive(&mut self) -> Session {
        let n = self.get_nonce();
        Session {
            s: self.s.clone(),
            e: None,
            rs: self.rs.clone(),
            re: None,
            k: match self.k {
                Some(ref k) => {
                    Some(getkey(&k, &n))
                },
                None => None
            },
            n: 0,
            h: self.h.clone()
        }
    }

    fn session_dh(&mut self, sender: &PrivKey, receiver: &PubKey) {
        let n = self.get_nonce();
        let k = self.k.clone().unwrap_or(chacha20::Key([0; 32]));
        self.k = Some(kdf(&k, &n, &dh(&sender.0, &receiver.0)[..]));
    }

    pub fn create(&mut self, prologue: &[u8], descriptors: &[Descriptor], payload: &[u8]) -> Vec<u8> {
        assert!(prologue.len() < 256);
        let mut buf = vec![];
        buf.push(prologue.len() as u8);
        buf.extend(prologue.iter().cloned());

        macro_rules! dh_branch {
            ($a:ident, $b:ident) => ({
                let $a = self.$a.clone().unwrap().privkey;
                let $b = self.$b.clone().unwrap();
                self.session_dh(&$a, &$b)
            })
        }

        for d in descriptors.iter() {
            match *d {
                Descriptor::Ephemeral => {
                    self.e = Some(gen_keypair());
                    buf.extend(self.e.clone().unwrap().pubkey.0.iter().cloned())
                },
                Descriptor::Static => {
                    let k = self.k.clone().unwrap();
                    let n = self.get_nonce();
                    let s = self.s.clone().unwrap().pubkey.0;
                    let a = concat_vec!(buf, self.h.0);
                    buf.extend(NoiseBody::encrypt(&k, &n, &a[..], &s[..])
                               .write().iter().cloned());
                },
                Descriptor::DHSS => dh_branch!(s, rs),
                Descriptor::DHEE => dh_branch!(e, re),
                Descriptor::DHSE => dh_branch!(s, re),
                Descriptor::DHES => dh_branch!(e, rs)
            }
        }
        let k = self.k.clone().unwrap();
        let n = self.get_nonce();
        let a = concat_vec!(buf, self.h.0);
        buf.extend(NoiseBody::encrypt(&k, &n, &a[..], payload).write().iter().cloned());
        if descriptors.len() > 0 {
            self.h = sha512::hash(&concat_vec!(self.h.0, buf)[..]);
        }

        buf
    }

    pub fn consume(&mut self, data: &[u8], descriptors: &[Descriptor])
                   -> Result<(Vec<u8>, Vec<u8>), ()> {
        assert!(data.len() > 0);
        let plen = data[0] as usize;
        let prologue = data[1..plen+1].to_vec();
        let mut off = plen + 1;

        macro_rules! dh_branch {
            ($a:ident, $b:ident) => ({
                let $a = self.$a.clone().unwrap().privkey;
                let $b = self.$b.clone().unwrap();
                self.session_dh(&$a, &$b)
            })
        }

        for d in descriptors.iter() {
            match *d {
                Descriptor::Ephemeral => {
                    self.re = Some(PubKey(make_fixed!(u8, DH_LEN, data[off..off+DH_LEN])));
                    off += DH_LEN;
                },
                Descriptor::Static => {
                    let k = self.k.clone().unwrap();
                    let n = self.get_nonce();
                    let a = concat_vec!(data[..off], self.h.0);
                    println!("Static");
                    self.rs = Some(PubKey(make_fixed!(u8, DH_LEN, try!(NoiseBody::read(&data[off..off+DH_LEN+MAC_LEN])
                                                                       .decrypt(&k, &n, &a[..])))));
                    off += DH_LEN + MAC_LEN;
                },
                Descriptor::DHSS => dh_branch!(s, rs),
                Descriptor::DHEE => dh_branch!(e, re),
                Descriptor::DHSE => dh_branch!(e, rs), // reversed because consuming instead of creating
                Descriptor::DHES => dh_branch!(s, re)
            }
        }

        println!("Decrypt");
        let k = self.k.clone().unwrap();
        let n = self.get_nonce();
        let a = concat_vec!(data[..off], self.h.0);
        let payload = try!(NoiseBody::read(&data[off..]).decrypt(&k, &n, &a[..]));
        if descriptors.len() > 0 {
            self.h = sha512::hash(&concat_vec!(self.h.0, data)[..]);
        }

        Ok((prologue, payload))
    }
}

impl NoiseBody {
    pub fn read(buf: &[u8]) -> NoiseBody {
        NoiseBody {
            ciphertext: buf[..buf.len() - MAC_LEN].to_vec(),
            mac: poly1305::Tag(make_fixed!(u8, MAC_LEN, buf[buf.len() - MAC_LEN..]))
        }
    }

    pub fn write(&self) -> Vec<u8> {
        let mut out = self.ciphertext.clone();
        out.extend(self.mac.0.iter().cloned());
        out
    }

    pub fn encrypt(key: &chacha20::Key, nonce: &chacha20::Nonce, authtext: &[u8], plaintext: &[u8]) -> NoiseBody {
        let mut message = vec![0u8; 64];
        message.extend(plaintext.iter().cloned());

        let keystream = chacha20::stream_xor(&message[..], nonce, key);
        let mac_key = make_fixed!(u8, 32, keystream[..32]);
        // ignore 32..64
        let ciphertext = &keystream[64..];

        let mut to_be_authenticated = pad16(authtext);
        to_be_authenticated.extend(pad16(&ciphertext[..]).iter().cloned());
        to_be_authenticated.write_u64::<LittleEndian>(authtext.len() as u64).unwrap();
        to_be_authenticated.write_u64::<LittleEndian>(plaintext.len() as u64).unwrap();
        let mac = poly1305::authenticate(&to_be_authenticated[..], &poly1305::Key(mac_key));

        NoiseBody {
            ciphertext: ciphertext.to_vec(),
            mac: mac
        }
    }

    /* pub fn encrypt_padded(key: &chacha20::Key, nonce: &chacha20::Nonce, pad_len: usize, app_data: &[u8], authtext: &[u8]) -> NoiseBody {
        let mut plaintext = vec![];
        plaintext.extend(app_data.iter().cloned());
        for _ in 0..pad_len { plaintext.push(0); } // TODO: Random padding
        plaintext.write_u32::<LittleEndian>(pad_len as u32).unwrap();
        self.encrypt(&plaintext[..], authtext)
    }*/

    pub fn decrypt(&self, key: &chacha20::Key, nonce: &chacha20::Nonce, authtext: &[u8]) -> Result<Vec<u8>, ()> {
        let mut input = vec![0u8; 64];
        input.extend(self.ciphertext.iter().cloned());

        let keystream = chacha20::stream_xor(&input[..], nonce, key);
        let mac_key = make_fixed!(u8, 32, keystream[..32]);
        // ignore 32..64
        let plaintext = &keystream[64..];

        let mut to_be_authenticated = pad16(authtext);
        to_be_authenticated.extend(pad16(&self.ciphertext[..]).iter().cloned());
        to_be_authenticated.write_u64::<LittleEndian>(authtext.len() as u64).unwrap();
        to_be_authenticated.write_u64::<LittleEndian>(plaintext.len() as u64).unwrap();

        if poly1305::verify(&self.mac, &to_be_authenticated[..], &poly1305::Key(mac_key)) {
            Ok(plaintext.to_vec())
        } else {
            Err(())
        }
    }
}

#[test]
fn test_encrypt() {
    let key = chacha20::gen_key();
    let nonce = chacha20::gen_nonce();
    let input = "hello, world";
    let auth = "test";
    let body = NoiseBody::encrypt(&key, &nonce, auth.as_bytes(), input.as_bytes());
    let res = body.decrypt(&key, &nonce, auth.as_bytes());
    match res {
        Ok(v) => assert!(&v[..] == input.as_bytes()),
        Err(_) => assert!(false)
    }
}
<commit_msg>Remove debug prints<commit_after>use sodiumoxide::crypto::onetimeauth::poly1305;
use sodiumoxide::crypto::hash::sha512;
use sodiumoxide::crypto::scalarmult::curve25519;
use sodiumoxide::crypto::stream::chacha20;
use sodiumoxide::crypto::box_::curve25519xsalsa20poly1305;
//use sodiumoxide::randombytes::randombytes;
use byteorder::{LittleEndian, WriteBytesExt};

macro_rules! make_fixed {
    ($t:ty, $n:expr, $v:expr) => ({
        let mut res : [$t; $n] = [0; $n];
        assert!($v.len() == $n);
        for i in 0..$n { res[i] = $v[i] }
        res
    })
}

macro_rules! concat_vec {
    ($x:expr, $($y:expr),+) => ({
        $x.iter() $(.chain($y.iter()))+ .cloned().collect::<Vec<u8>>()
    })
}

pub fn pad16(input: &[u8]) -> Vec<u8> {
    let mut out = input.iter().cloned().collect::<Vec<u8>>();
    for _ in (out.len() % 16)..16 {
        out.push(0);
    }
    out
}

pub const MAC_LEN: usize = 16;
pub const CV_LEN: usize = 48;
pub const H_LEN: usize = 64;
pub const DH_LEN: usize = 32;
// "Noise255" followed by 16 zeros
pub const SUITE_NAME: [u8; 24] = [0x4E, 0x6F, 0x69, 0x73, 0x65, 0x32, 0x35, 0x35,
                                  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                                  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00];

pub fn hmac_sha512(key: &[u8], message: &[u8]) -> sha512::Digest {
    let nkey = if key.len() > sha512::HASHBYTES {
        sha512::hash(key).0
    } else {
        let mut arr = [0u8; sha512::HASHBYTES];
        for i in 0..key.len() { arr[i] = key[i] }
        arr
    };
    let o_pad = nkey.iter().map(|x| x^0x5c).collect::<Vec<u8>>();
    let i_pad = nkey.iter().map(|x| x^0x36).collect::<Vec<u8>>();

    let in1 : sha512::Digest = sha512::hash(&concat_vec!(i_pad, message)[..]);
    sha512::hash(&concat_vec!(o_pad, in1.0)[..])
}

pub fn getkey(key: &chacha20::Key, nonce: &chacha20::Nonce) -> chacha20::Key {
    chacha20::Key(make_fixed!(u8, chacha20::KEYBYTES, chacha20::stream(chacha20::KEYBYTES, nonce, key)))
}

pub fn kdf(key: &chacha20::Key, nonce: &chacha20::Nonce, input: &[u8]) -> chacha20::Key {
    chacha20::Key(make_fixed!(u8, 32, hmac_sha512(&getkey(key, nonce).0[..], input).0[..32]))
}

pub fn dh(privkey: &[u8; DH_LEN], pubkey: &[u8; DH_LEN]) -> [u8; DH_LEN] {
    curve25519::scalarmult(&curve25519::Scalar(*privkey), &curve25519::GroupElement(*pubkey)).0
}

pub struct NoiseBody {
    ciphertext: Vec<u8>,
    mac: poly1305::Tag
}

#[derive(Clone)]
pub struct PubKey(pub [u8; DH_LEN]);
#[derive(Clone)]
pub struct PrivKey(pub [u8; DH_LEN]);

#[derive(Clone)]
pub struct KeyPair {
    pub pubkey: PubKey,
    pub privkey: PrivKey
}

pub struct Session {
    s: Option<KeyPair>,
    e: Option<KeyPair>,
    rs: Option<PubKey>,
    re: Option<PubKey>,
    k: Option<chacha20::Key>,
    n: u64,
    h: sha512::Digest
}

pub enum Descriptor {
    Ephemeral,
    Static,
    DHSS,
    DHEE,
    DHSE,
    DHES
}

pub fn gen_keypair() -> KeyPair {
    let bkp = curve25519xsalsa20poly1305::gen_keypair();
    KeyPair {
        pubkey: PubKey((bkp.0).0),
        privkey: PrivKey((bkp.1).0)
    }
}

impl Session {
    pub fn new(local: Option<KeyPair>, remote: Option<PubKey>) -> Session {
        Session {
            s: local,
            e: None,
            rs: remote,
            re: None,
            k: None,
            n: 0,
            h: sha512::Digest([0u8; 64])
        }
    }

    pub fn get_nonce(&mut self) -> chacha20::Nonce {
        let mut n = vec![];
        n.write_u64::<LittleEndian>(self.n).unwrap();
        self.n += 1;
        chacha20::Nonce::from_slice(&n[..]).unwrap()
    }

    pub fn derive(&mut self) -> Session {
        let n = self.get_nonce();
        Session {
            s: self.s.clone(),
            e: None,
            rs: self.rs.clone(),
            re: None,
            k: match self.k {
                Some(ref k) => {
                    Some(getkey(&k, &n))
                },
                None => None
            },
            n: 0,
            h: self.h.clone()
        }
    }

    fn session_dh(&mut self, sender: &PrivKey, receiver: &PubKey) {
        let n = self.get_nonce();
        let k = self.k.clone().unwrap_or(chacha20::Key([0; 32]));
        self.k = Some(kdf(&k, &n, &dh(&sender.0, &receiver.0)[..]));
    }

    pub fn create(&mut self, prologue: &[u8], descriptors: &[Descriptor], payload: &[u8]) -> Vec<u8> {
        assert!(prologue.len() < 256);
        let mut buf = vec![];
        buf.push(prologue.len() as u8);
        buf.extend(prologue.iter().cloned());

        macro_rules! dh_branch {
            ($a:ident, $b:ident) => ({
                let $a = self.$a.clone().unwrap().privkey;
                let $b = self.$b.clone().unwrap();
                self.session_dh(&$a, &$b)
            })
        }

        for d in descriptors.iter() {
            match *d {
                Descriptor::Ephemeral => {
                    self.e = Some(gen_keypair());
                    buf.extend(self.e.clone().unwrap().pubkey.0.iter().cloned())
                },
                Descriptor::Static => {
                    let k = self.k.clone().unwrap();
                    let n = self.get_nonce();
                    let s = self.s.clone().unwrap().pubkey.0;
                    let a = concat_vec!(buf, self.h.0);
                    buf.extend(NoiseBody::encrypt(&k, &n, &a[..], &s[..])
                               .write().iter().cloned());
                },
                Descriptor::DHSS => dh_branch!(s, rs),
                Descriptor::DHEE => dh_branch!(e, re),
                Descriptor::DHSE => dh_branch!(s, re),
                Descriptor::DHES => dh_branch!(e, rs)
            }
        }
        let k = self.k.clone().unwrap();
        let n = self.get_nonce();
        let a = concat_vec!(buf, self.h.0);
        buf.extend(NoiseBody::encrypt(&k, &n, &a[..], payload).write().iter().cloned());
        if descriptors.len() > 0 {
            self.h = sha512::hash(&concat_vec!(self.h.0, buf)[..]);
        }

        buf
    }

    pub fn consume(&mut self, data: &[u8], descriptors: &[Descriptor])
                   -> Result<(Vec<u8>, Vec<u8>), ()> {
        assert!(data.len() > 0);
        let plen = data[0] as usize;
        let prologue = data[1..plen+1].to_vec();
        let mut off = plen + 1;

        macro_rules! dh_branch {
            ($a:ident, $b:ident) => ({
                let $a = self.$a.clone().unwrap().privkey;
                let $b = self.$b.clone().unwrap();
                self.session_dh(&$a, &$b)
            })
        }

        for d in descriptors.iter() {
            match *d {
                Descriptor::Ephemeral => {
                    self.re = Some(PubKey(make_fixed!(u8, DH_LEN, data[off..off+DH_LEN])));
                    off += DH_LEN;
                },
                Descriptor::Static => {
                    let k = self.k.clone().unwrap();
                    let n = self.get_nonce();
                    let a = concat_vec!(data[..off], self.h.0);
                    self.rs = Some(PubKey(make_fixed!(u8, DH_LEN, try!(NoiseBody::read(&data[off..off+DH_LEN+MAC_LEN])
                                                                       .decrypt(&k, &n, &a[..])))));
                    off += DH_LEN + MAC_LEN;
                },
                Descriptor::DHSS => dh_branch!(s, rs),
                Descriptor::DHEE => dh_branch!(e, re),
                Descriptor::DHSE => dh_branch!(e, rs), // reversed because consuming instead of creating
                Descriptor::DHES => dh_branch!(s, re)
            }
        }

        let k = self.k.clone().unwrap();
        let n = self.get_nonce();
        let a = concat_vec!(data[..off], self.h.0);
        let payload = try!(NoiseBody::read(&data[off..]).decrypt(&k, &n, &a[..]));
        if descriptors.len() > 0 {
            self.h = sha512::hash(&concat_vec!(self.h.0, data)[..]);
        }

        Ok((prologue, payload))
    }
}

impl NoiseBody {
    pub fn read(buf: &[u8]) -> NoiseBody {
        NoiseBody {
            ciphertext: buf[..buf.len() - MAC_LEN].to_vec(),
            mac: poly1305::Tag(make_fixed!(u8, MAC_LEN, buf[buf.len() - MAC_LEN..]))
        }
    }

    pub fn write(&self) -> Vec<u8> {
        let mut out = self.ciphertext.clone();
        out.extend(self.mac.0.iter().cloned());
        out
    }

    pub fn encrypt(key: &chacha20::Key, nonce: &chacha20::Nonce, authtext: &[u8], plaintext: &[u8]) -> NoiseBody {
        let mut message = vec![0u8; 64];
        message.extend(plaintext.iter().cloned());

        let keystream = chacha20::stream_xor(&message[..], nonce, key);
        let mac_key = make_fixed!(u8, 32, keystream[..32]);
        // ignore 32..64
        let ciphertext = &keystream[64..];

        let mut to_be_authenticated = pad16(authtext);
        to_be_authenticated.extend(pad16(&ciphertext[..]).iter().cloned());
        to_be_authenticated.write_u64::<LittleEndian>(authtext.len() as u64).unwrap();
        to_be_authenticated.write_u64::<LittleEndian>(plaintext.len() as u64).unwrap();
        let mac = poly1305::authenticate(&to_be_authenticated[..], &poly1305::Key(mac_key));

        NoiseBody {
            ciphertext: ciphertext.to_vec(),
            mac: mac
        }
    }

    /* pub fn encrypt_padded(key: &chacha20::Key, nonce: &chacha20::Nonce, pad_len: usize, app_data: &[u8], authtext: &[u8]) -> NoiseBody {
        let mut plaintext = vec![];
        plaintext.extend(app_data.iter().cloned());
        for _ in 0..pad_len { plaintext.push(0); } // TODO: Random padding
        plaintext.write_u32::<LittleEndian>(pad_len as u32).unwrap();
        self.encrypt(&plaintext[..], authtext)
    }*/

    pub fn decrypt(&self, key: &chacha20::Key, nonce: &chacha20::Nonce, authtext: &[u8]) -> Result<Vec<u8>, ()> {
        let mut input = vec![0u8; 64];
        input.extend(self.ciphertext.iter().cloned());

        let keystream = chacha20::stream_xor(&input[..], nonce, key);
        let mac_key = make_fixed!(u8, 32, keystream[..32]);
        // ignore 32..64
        let plaintext = &keystream[64..];

        let mut to_be_authenticated = pad16(authtext);
        to_be_authenticated.extend(pad16(&self.ciphertext[..]).iter().cloned());
        to_be_authenticated.write_u64::<LittleEndian>(authtext.len() as u64).unwrap();
        to_be_authenticated.write_u64::<LittleEndian>(plaintext.len() as u64).unwrap();

        if poly1305::verify(&self.mac, &to_be_authenticated[..], &poly1305::Key(mac_key)) {
            Ok(plaintext.to_vec())
        } else {
            Err(())
        }
    }
}

#[test]
fn test_encrypt() {
    let key = chacha20::gen_key();
    let nonce = chacha20::gen_nonce();
    let input = "hello, world";
    let auth = "test";
    let body = NoiseBody::encrypt(&key, &nonce, auth.as_bytes(), input.as_bytes());
    let res = body.decrypt(&key, &nonce, auth.as_bytes());
    match res {
        Ok(v) => assert!(&v[..] == input.as_bytes()),
        Err(_) => assert!(false)
    }
}
<|endoftext|>


<commit_before>use std::env;
use std::path::Path;
use std::string::String;

lazy_static! {
    static ref DEFAULT_CONF_PATH_STR: String = String::from("/etc/sectora.conf");
    static ref CONF_PATH_STR: String = env::var("SECTORA_CONFIG").unwrap_or(DEFAULT_CONF_PATH_STR.clone());
    pub static ref CONF_PATH: &'static Path = Path::new(&(*CONF_PATH_STR));
}

pub const TEMP_DIRNAME: &'static str = "sectora-cache";
<commit_msg>Remove useless modifier<commit_after>use std::env;
use std::path::Path;
use std::string::String;

lazy_static! {
    static ref DEFAULT_CONF_PATH_STR: String = String::from("/etc/sectora.conf");
    static ref CONF_PATH_STR: String = env::var("SECTORA_CONFIG").unwrap_or(DEFAULT_CONF_PATH_STR.clone());
    pub static ref CONF_PATH: &'static Path = Path::new(&(*CONF_PATH_STR));
}

pub const TEMP_DIRNAME: &str = "sectora-cache";
<|endoftext|>


<commit_before>use error::Error;

#[derive(Debug)]
pub struct Summarizer {
    data: Vec<f64>,
}

impl Summarizer {
    /// Construct a `Summarizer` from a slice of 64-bit floating point numbers.
    ///
    /// This constructor is partial, and we obtain the following guarantees
    /// about the resulting sample data:
    ///
    ///   - The sample size is positive
    ///   - All values are finite
    ///   - The data are sorted
    ///
    pub fn new(data: &[f64]) -> Result<Self, Error> {
        if data.is_empty() {
            return Err(Error::EmptySample);
        }

        if data.iter().any(|x| !x.is_finite()) {
            return Err(Error::BadSample);
        }

        let mut data = Vec::from(data);

        // Won't panic: we have checked that each float is finite.
        data.sort_by(|a, b| a.partial_cmp(b).unwrap_or_else(|| unreachable!()));

        let s = Summarizer { data };

        Ok(s)
    }

    pub fn as_slice(&self) -> &[f64] {
        self.data.as_slice()
    }

    pub fn size(&self) -> f64 {
        self.data.len() as f64
    }

    pub fn min(&self) -> f64 {
        self.data[0]
    }

    pub fn max(&self) -> f64 {
        self.data[self.data.len() - 1]
    }

    pub fn mean(&self) -> f64 {
        let t: f64 = self.data.iter().sum();

        t / self.size()
    }

    pub fn median(&self) -> f64 {
        let d = &self.data;
        let n = d.len();

        if n % 2 == 0 {
            (d[(n / 2) - 1] + d[n / 2]) / 2.0
        } else {
            d[(n - 1) / 2]
        }
    }

    /// Closest-ranks percentile computed via linear interpolation.
    /// See: http://www.itl.nist.gov/div898/handbook/prc/section2/prc262.htm
    ///
    /// According to NIST, there isn't a standard computational definition of percentile.
    /// We take a practical approach that aims to be both unsurprising and consistent with
    /// common statistics packages. In particular, our implementation guarantees that the
    /// boundary percentiles correspond to the sample min and max.
    pub fn percentile(&self, p: f64) -> Result<f64, Error> {
        if !p.is_finite() { return Err(Error::Undefined); }
        if p < 0.0 || 1.0 < p {
            return Err(Error::Undefined);
        }

        let rank = (self.size() - 1.0) * p;
        let frac = rank.fract();

        let i = rank.floor() as usize;
        let j = i + 1;

        if j == self.data.len() {
            // This implies that `i` indexes the largest data point in the sample.
            // Dereferencing at `j` would be an error, but `i` is exactly the max.
            return Ok(self.data[i]);
        }

        let xi = self.data[i];
        let xj = self.data[j];
        let x = xi + frac * (xj - xi);

        Ok(x)
    }

    /// Uses Bessel's correction to estimate population variance.
    pub fn unbiased_variance(&self) -> f64 {
        let m = self.mean();
        let sum_sq_diff: f64 = self.data
            .iter()
            .map(|x| (x - m).powi(2))
            .sum();

        (1.0 / (self.size() - 1.0)) * sum_sq_diff
    }

    pub fn standard_deviation(&self) -> f64 {
        self.unbiased_variance().sqrt()
    }

    pub fn standard_error(&self) -> f64 {
        self.standard_deviation() / self.size().sqrt()
    }
}

#[derive(Debug)]
pub struct Summary {
    iqr: f64,
    len: usize,
    lower_quartile: f64,
    min: f64,
    max: f64,
    mean: f64,
    median: f64,
    standard_deviation: f64,
    standard_error: f64,
    unbiased_variance: f64,
    upper_quartile: f64,
}

impl Summary {
    /// Construct a `Summary` from a slice of 64-bit floating point numbers.
    ///
    /// This constructor is partial, and we obtain the following guarantees
    /// about the resulting sample data:
    ///
    ///   - The sample size is positive
    ///   - All values are finite
    ///   - The data are sorted
    ///
    pub fn new(data: &[f64]) -> Result<Self, Error> {
        let s = Summarizer::new(data)?;

        // The percentile arguments below are statically known to meet the
        // `percentile()` bounds, so we can always unwrap.
        let q1 = s.percentile(0.25).unwrap_or_else(|_| unreachable!());
        let q3 = s.percentile(0.75).unwrap_or_else(|_| unreachable!());
        let iqr = q3 - q1;

        Ok(Summary {
            iqr: iqr,
            len: s.data.len(),
            lower_quartile: q1,
            min: s.min(),
            max: s.max(),
            mean: s.mean(),
            median: s.median(),
            upper_quartile: q3,
            unbiased_variance: s.unbiased_variance(),
            standard_deviation: s.standard_deviation(),
            standard_error: s.standard_error(),
        })
    }

    pub fn size(&self) -> f64 {
        self.len as f64
    }

    pub fn range(&self) -> f64 {
        self.max - self.min
    }

    pub fn iqr(&self) -> f64 {
        self.iqr
    }

    pub fn lower_quartile(&self) -> f64 {
        self.lower_quartile
    }

    pub fn min(&self) -> f64 {
        self.min
    }

    pub fn max(&self) -> f64 {
        self.max
    }

    pub fn mean(&self) -> f64 {
        self.mean
    }

    pub fn median(&self) -> f64 {
        self.median
    }

    /// Uses Bessel's correction to estimate population variance.
    pub fn unbiased_variance(&self) -> f64 {
        self.unbiased_variance
    }

    pub fn upper_quartile(&self) -> f64 {
        self.upper_quartile
    }

    pub fn standard_deviation(&self) -> f64 {
        self.standard_deviation
    }

    pub fn standard_error(&self) -> f64 {
        self.standard_error
    }
}
<commit_msg>Add `min`/`max_non_outlier()` methods to `Summary`<commit_after>use error::Error;

#[derive(Debug)]
pub struct Summarizer {
    data: Vec<f64>,
}

impl Summarizer {
    /// Construct a `Summarizer` from a slice of 64-bit floating point numbers.
    ///
    /// This constructor is partial, and we obtain the following guarantees
    /// about the resulting sample data:
    ///
    ///   - The sample size is positive
    ///   - All values are finite
    ///   - The data are sorted
    ///
    pub fn new(data: &[f64]) -> Result<Self, Error> {
        if data.is_empty() {
            return Err(Error::EmptySample);
        }

        if data.iter().any(|x| !x.is_finite()) {
            return Err(Error::BadSample);
        }

        let mut data = Vec::from(data);

        // Won't panic: we have checked that each float is finite.
        data.sort_by(|a, b| a.partial_cmp(b).unwrap_or_else(|| unreachable!()));

        let s = Summarizer { data };

        Ok(s)
    }

    pub fn as_slice(&self) -> &[f64] {
        self.data.as_slice()
    }

    pub fn size(&self) -> f64 {
        self.data.len() as f64
    }

    pub fn min(&self) -> f64 {
        self.data[0]
    }

    pub fn max(&self) -> f64 {
        self.data[self.data.len() - 1]
    }

    pub fn mean(&self) -> f64 {
        let t: f64 = self.data.iter().sum();

        t / self.size()
    }

    pub fn median(&self) -> f64 {
        let d = &self.data;
        let n = d.len();

        if n % 2 == 0 {
            (d[(n / 2) - 1] + d[n / 2]) / 2.0
        } else {
            d[(n - 1) / 2]
        }
    }

    /// Closest-ranks percentile computed via linear interpolation.
    /// See: http://www.itl.nist.gov/div898/handbook/prc/section2/prc262.htm
    ///
    /// According to NIST, there isn't a standard computational definition of percentile.
    /// We take a practical approach that aims to be both unsurprising and consistent with
    /// common statistics packages. In particular, our implementation guarantees that the
    /// boundary percentiles correspond to the sample min and max.
    pub fn percentile(&self, p: f64) -> Result<f64, Error> {
        if !p.is_finite() { return Err(Error::Undefined); }
        if p < 0.0 || 1.0 < p {
            return Err(Error::Undefined);
        }

        let rank = (self.size() - 1.0) * p;
        let frac = rank.fract();

        let i = rank.floor() as usize;
        let j = i + 1;

        if j == self.data.len() {
            // This implies that `i` indexes the largest data point in the sample.
            // Dereferencing at `j` would be an error, but `i` is exactly the max.
            return Ok(self.data[i]);
        }

        let xi = self.data[i];
        let xj = self.data[j];
        let x = xi + frac * (xj - xi);

        Ok(x)
    }

    /// Uses Bessel's correction to estimate population variance.
    pub fn unbiased_variance(&self) -> f64 {
        let m = self.mean();
        let sum_sq_diff: f64 = self.data
            .iter()
            .map(|x| (x - m).powi(2))
            .sum();

        (1.0 / (self.size() - 1.0)) * sum_sq_diff
    }

    pub fn standard_deviation(&self) -> f64 {
        self.unbiased_variance().sqrt()
    }

    pub fn standard_error(&self) -> f64 {
        self.standard_deviation() / self.size().sqrt()
    }
}

#[derive(Debug)]
pub struct Summary {
    iqr: f64,
    len: usize,
    lower_quartile: f64,
    min: f64,
    min_non_outlier: f64,
    max: f64,
    max_non_outlier: f64,
    mean: f64,
    median: f64,
    standard_deviation: f64,
    standard_error: f64,
    unbiased_variance: f64,
    upper_quartile: f64,
}

impl Summary {
    /// Construct a `Summary` from a slice of 64-bit floating point numbers.
    ///
    /// This constructor is partial, and we obtain the following guarantees
    /// about the resulting sample data:
    ///
    ///   - The sample size is positive
    ///   - All values are finite
    ///   - The data are sorted
    ///
    pub fn new(data: &[f64]) -> Result<Self, Error> {
        let s = Summarizer::new(data)?;

        // The percentile arguments below are statically known to meet the
        // `percentile()` bounds, so we can always unwrap.
        let q1 = s.percentile(0.25).unwrap_or_else(|_| unreachable!());
        let q3 = s.percentile(0.75).unwrap_or_else(|_| unreachable!());
        let iqr = q3 - q1;

        let lower_outlier_bound = q1 - 1.5 * iqr;
        let min_non_outlier = s
            .as_slice()
            .iter()
            .cloned()
            .find(|&x| lower_outlier_bound <= x)
            .unwrap_or_else(|| unreachable!());  // By definition of quartile.

        let upper_outlier_bound = q3 + 1.5 * iqr;
        let max_non_outlier = s
            .as_slice()
            .iter()
            .cloned()
            .rev()
            .find(|&x| x <= upper_outlier_bound)
            .unwrap_or_else(|| unreachable!());  // By definition of quartile.

        Ok(Summary {
            iqr: iqr,
            len: s.data.len(),
            lower_quartile: q1,
            min: s.min(),
            min_non_outlier: min_non_outlier,
            max: s.max(),
            max_non_outlier: max_non_outlier,
            mean: s.mean(),
            median: s.median(),
            upper_quartile: q3,
            unbiased_variance: s.unbiased_variance(),
            standard_deviation: s.standard_deviation(),
            standard_error: s.standard_error(),
        })
    }

    pub fn size(&self) -> f64 {
        self.len as f64
    }

    pub fn range(&self) -> f64 {
        self.max - self.min
    }

    pub fn iqr(&self) -> f64 {
        self.iqr
    }

    pub fn lower_quartile(&self) -> f64 {
        self.lower_quartile
    }

    pub fn min(&self) -> f64 {
        self.min
    }

    pub fn min_non_outlier(&self) -> f64 {
        self.min_non_outlier
    }

    pub fn max(&self) -> f64 {
        self.max
    }

    pub fn max_non_outlier(&self) -> f64 {
        self.max_non_outlier
    }

    pub fn mean(&self) -> f64 {
        self.mean
    }

    pub fn median(&self) -> f64 {
        self.median
    }

    /// Uses Bessel's correction to estimate population variance.
    pub fn unbiased_variance(&self) -> f64 {
        self.unbiased_variance
    }

    pub fn upper_quartile(&self) -> f64 {
        self.upper_quartile
    }

    pub fn standard_deviation(&self) -> f64 {
        self.standard_deviation
    }

    pub fn standard_error(&self) -> f64 {
        self.standard_error
    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2017 Stefan Lankes, RWTH Aachen University
//
// 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.

#![allow(dead_code)]

use alloc;
use alloc::rc::Rc;
use core::cell::RefCell;
use core::fmt;
use alloc::alloc::{alloc, dealloc, Layout};
use arch;
use arch::processor::msb;
use arch::{PageSize,BasePageSize};
use logging::*;
use consts::*;

extern {
    fn get_bootstack() -> *mut u8;
}

/// The status of the task - used for scheduling
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum TaskStatus {
	TaskInvalid,
	TaskReady,
	TaskRunning,
	TaskBlocked,
	TaskFinished,
	TaskIdle
}

/// Unique identifier for a task (i.e. `pid`).
#[derive(PartialEq, Eq, PartialOrd, Ord, Debug, Clone, Copy)]
pub struct TaskId(u32);

impl TaskId {
	pub const fn into(self) -> u32 {
		self.0
	}

	pub const fn from(x: u32) -> Self {
		TaskId(x)
	}
}

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

/// Priority of a task
#[derive(PartialEq, Eq, PartialOrd, Ord, Debug, Clone, Copy)]
pub struct TaskPriority(u8);

impl TaskPriority {
	pub const fn into(self) -> u8 {
		self.0
	}

	pub const fn from(x: u8) -> Self {
		TaskPriority(x)
	}
}

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

pub const REALTIME_PRIORITY: TaskPriority = TaskPriority::from(NO_PRIORITIES as u8 - 1);
pub const HIGH_PRIORITY: TaskPriority = TaskPriority::from(24);
pub const NORMAL_PRIORITY: TaskPriority = TaskPriority::from(16);
pub const LOW_PRIORITY: TaskPriority = TaskPriority::from(0);

struct QueueHead {
	head: Option<Rc<RefCell<Task>>>,
	tail: Option<Rc<RefCell<Task>>>,
}

impl QueueHead {
	pub const fn new() -> Self {
		QueueHead {
			head: None,
			tail: None
		}
	}
}

impl Default for QueueHead {
	fn default() -> Self {
		Self { head: None, tail: None }
	}
}

/// Realize a priority queue for tasks
pub struct PriorityTaskQueue {
	queues: [QueueHead; NO_PRIORITIES],
	prio_bitmap: u64
}

impl PriorityTaskQueue {
	/// Creates an empty priority queue for tasks
	pub fn new() -> PriorityTaskQueue {
		PriorityTaskQueue {
			queues: Default::default(),
			prio_bitmap: 0
		}
	}

	/// Add a task by its priority to the queue
	pub fn push(&mut self, task: Rc<RefCell<Task>>) {
		let i = task.borrow().prio.into() as usize;
		//assert!(i < NO_PRIORITIES, "Priority {} is too high", i);

		self.prio_bitmap |= 1 << i;
		match self.queues[i].tail {
			None => {
				// first element in the queue
				self.queues[i].head = Some(task.clone());

				let mut borrow = task.borrow_mut();
					borrow.next = None;
				borrow.prev = None;
			},
			Some(ref mut tail) => {
				// add task at the end of the node
				tail.borrow_mut().next = Some(task.clone());

				let mut borrow = task.borrow_mut();
				borrow.next = None;
				borrow.prev = Some(tail.clone());
			}
		}

		self.queues[i].tail = Some(task.clone());
	}

	fn pop_from_queue(&mut self, queue_index: usize) -> Option<Rc<RefCell<Task>>> {
		let new_head;
		let task;

		match self.queues[queue_index].head {
			None => { return None; },
			Some(ref mut head) => {
				let mut borrow = head.borrow_mut();

				match borrow.next {
					Some(ref mut nhead) => { nhead.borrow_mut().prev = None; },
					None => {}
				}

				new_head = borrow.next.clone();
				borrow.next = None;
				borrow.prev = None;

				task = head.clone();
			}
		}

		self.queues[queue_index].head = new_head;
		if self.queues[queue_index].head.is_none() {
			self.queues[queue_index].tail = None;
			self.prio_bitmap &= !(1 << queue_index as u64);
		}

		Some(task)
	}

	/// Pop the task with the highest priority from the queue
	pub fn pop(&mut self) -> Option<Rc<RefCell<Task>>> {
		if let Some(i) = msb(self.prio_bitmap) {
			return self.pop_from_queue(i as usize);
		}

		None
	}

	/// Pop the next task, which has a higher or the same priority as `prio`
	pub fn pop_with_prio(&mut self, prio: TaskPriority) -> Option<Rc<RefCell<Task>>> {
		if let Some(i) = msb(self.prio_bitmap) {
			if i >= prio.into() as u64 {
				return self.pop_from_queue(i as usize);
			}
		}

		None
	}

	/// Remove a specific task from the priority queue.
	pub fn remove(&mut self, task: Rc<RefCell<Task>>) {
		let i = task.borrow().prio.into() as usize;
		//assert!(i < NO_PRIORITIES, "Priority {} is too high", i);

		let mut curr = self.queues[i].head.clone();
		let mut next_curr;

		loop {
			match curr {
				None => { break; },
				Some(ref curr_task) => {
					if Rc::ptr_eq(&curr_task, &task) {
						let (mut prev, mut next) = {
							let mut borrowed = curr_task.borrow_mut();
							(borrowed.prev.clone(), borrowed.next.clone())
						};

						match prev {
							Some(ref mut t) => { t.borrow_mut().next = next.clone(); },
							None => {}
						};

						match next {
							Some(ref mut t) => { t.borrow_mut().prev = prev.clone(); },
							None => {}
						};

						break;
					}

					next_curr = curr_task.borrow().next.clone();
				}
			}

			curr = next_curr.clone();
		}

		let new_head = match self.queues[i].head {
			Some(ref curr_task) => {
				if Rc::ptr_eq(&curr_task, &task) {
					true
				} else {
					false
				}
			},
			None => { false }
		};

		if new_head == true {
				self.queues[i].head = task.borrow().next.clone();

				if self.queues[i].head.is_none() {
					self.prio_bitmap &= !(1 << i as u64);
				}
		}
	}
}

#[derive(Copy, Clone)]
#[repr(align(64))]
#[repr(C)]
pub struct Stack {
	buffer: [u8; STACK_SIZE]
}

impl Stack {
	pub const fn new() -> Stack {
		Stack {
			buffer: [0; STACK_SIZE]
		}
	}

	pub fn top(&self) -> usize {
		(&(self.buffer[STACK_SIZE - 16]) as *const _) as usize
	}

	pub fn bottom(&self) -> usize {
		(&(self.buffer[0]) as *const _) as usize
	}
}

pub static mut BOOT_STACK: Stack = Stack::new();

/// A task control block, which identifies either a process or a thread
#[repr(align(64))]
pub struct Task {
	/// The ID of this context
	pub id: TaskId,
	/// Task Priority
	pub prio: TaskPriority,
	/// Status of a task, e.g. if the task is ready or blocked
	pub status: TaskStatus,
	/// Last stack pointer before a context switch to another task
	pub last_stack_pointer: usize,
	// Stack of the task
	pub stack: *mut Stack,
	// Physical address of the 1st level page table
	pub root_page_table: usize,
	// next task in queue
	pub next: Option<Rc<RefCell<Task>>>,
	// previous task in queue
	pub prev: Option<Rc<RefCell<Task>>>
}

impl Task {
	pub fn new_idle(id: TaskId) -> Task {
		Task {
			id: id,
			prio: LOW_PRIORITY,
			status: TaskStatus::TaskIdle,
			last_stack_pointer: 0,
			stack: unsafe { &mut BOOT_STACK },
			root_page_table: arch::get_kernel_root_page_table(),
			next: None,
			prev: None
		}
	}

	pub fn new(id: TaskId, status: TaskStatus, prio: TaskPriority) -> Task {
		let stack = unsafe { alloc(Layout::new::<Stack>()) as *mut Stack };

		debug!("Allocate stack for task {} at 0x{:x}", id, stack as usize);

		Task {
			id: id,
			prio: prio,
			status: status,
			last_stack_pointer: 0,
			stack: stack,
			root_page_table: arch::get_kernel_root_page_table(),
			next: None,
			prev: None
		}
	}
}

pub trait TaskFrame {
	/// Create the initial stack frame for a new task
	fn create_stack_frame(&mut self, func: extern fn());
}

impl Drop for Task {
	fn drop(&mut self) {
		if unsafe { self.stack != &mut BOOT_STACK } {
			debug!("Deallocate stack of task {} (stack at 0x{:x})", self.id, self.stack as usize);

			// deallocate stack
			unsafe { dealloc(self.stack as *mut u8, Layout::new::<Stack>()); }
		}

		if self.root_page_table != arch::get_kernel_root_page_table() {
			debug!("Deallocate page table 0x{:x} of task {}", self.root_page_table, self.id);
			arch::mm::physicalmem::deallocate(self.root_page_table, BasePageSize::SIZE);
		}
	}
}
<commit_msg>remove compiler warnings<commit_after>// Copyright (c) 2017 Stefan Lankes, RWTH Aachen University
//
// 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.

#![allow(dead_code)]

use alloc;
use alloc::rc::Rc;
use core::cell::RefCell;
use core::fmt;
use alloc::alloc::{alloc, dealloc, Layout};
use arch;
use arch::processor::msb;
use arch::{PageSize,BasePageSize};
use logging::*;
use consts::*;

extern {
    fn get_bootstack() -> *mut u8;
}

/// The status of the task - used for scheduling
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum TaskStatus {
	TaskInvalid,
	TaskReady,
	TaskRunning,
	TaskBlocked,
	TaskFinished,
	TaskIdle
}

/// Unique identifier for a task (i.e. `pid`).
#[derive(PartialEq, Eq, PartialOrd, Ord, Debug, Clone, Copy)]
pub struct TaskId(u32);

impl TaskId {
	pub const fn into(self) -> u32 {
		self.0
	}

	pub const fn from(x: u32) -> Self {
		TaskId(x)
	}
}

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

/// Priority of a task
#[derive(PartialEq, Eq, PartialOrd, Ord, Debug, Clone, Copy)]
pub struct TaskPriority(u8);

impl TaskPriority {
	pub const fn into(self) -> u8 {
		self.0
	}

	pub const fn from(x: u8) -> Self {
		TaskPriority(x)
	}
}

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

pub const REALTIME_PRIORITY: TaskPriority = TaskPriority::from(NO_PRIORITIES as u8 - 1);
pub const HIGH_PRIORITY: TaskPriority = TaskPriority::from(24);
pub const NORMAL_PRIORITY: TaskPriority = TaskPriority::from(16);
pub const LOW_PRIORITY: TaskPriority = TaskPriority::from(0);

struct QueueHead {
	head: Option<Rc<RefCell<Task>>>,
	tail: Option<Rc<RefCell<Task>>>,
}

impl QueueHead {
	pub const fn new() -> Self {
		QueueHead {
			head: None,
			tail: None
		}
	}
}

impl Default for QueueHead {
	fn default() -> Self {
		Self { head: None, tail: None }
	}
}

/// Realize a priority queue for tasks
pub struct PriorityTaskQueue {
	queues: [QueueHead; NO_PRIORITIES],
	prio_bitmap: u64
}

impl PriorityTaskQueue {
	/// Creates an empty priority queue for tasks
	pub fn new() -> PriorityTaskQueue {
		PriorityTaskQueue {
			queues: Default::default(),
			prio_bitmap: 0
		}
	}

	/// Add a task by its priority to the queue
	pub fn push(&mut self, task: Rc<RefCell<Task>>) {
		let i = task.borrow().prio.into() as usize;
		//assert!(i < NO_PRIORITIES, "Priority {} is too high", i);

		self.prio_bitmap |= 1 << i;
		match self.queues[i].tail {
			None => {
				// first element in the queue
				self.queues[i].head = Some(task.clone());

				let mut borrow = task.borrow_mut();
					borrow.next = None;
				borrow.prev = None;
			},
			Some(ref mut tail) => {
				// add task at the end of the node
				tail.borrow_mut().next = Some(task.clone());

				let mut borrow = task.borrow_mut();
				borrow.next = None;
				borrow.prev = Some(tail.clone());
			}
		}

		self.queues[i].tail = Some(task.clone());
	}

	fn pop_from_queue(&mut self, queue_index: usize) -> Option<Rc<RefCell<Task>>> {
		let new_head;
		let task;

		match self.queues[queue_index].head {
			None => { return None; },
			Some(ref mut head) => {
				let mut borrow = head.borrow_mut();

				match borrow.next {
					Some(ref mut nhead) => { nhead.borrow_mut().prev = None; },
					None => {}
				}

				new_head = borrow.next.clone();
				borrow.next = None;
				borrow.prev = None;

				task = head.clone();
			}
		}

		self.queues[queue_index].head = new_head;
		if self.queues[queue_index].head.is_none() {
			self.queues[queue_index].tail = None;
			self.prio_bitmap &= !(1 << queue_index as u64);
		}

		Some(task)
	}

	/// Pop the task with the highest priority from the queue
	pub fn pop(&mut self) -> Option<Rc<RefCell<Task>>> {
		if let Some(i) = msb(self.prio_bitmap) {
			return self.pop_from_queue(i as usize);
		}

		None
	}

	/// Pop the next task, which has a higher or the same priority as `prio`
	pub fn pop_with_prio(&mut self, prio: TaskPriority) -> Option<Rc<RefCell<Task>>> {
		if let Some(i) = msb(self.prio_bitmap) {
			if i >= prio.into() as u64 {
				return self.pop_from_queue(i as usize);
			}
		}

		None
	}

	/// Remove a specific task from the priority queue.
	pub fn remove(&mut self, task: Rc<RefCell<Task>>) {
		let i = task.borrow().prio.into() as usize;
		//assert!(i < NO_PRIORITIES, "Priority {} is too high", i);

		let mut curr = self.queues[i].head.clone();
		let mut next_curr;

		loop {
			match curr {
				None => { break; },
				Some(ref curr_task) => {
					if Rc::ptr_eq(&curr_task, &task) {
						let (mut prev, mut next) = {
							let borrowed = curr_task.borrow_mut();
							(borrowed.prev.clone(), borrowed.next.clone())
						};

						match prev {
							Some(ref mut t) => { t.borrow_mut().next = next.clone(); },
							None => {}
						};

						match next {
							Some(ref mut t) => { t.borrow_mut().prev = prev.clone(); },
							None => {}
						};

						break;
					}

					next_curr = curr_task.borrow().next.clone();
				}
			}

			curr = next_curr.clone();
		}

		let new_head = match self.queues[i].head {
			Some(ref curr_task) => {
				if Rc::ptr_eq(&curr_task, &task) {
					true
				} else {
					false
				}
			},
			None => { false }
		};

		if new_head == true {
				self.queues[i].head = task.borrow().next.clone();

				if self.queues[i].head.is_none() {
					self.prio_bitmap &= !(1 << i as u64);
				}
		}
	}
}

#[derive(Copy, Clone)]
#[repr(align(64))]
#[repr(C)]
pub struct Stack {
	buffer: [u8; STACK_SIZE]
}

impl Stack {
	pub const fn new() -> Stack {
		Stack {
			buffer: [0; STACK_SIZE]
		}
	}

	pub fn top(&self) -> usize {
		(&(self.buffer[STACK_SIZE - 16]) as *const _) as usize
	}

	pub fn bottom(&self) -> usize {
		(&(self.buffer[0]) as *const _) as usize
	}
}

pub static mut BOOT_STACK: Stack = Stack::new();

/// A task control block, which identifies either a process or a thread
#[repr(align(64))]
pub struct Task {
	/// The ID of this context
	pub id: TaskId,
	/// Task Priority
	pub prio: TaskPriority,
	/// Status of a task, e.g. if the task is ready or blocked
	pub status: TaskStatus,
	/// Last stack pointer before a context switch to another task
	pub last_stack_pointer: usize,
	// Stack of the task
	pub stack: *mut Stack,
	// Physical address of the 1st level page table
	pub root_page_table: usize,
	// next task in queue
	pub next: Option<Rc<RefCell<Task>>>,
	// previous task in queue
	pub prev: Option<Rc<RefCell<Task>>>
}

impl Task {
	pub fn new_idle(id: TaskId) -> Task {
		Task {
			id: id,
			prio: LOW_PRIORITY,
			status: TaskStatus::TaskIdle,
			last_stack_pointer: 0,
			stack: unsafe { &mut BOOT_STACK },
			root_page_table: arch::get_kernel_root_page_table(),
			next: None,
			prev: None
		}
	}

	pub fn new(id: TaskId, status: TaskStatus, prio: TaskPriority) -> Task {
		let stack = unsafe { alloc(Layout::new::<Stack>()) as *mut Stack };

		debug!("Allocate stack for task {} at 0x{:x}", id, stack as usize);

		Task {
			id: id,
			prio: prio,
			status: status,
			last_stack_pointer: 0,
			stack: stack,
			root_page_table: arch::get_kernel_root_page_table(),
			next: None,
			prev: None
		}
	}
}

pub trait TaskFrame {
	/// Create the initial stack frame for a new task
	fn create_stack_frame(&mut self, func: extern fn());
}

impl Drop for Task {
	fn drop(&mut self) {
		if unsafe { self.stack != &mut BOOT_STACK } {
			debug!("Deallocate stack of task {} (stack at 0x{:x})", self.id, self.stack as usize);

			// deallocate stack
			unsafe { dealloc(self.stack as *mut u8, Layout::new::<Stack>()); }
		}

		if self.root_page_table != arch::get_kernel_root_page_table() {
			debug!("Deallocate page table 0x{:x} of task {}", self.root_page_table, self.id);
			arch::mm::physicalmem::deallocate(self.root_page_table, BasePageSize::SIZE);
		}
	}
}
<|endoftext|>


<commit_before>use std::error::Error;
use chrono::{Duration, NaiveDate};

/// Transit trait defines methods for iterating over components of a Transit
/// system
pub trait Transit<'a, E: Error> {
    type AgencyIterator: Iterator<Item=Result<Agency, E>>;

    fn agencies(&'a self) -> Self::AgencyIterator;
}

/// Agency
pub struct Agency {
    pub agency_id: Option<String>,
    pub agency_name: String,
    pub agency_url: String,
    pub agency_timezone: String,
    pub agency_lang: Option<String>,
    pub agency_phone: Option<String>,
    pub agency_fare_url: Option<String>,
    pub agency_email: Option<String>,
}

/// Calendar
pub struct Calendar {
    pub service_id: String,
    pub monday: bool,
    pub tuesday: bool,
    pub wednesday: bool,
    pub thursday: bool,
    pub friday: bool,
    pub saturday: bool,
    pub sunday: bool,
    pub start_date: NaiveDate,
    pub end_date: NaiveDate,
}

/// ExceptionType for `CalendarDate`
pub enum ExceptionType {
    ServiceAdded,
    ServiceRemoved,
}

/// CalendarDate
pub struct CalendarDate {
    pub service_id: String,
    pub date: NaiveDate,
    pub exception_type: ExceptionType
}

/// Location Type
pub enum LocationType {
    Stop,
    Station,
}

/// Wheelchair Boarding
pub enum WheelchairBoarding {
    NoInformation,
    SomeAccessibility,
    NoAccessibility,
}

/// Stop
pub struct Stop {
    pub stop_id: String,
    pub stop_code: Option<String>,
    pub stop_name: String,
    pub stop_desc: Option<String>,
    pub stop_lat: f64,
    pub stop_lon: f64,
    pub zone_id: Option<String>,
    pub stop_url: Option<String>,
    pub location_type: LocationType,
    pub parent_station: Option<String>,
    pub stop_timezone: Option<String>,
    pub wheelchair_boarding: WheelchairBoarding,
}

/// RouteType
pub enum RouteType {
    LightRail,
    Subway,
    Rail,
    Bus,
    Ferry,
    CableCar,
    Gondola,
    Funicular,
}

/// Route
pub struct Route {
    pub route_id: String,
    pub agency_id: Option<String>,
    pub route_short_name: String,
    pub route_long_name: String,
    pub route_desc: Option<String>,
    pub route_type: RouteType,
    pub route_url: Option<String>,
    pub route_color: Option<String>,
    pub route_text_color: Option<String>,
}

/// Wheelchair Accessible
pub enum WheelchairAccessible {
    NoInformation,
    SomeAccessibility,
    NoAccessibility,
}

/// Bikes Allowed
pub enum BikesAllowed {
    NoInformation,
    SomeBikes,
    NoBikes,
}

/// Trip
pub struct Trip {
    pub route_id: String,
    pub service_id: String,
    pub trip_id: String,
    pub trip_headsign: Option<String>,
    pub trip_short_name: Option<String>,
    pub direction_id: Option<String>,
    pub block_id: Option<String>,
    pub shape_id: Option<String>,
    pub wheelchair_accessible: WheelchairAccessible,
    pub bikes_allowed: BikesAllowed,
}

/// exact_times for Frequency
pub enum FrequencyAccuracy {
    Approximate,
    Exact
}

/// Frequency
pub struct Frequency {
    pub trip_id: String,
    pub start_time: TimeOffset,
    pub end_time: TimeOffset,
    pub headway_secs: u64,
    pub exact_times: FrequencyAccuracy,
}

/// PickupType for `StopTime`
#[derive(Debug)]
pub enum PickupType {
    RegularlyScheduled,
    NoPickupAvailable,
    MustPhoneAgency,
    MustCoordinateWithDriver,
}

/// DropoffType for `StopTime`
#[derive(Debug)]
pub enum DropoffType {
    RegularlyScheduled,
    NoDropoffAvailable,
    MustPhoneAgency,
    MustCoordinateWithDriver,
}

/// Timepoint for `StopTime`
#[derive(Debug)]
pub enum Timepoint {
    Approximate,
    Exact,
}

#[derive(Debug, PartialEq, Eq)]
pub struct TimeOffset {
    pub hours: u32,
    pub minutes: u32,
    pub seconds: u32,
}

impl TimeOffset {
    pub fn from_hms(hours: u32, minutes: u32, seconds: u32) -> TimeOffset {
        TimeOffset {
            hours: hours,
            minutes: minutes,
            seconds: seconds,
        }
    }

    pub fn duration(&self) -> Duration {
        Duration::hours(self.hours as i64)
            + Duration::minutes(self.minutes as i64)
            + Duration::seconds(self.seconds as i64)
    }
}

/// StopTime
#[derive(Debug)]
pub struct StopTime {
    pub trip_id: String,
    pub arrival_time: TimeOffset,
    pub departure_time: TimeOffset,
    pub stop_id: String,
    pub stop_sequence: u64,
    pub stop_headsign: Option<String>,
    pub pickup_type: PickupType,
    pub dropoff_type: DropoffType,
    pub shape_dist_traveled: Option<f64>,
    pub timepoint: Timepoint,
}

/// PaymentMethod for `FareAttribute`
pub enum PaymentMethod {
    PaidOnboard,
    PaidBefore,
}

/// Tranfers for `FareAttribute`
pub enum Transfers {
    None,
    TransferOnce,
    TransferTwice,
    Unlimited,
}

/// FareAttribute
pub struct FareAttribute {
    pub fare_id: String,
    pub price: f64,
    pub currency_type: String,
    pub payment_method: PaymentMethod,
    pub transfers: Transfers,
    pub transfer_duration: Duration,
}

/// FareRule
/// origin, destination, and contains reference a zone_id from stops
pub struct FareRule {
    pub fare_id: String,
    pub route_id: Option<String>,
    pub origin_id: Option<String>,
    pub destination_id: Option<String>,
    pub contains_id: Option<String>,
}

/// Shape
pub struct Shape {
    pub shape_id: String,
    pub shape_pt_lat: f64,
    pub shape_pt_lon: f64,
    pub shape_pt_sequence: u64,
    pub shape_dist_traveled: f64,
}
<commit_msg>Reorder transit structs (by order in reference), impl Debug<commit_after>use std::error::Error;
use chrono::{Duration, NaiveDate};

/// Transit trait defines methods for iterating over components of a Transit
/// system
pub trait Transit<'a, E: Error> {
    type AgencyIterator: Iterator<Item=Result<Agency, E>>;

    fn agencies(&'a self) -> Self::AgencyIterator;
}

/// Agency
#[derive(Debug)]
pub struct Agency {
    pub agency_id: Option<String>,
    pub agency_name: String,
    pub agency_url: String,
    pub agency_timezone: String,
    pub agency_lang: Option<String>,
    pub agency_phone: Option<String>,
    pub agency_fare_url: Option<String>,
    pub agency_email: Option<String>,
}

/// Calendar
#[derive(Debug)]
pub struct Calendar {
    pub service_id: String,
    pub monday: bool,
    pub tuesday: bool,
    pub wednesday: bool,
    pub thursday: bool,
    pub friday: bool,
    pub saturday: bool,
    pub sunday: bool,
    pub start_date: NaiveDate,
    pub end_date: NaiveDate,
}

/// ExceptionType for `CalendarDate`
#[derive(Debug)]
pub enum ExceptionType {
    ServiceAdded,
    ServiceRemoved,
}

/// CalendarDate
#[derive(Debug)]
pub struct CalendarDate {
    pub service_id: String,
    pub date: NaiveDate,
    pub exception_type: ExceptionType
}

/// PaymentMethod for `FareAttribute`
#[derive(Debug)]
pub enum PaymentMethod {
    PaidOnboard,
    PaidBefore,
}

/// Tranfers for `FareAttribute`
#[derive(Debug)]
pub enum Transfers {
    None,
    TransferOnce,
    TransferTwice,
    Unlimited,
}

/// FareAttribute
#[derive(Debug)]
pub struct FareAttribute {
    pub fare_id: String,
    pub price: f64,
    pub currency_type: String,
    pub payment_method: PaymentMethod,
    pub transfers: Transfers,
    pub transfer_duration: Duration,
}

/// FareRule
/// origin, destination, and contains reference a zone_id from stops
#[derive(Debug)]
pub struct FareRule {
    pub fare_id: String,
    pub route_id: Option<String>,
    pub origin_id: Option<String>,
    pub destination_id: Option<String>,
    pub contains_id: Option<String>,
}

#[derive(Debug, PartialEq, Eq)]
pub struct TimeOffset {
    pub hours: u32,
    pub minutes: u32,
    pub seconds: u32,
}

impl TimeOffset {
    pub fn from_hms(hours: u32, minutes: u32, seconds: u32) -> TimeOffset {
        TimeOffset {
            hours: hours,
            minutes: minutes,
            seconds: seconds,
        }
    }

    pub fn duration(&self) -> Duration {
        Duration::hours(self.hours as i64)
            + Duration::minutes(self.minutes as i64)
            + Duration::seconds(self.seconds as i64)
    }
}

/// exact_times for Frequency
#[derive(Debug)]
pub enum FrequencyAccuracy {
    Approximate,
    Exact
}

/// Frequency
#[derive(Debug)]
pub struct Frequency {
    pub trip_id: String,
    pub start_time: TimeOffset,
    pub end_time: TimeOffset,
    pub headway_secs: u64,
    pub exact_times: FrequencyAccuracy,
}

/// RouteType
#[derive(Debug)]
pub enum RouteType {
    LightRail,
    Subway,
    Rail,
    Bus,
    Ferry,
    CableCar,
    Gondola,
    Funicular,
}

/// Route
#[derive(Debug)]
pub struct Route {
    pub route_id: String,
    pub agency_id: Option<String>,
    pub route_short_name: String,
    pub route_long_name: String,
    pub route_desc: Option<String>,
    pub route_type: RouteType,
    pub route_url: Option<String>,
    pub route_color: Option<String>,
    pub route_text_color: Option<String>,
}

/// Shape
#[derive(Debug)]
pub struct Shape {
    pub shape_id: String,
    pub shape_pt_lat: f64,
    pub shape_pt_lon: f64,
    pub shape_pt_sequence: u64,
    pub shape_dist_traveled: f64,
}

/// Location Type
#[derive(Debug)]
pub enum LocationType {
    Stop,
    Station,
}

/// Wheelchair Boarding
#[derive(Debug)]
pub enum WheelchairBoarding {
    NoInformation,
    SomeAccessibility,
    NoAccessibility,
}

/// Stop
#[derive(Debug)]
pub struct Stop {
    pub stop_id: String,
    pub stop_code: Option<String>,
    pub stop_name: String,
    pub stop_desc: Option<String>,
    pub stop_lat: f64,
    pub stop_lon: f64,
    pub zone_id: Option<String>,
    pub stop_url: Option<String>,
    pub location_type: LocationType,
    pub parent_station: Option<String>,
    pub stop_timezone: Option<String>,
    pub wheelchair_boarding: WheelchairBoarding,
}

/// PickupType for `StopTime`
#[derive(Debug)]
pub enum PickupType {
    RegularlyScheduled,
    NoPickupAvailable,
    MustPhoneAgency,
    MustCoordinateWithDriver,
}

/// DropoffType for `StopTime`
#[derive(Debug)]
pub enum DropoffType {
    RegularlyScheduled,
    NoDropoffAvailable,
    MustPhoneAgency,
    MustCoordinateWithDriver,
}

/// Timepoint for `StopTime`
#[derive(Debug)]
pub enum Timepoint {
    Approximate,
    Exact,
}

/// StopTime
#[derive(Debug)]
pub struct StopTime {
    pub trip_id: String,
    pub arrival_time: TimeOffset,
    pub departure_time: TimeOffset,
    pub stop_id: String,
    pub stop_sequence: u64,
    pub stop_headsign: Option<String>,
    pub pickup_type: PickupType,
    pub dropoff_type: DropoffType,
    pub shape_dist_traveled: Option<f64>,
    pub timepoint: Timepoint,
}

/// Wheelchair Accessible
#[derive(Debug)]
pub enum WheelchairAccessible {
    NoInformation,
    SomeAccessibility,
    NoAccessibility,
}

/// Bikes Allowed
#[derive(Debug)]
pub enum BikesAllowed {
    NoInformation,
    SomeBikes,
    NoBikes,
}

/// Trip
#[derive(Debug)]
pub struct Trip {
    pub route_id: String,
    pub service_id: String,
    pub trip_id: String,
    pub trip_headsign: Option<String>,
    pub trip_short_name: Option<String>,
    pub direction_id: Option<String>,
    pub block_id: Option<String>,
    pub shape_id: Option<String>,
    pub wheelchair_accessible: WheelchairAccessible,
    pub bikes_allowed: BikesAllowed,
}
<|endoftext|>


<commit_before>/// Defines a wrapper type and implements the appropriate traits.
///
/// The basic syntax is
///
/// ```ignore
/// glib_wrapper! {
///     /// Documentation
///     pub struct $name($kind<$foreign>);
///
///     match fn {
///         $fn_name => /* a closure-like expression */,
///         ...
///     }
/// }
/// ```
///
/// This creates a wrapper named `$name` around the foreign type `$foreign`
/// of $kind (one of `Boxed`, `Shared`, `Object`) using expressions from the `match fn`
/// block to implement type-specific low-level operations. The expression
/// will be evaluated in `unsafe` context.
///
/// ### Boxed
///
/// Boxed records with single ownership.
///
/// ```ignore
/// glib_wrapper! {
///     /// Text buffer iterator
///     pub struct TextIter(Boxed<ffi::GtkTextIter>);
///
///     match fn {
///         copy => |ptr| ffi::gtk_text_iter_copy(ptr),
///         free => |ptr| ffi::gtk_text_iter_free(ptr),
///     }
/// }
/// ```
///
/// `copy`: `|*const $foreign| -> *mut $foreign` creates a copy of the value.
///
/// `free`: `|*mut $foreign|` frees the value.
///
/// ### Shared
///
/// Records with reference counted shared ownership.
///
/// ```ignore
/// glib_wrapper! {
///     /// Object holding timing information for a single frame.
///     pub struct FrameTimings(Shared<ffi::GdkFrameTimings>);
///
///     match fn {
///         ref => |ptr| ffi::gdk_frame_timings_ref(ptr),
///         unref => |ptr| ffi::gdk_frame_timings_unref(ptr),
///     }
/// }
/// ```
///
/// `ref`: `|*mut $foreign|` increases the refcount.
///
/// `unref`: `|*mut $foreign|` decreases the refcount.
///
/// ### Object
///
/// Objects -- classes and interfaces.
///
/// ```
/// glib_wrapper! {
///     /// Object representing an input device.
///     pub struct Device(Object<ffi::GdkDevice>);
///
///     match fn {
///         get_type => || ffi::gdk_device_get_type(),
///     }
/// }
/// ```
///
/// ```
/// glib_wrapper! {
///     /// A container with just one child.
///     pub struct Bin(Object<ffi::GtkBin>): Container, Widget, Buildable;
///
///     match fn {
///         get_type => || ffi::gtk_bin_get_type(),
///     }
/// }
/// ```
///
/// `get_type: || -> GType` returns the type identifier of the class or interface.
#[macro_export]
macro_rules! glib_wrapper {
    (
        $(#[$attr:meta])*
        pub struct $name:ident(Boxed<$ffi_name:path>);

        match fn {
            copy => |$copy_arg:ident| $copy_expr:expr,
            free => |$free_arg:ident| $free_expr:expr,
        }
    ) => {
        glib_boxed_wrapper!([$($attr)*] $name, $ffi_name, @copy $copy_arg $copy_expr,
            @free $free_arg $free_expr);
    };

    // Same as Shared, to be removed
    (
        $(#[$attr:meta])*
        pub struct $name:ident(Refcounted<$ffi_name:path>);

        match fn {
            ref => |$ref_arg:ident| $ref_expr:expr,
            unref => |$unref_arg:ident| $unref_expr:expr,
        }
    ) => {
        glib_shared_wrapper!([$($attr)*] $name, $ffi_name, @ref $ref_arg $ref_expr,
            @unref $unref_arg $unref_expr);
    };

    (
        $(#[$attr:meta])*
        pub struct $name:ident(Shared<$ffi_name:path>);

        match fn {
            ref => |$ref_arg:ident| $ref_expr:expr,
            unref => |$unref_arg:ident| $unref_expr:expr,
        }
    ) => {
        glib_shared_wrapper!([$($attr)*] $name, $ffi_name, @ref $ref_arg $ref_expr,
            @unref $unref_arg $unref_expr);
    };

    (
        $(#[$attr:meta])*
        pub struct $name:ident(Object<$ffi_name:path>);

        match fn {
            get_type => || $get_type_expr:expr,
        }
    ) => {
        glib_object_wrapper!([$($attr)*] $name, $ffi_name, @get_type $get_type_expr, []);
    };

    (
        $(#[$attr:meta])*
        pub struct $name:ident(Object<$ffi_name:path>): $($implements:path),+;

        match fn {
            get_type => || $get_type_expr:expr,
        }
    ) => {
        glib_object_wrapper!([$($attr)*] $name, $ffi_name, @get_type $get_type_expr,
            [$($implements),+]);
    };
}

/// A wrapper struct.
pub trait Wrapper {
    /// Foreign type represented by the struct.
    type GlibType: 'static;
}

pub trait UnsafeFrom<T> {
    unsafe fn from(t: T) -> Self;
}
<commit_msg>Ignore glib_wrapper examples<commit_after>/// Defines a wrapper type and implements the appropriate traits.
///
/// The basic syntax is
///
/// ```ignore
/// glib_wrapper! {
///     /// Documentation
///     pub struct $name($kind<$foreign>);
///
///     match fn {
///         $fn_name => /* a closure-like expression */,
///         ...
///     }
/// }
/// ```
///
/// This creates a wrapper named `$name` around the foreign type `$foreign`
/// of $kind (one of `Boxed`, `Shared`, `Object`) using expressions from the `match fn`
/// block to implement type-specific low-level operations. The expression
/// will be evaluated in `unsafe` context.
///
/// ### Boxed
///
/// Boxed records with single ownership.
///
/// ```ignore
/// glib_wrapper! {
///     /// Text buffer iterator
///     pub struct TextIter(Boxed<ffi::GtkTextIter>);
///
///     match fn {
///         copy => |ptr| ffi::gtk_text_iter_copy(ptr),
///         free => |ptr| ffi::gtk_text_iter_free(ptr),
///     }
/// }
/// ```
///
/// `copy`: `|*const $foreign| -> *mut $foreign` creates a copy of the value.
///
/// `free`: `|*mut $foreign|` frees the value.
///
/// ### Shared
///
/// Records with reference counted shared ownership.
///
/// ```ignore
/// glib_wrapper! {
///     /// Object holding timing information for a single frame.
///     pub struct FrameTimings(Shared<ffi::GdkFrameTimings>);
///
///     match fn {
///         ref => |ptr| ffi::gdk_frame_timings_ref(ptr),
///         unref => |ptr| ffi::gdk_frame_timings_unref(ptr),
///     }
/// }
/// ```
///
/// `ref`: `|*mut $foreign|` increases the refcount.
///
/// `unref`: `|*mut $foreign|` decreases the refcount.
///
/// ### Object
///
/// Objects -- classes and interfaces.
///
/// ```ignore
/// glib_wrapper! {
///     /// Object representing an input device.
///     pub struct Device(Object<ffi::GdkDevice>);
///
///     match fn {
///         get_type => || ffi::gdk_device_get_type(),
///     }
/// }
/// ```
///
/// ```ignore
/// glib_wrapper! {
///     /// A container with just one child.
///     pub struct Bin(Object<ffi::GtkBin>): Container, Widget, Buildable;
///
///     match fn {
///         get_type => || ffi::gtk_bin_get_type(),
///     }
/// }
/// ```
///
/// `get_type: || -> GType` returns the type identifier of the class or interface.
#[macro_export]
macro_rules! glib_wrapper {
    (
        $(#[$attr:meta])*
        pub struct $name:ident(Boxed<$ffi_name:path>);

        match fn {
            copy => |$copy_arg:ident| $copy_expr:expr,
            free => |$free_arg:ident| $free_expr:expr,
        }
    ) => {
        glib_boxed_wrapper!([$($attr)*] $name, $ffi_name, @copy $copy_arg $copy_expr,
            @free $free_arg $free_expr);
    };

    // Same as Shared, to be removed
    (
        $(#[$attr:meta])*
        pub struct $name:ident(Refcounted<$ffi_name:path>);

        match fn {
            ref => |$ref_arg:ident| $ref_expr:expr,
            unref => |$unref_arg:ident| $unref_expr:expr,
        }
    ) => {
        glib_shared_wrapper!([$($attr)*] $name, $ffi_name, @ref $ref_arg $ref_expr,
            @unref $unref_arg $unref_expr);
    };

    (
        $(#[$attr:meta])*
        pub struct $name:ident(Shared<$ffi_name:path>);

        match fn {
            ref => |$ref_arg:ident| $ref_expr:expr,
            unref => |$unref_arg:ident| $unref_expr:expr,
        }
    ) => {
        glib_shared_wrapper!([$($attr)*] $name, $ffi_name, @ref $ref_arg $ref_expr,
            @unref $unref_arg $unref_expr);
    };

    (
        $(#[$attr:meta])*
        pub struct $name:ident(Object<$ffi_name:path>);

        match fn {
            get_type => || $get_type_expr:expr,
        }
    ) => {
        glib_object_wrapper!([$($attr)*] $name, $ffi_name, @get_type $get_type_expr, []);
    };

    (
        $(#[$attr:meta])*
        pub struct $name:ident(Object<$ffi_name:path>): $($implements:path),+;

        match fn {
            get_type => || $get_type_expr:expr,
        }
    ) => {
        glib_object_wrapper!([$($attr)*] $name, $ffi_name, @get_type $get_type_expr,
            [$($implements),+]);
    };
}

/// A wrapper struct.
pub trait Wrapper {
    /// Foreign type represented by the struct.
    type GlibType: 'static;
}

pub trait UnsafeFrom<T> {
    unsafe fn from(t: T) -> Self;
}
<|endoftext|>