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

/// See the documentation at https://github.com/pagekite/libpagekite/blob/master/doc/API.md

use ffi::*;
use std::ffi::{CStr, CString};
use std::mem::transmute;
use std::{convert, ptr};
use std::time::Duration;
#[derive(Clone, Copy)]
pub enum InitFlags {
    WithDefaults = 0x8000,
    WithoutDefaults = 0x4000,
    WithSsl = 0x0001,
    WithIpv4 = 0x0002,
    WithIpv6 = 0x0004,
    WithServiceFrontends = 0x0008,
    WithoutServiceFrontends = 0x0010,
    WithDynamicFeList = 0x0020,
    WithFrontendSni = 0x0040,
    AsFrontendRelay = 0x0100,
    WithSyslog = 0x0200,
}

#[derive(Clone, Copy)]
pub enum VerbosityFlags {
    LogTunnelData = 0x000100,
    LogTunnelHeaders = 0x000200,
    LogTunnelConns = 0x000400,
    LogBeData = 0x001000,
    LogBeHeaders = 0x002000,
    LogBeConns = 0x004000,
    LogManagerError = 0x010000,
    LogManagerInfo = 0x020000,
    LogManagerDebug = 0x040000,
    LogTrace = 0x080000,
    LogLuaDebug = 0x008000,
    LogLuaInfo = 0x000800,
    LogError = 0x100000,
}

#[repr(i32)]
pub enum Status {
    Startup = 10,
    Connecting = 20,
    UpdatingDns = 30,
    Flying = 40,
    PROProblems = 50,
    Rejected = 60,
    NoNetwork = 90,
}

impl convert::Into<Status> for i32 {
    fn into(self) -> Status {
        unsafe { transmute::<i32, Status>(self) }
    }
}

pub static LOG_ERRORS: [VerbosityFlags; 2] = [VerbosityFlags::LogError,
                                              VerbosityFlags::LogManagerError];
pub static LOG_MANAGER: [VerbosityFlags; 2] = [VerbosityFlags::LogManagerError,
                                               VerbosityFlags::LogManagerInfo];
pub static LOG_CONNS: [VerbosityFlags; 2] = [VerbosityFlags::LogBeConns,
                                             VerbosityFlags::LogTunnelConns];
pub static LOG_NORMAL: [VerbosityFlags; 7] = [VerbosityFlags::LogError,
                                              VerbosityFlags::LogManagerError,
                                              VerbosityFlags::LogBeConns,
                                              VerbosityFlags::LogTunnelConns,
                                              VerbosityFlags::LogManagerError,
                                              VerbosityFlags::LogManagerInfo,
                                              VerbosityFlags::LogLuaInfo];
pub static LOG_ALL: [VerbosityFlags; 13] = [VerbosityFlags::LogTunnelData,
                                            VerbosityFlags::LogTunnelHeaders,
                                            VerbosityFlags::LogTunnelConns,
                                            VerbosityFlags::LogBeData,
                                            VerbosityFlags::LogBeHeaders,
                                            VerbosityFlags::LogBeConns,
                                            VerbosityFlags::LogManagerError,
                                            VerbosityFlags::LogManagerInfo,
                                            VerbosityFlags::LogManagerDebug,
                                            VerbosityFlags::LogTrace,
                                            VerbosityFlags::LogLuaDebug,
                                            VerbosityFlags::LogLuaInfo,
                                            VerbosityFlags::LogError];

#[derive(Clone)]
pub struct PageKite {
    inner: pagekite_mgr,
}

macro_rules! str_cstring(
    ($a:ident) => ( CString::new($a).unwrap().as_ptr() )
);

macro_rules! build_flag(
    ($flag:ident, $array:ident) => (
        let mut $flag = 0;
        for item in $array {
            $flag |= *item as i32;
        }
    )
);

#[inline]
fn bool2int(val: bool) -> i32 {
    if val { 1 } else { 0 }
}

impl PageKite {
    pub fn init(app_id: Option<&str>,
                max_kites: i32,
                max_frontends: i32,
                max_conns: i32,
                dyndns_url: Option<&str>,
                flags: &[InitFlags],
                verbosity: &[VerbosityFlags])
                -> Option<Self> {

        build_flag!(c_flags, flags);
        build_flag!(c_verbosity, verbosity);

        let c_app_id = match app_id {
            Some(value) => str_cstring!(value),
            None => ptr::null(),
        };

        let c_dyndns_url = match dyndns_url {
            Some(value) => str_cstring!(value),
            None => ptr::null(),
        };

        let raw = unsafe {
            pagekite_init(c_app_id,
                          max_kites,
                          max_frontends,
                          max_conns,
                          c_dyndns_url,
                          c_flags,
                          c_verbosity)
        };
        if raw.is_null() {
            return None;
        }
        Some(PageKite { inner: raw })
    }

    pub fn init_pagekitenet(app_id: Option<&str>,
                            max_kites: i32,
                            max_conns: i32,
                            flags: &[InitFlags],
                            verbosity: &[VerbosityFlags])
                            -> Option<Self> {

        build_flag!(c_flags, flags);
        build_flag!(c_verbosity, verbosity);

        let c_app_id = match app_id {
            Some(value) => str_cstring!(value),
            None => ptr::null(),
        };

        let raw = unsafe {
            pagekite_init_pagekitenet(c_app_id, max_kites, max_conns, c_flags, c_verbosity)
        };
        if raw.is_null() {
            return None;
        }
        Some(PageKite { inner: raw })
    }

    pub fn init_whitelabel(app_id: Option<&str>,
                           max_kites: i32,
                           max_conns: i32,
                           flags: &[InitFlags],
                           verbosity: &[VerbosityFlags],
                           whitelabel_tld: Option<&str>)
                           -> Option<Self> {

        build_flag!(c_flags, flags);
        build_flag!(c_verbosity, verbosity);

        let c_app_id = match app_id {
            Some(value) => str_cstring!(value),
            None => ptr::null(),
        };

        let c_tld = match whitelabel_tld {
            Some(value) => str_cstring!(value),
            None => ptr::null(),
        };

        let raw = unsafe {
            pagekite_init_whitelabel(c_app_id, max_kites, max_conns, c_flags, c_verbosity, c_tld)
        };
        if raw.is_null() {
            return None;
        }
        Some(PageKite { inner: raw })
    }

    pub fn add_kite(&self,
                    proto: &str,
                    kitename: &str,
                    public_port: i32,
                    secret: &str,
                    backend: &str,
                    local_port: i32)
                    -> bool {

        return unsafe {
                   pagekite_add_kite(self.inner,
                                     str_cstring!(proto),
                                     str_cstring!(kitename),
                                     public_port,
                                     str_cstring!(secret),
                                     str_cstring!(backend),
                                     local_port)
               } == 0;
    }

    /// Useful flags are WithDefaults, WithIpv4, WithIpv6, WithDynamicFeList
    /// Returns the number of frontend ips, or an empty error.
    pub fn add_service_frontends(&self, flags: &[InitFlags]) -> Result<usize, ()> {
        build_flag!(c_flags, flags);
        let ret = unsafe { pagekite_add_service_frontends(self.inner, c_flags) };
        if ret == -1 { Err(()) } else { Ok(ret as usize) }
    }

    pub fn add_whitelabel_frontends(&self,
                                    flags: &[InitFlags],
                                    whitelabel_tld: Option<&str>)
                                    -> Result<usize, ()> {
        build_flag!(c_flags, flags);
        let c_tld = match whitelabel_tld {
            Some(value) => str_cstring!(value),
            None => ptr::null(),
        };
        let ret = unsafe { pagekite_add_whitelabel_frontends(self.inner, c_flags, c_tld) };
        if ret == -1 { Err(()) } else { Ok(ret as usize) }
    }

    pub fn lookup_and_add_frontend(&self,
                                   domain: &str,
                                   port: i32,
                                   update_from_dns: bool)
                                   -> Option<i32> {
        let count = unsafe {
            pagekite_lookup_and_add_frontend(self.inner,
                                             str_cstring!(domain),
                                             port,
                                             if update_from_dns { 1 } else { 0 })
        };
        if count == -1 { None } else { Some(count) }
    }

    pub fn add_frontend(&self, domain: &str, port: i32) -> Option<i32> {
        let count = unsafe { pagekite_add_frontend(self.inner, str_cstring!(domain), port) };
        if count == -1 { None } else { Some(count) }
    }

    pub fn set_log_mask(&self, flags: &[VerbosityFlags]) {
        build_flag!(c_verbosity, flags);
        unsafe {
            pagekite_set_log_mask(self.inner, c_verbosity);
        }
    }

    pub fn set_housekeeping_min_interval(&self, interval: Duration) -> Duration {
        let ret = unsafe {
            pagekite_set_housekeeping_min_interval(self.inner, interval.as_secs() as i32)
        };
        Duration::new(ret as u64, 0)
    }

    pub fn set_housekeeping_max_interval(&self, interval: Duration) -> Duration {
        let ret = unsafe {
            pagekite_set_housekeeping_max_interval(self.inner, interval.as_secs() as i32)
        };
        Duration::new(ret as u64, 0)
    }

    pub fn enable_http_forwarding_headers(&self, enable: bool) -> &Self {
        unsafe {
            pagekite_enable_http_forwarding_headers(self.inner, bool2int(enable));
        }
        self
    }

    pub fn enable_fake_ping(&self, enable: bool) -> &Self {
        unsafe {
            pagekite_enable_fake_ping(self.inner, bool2int(enable));
        }
        self
    }

    pub fn enable_watchdog(&self, enable: bool) -> &Self {
        unsafe {
            pagekite_enable_watchdog(self.inner, bool2int(enable));
        }
        self
    }

    pub fn enable_tick_timer(&self, enable: bool) -> &Self {
        unsafe {
            pagekite_enable_tick_timer(self.inner, bool2int(enable));
        }
        self
    }

    pub fn set_conn_eviction_idle_s(&self, seconds: Duration) -> &Self {
        unsafe {
            pagekite_set_conn_eviction_idle_s(self.inner, seconds.as_secs() as i32);
        }
        self
    }

    pub fn set_openssl_ciphers(&self, ciphers: &str) -> &Self {
        unsafe {
            pagekite_set_openssl_ciphers(self.inner, str_cstring!(ciphers));
        }
        self
    }

    pub fn want_spare_frontends(&self, spares: i32) -> &Self {
        unsafe {
            pagekite_want_spare_frontends(self.inner, spares);
        }
        self
    }

    pub fn thread_start(&self) -> bool {
        return unsafe { pagekite_thread_start(self.inner) } == 0;
    }

    pub fn thread_wait(&self) -> bool {
        return unsafe { pagekite_thread_wait(self.inner) } == 0;
    }

    pub fn thread_stop(&self) -> bool {
        return unsafe { pagekite_thread_stop(self.inner) } == 0;
    }

    pub fn get_status(&self) -> Status {
        return unsafe { pagekite_get_status(self.inner) }.into();
    }

    pub fn get_log(&self) -> String {
        unsafe {
            CStr::from_ptr(pagekite_get_log(self.inner))
                .to_string_lossy()
                .into_owned()
        }
    }

    pub fn dump_state_to_log(&self) -> &Self {
        unsafe {
            pagekite_dump_state_to_log(self.inner);
        }
        self
    }

    pub fn poll(&self, timeout: Duration) -> bool {
        return unsafe { pagekite_poll(self.inner, timeout.as_secs() as i32) } == 0;
    }

    pub fn tick(&self) -> bool {
        return unsafe { pagekite_tick(self.inner) } == 0;
    }
}

impl Drop for PageKite {
    fn drop(&mut self) {
        unsafe {
            pagekite_thread_stop(self.inner);
            pagekite_free(self.inner);
        }
    }
}
<commit_msg>Implement Send on PageKite<commit_after>// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
// You can obtain one at http://mozilla.org/MPL/2.0/.

/// See the documentation at https://github.com/pagekite/libpagekite/blob/master/doc/API.md

use ffi::*;
use std::ffi::{CStr, CString};
use std::mem::transmute;
use std::{convert, ptr};
use std::time::Duration;
#[derive(Clone, Copy)]
pub enum InitFlags {
    WithDefaults = 0x8000,
    WithoutDefaults = 0x4000,
    WithSsl = 0x0001,
    WithIpv4 = 0x0002,
    WithIpv6 = 0x0004,
    WithServiceFrontends = 0x0008,
    WithoutServiceFrontends = 0x0010,
    WithDynamicFeList = 0x0020,
    WithFrontendSni = 0x0040,
    AsFrontendRelay = 0x0100,
    WithSyslog = 0x0200,
}

#[derive(Clone, Copy)]
pub enum VerbosityFlags {
    LogTunnelData = 0x000100,
    LogTunnelHeaders = 0x000200,
    LogTunnelConns = 0x000400,
    LogBeData = 0x001000,
    LogBeHeaders = 0x002000,
    LogBeConns = 0x004000,
    LogManagerError = 0x010000,
    LogManagerInfo = 0x020000,
    LogManagerDebug = 0x040000,
    LogTrace = 0x080000,
    LogLuaDebug = 0x008000,
    LogLuaInfo = 0x000800,
    LogError = 0x100000,
}

#[repr(i32)]
pub enum Status {
    Startup = 10,
    Connecting = 20,
    UpdatingDns = 30,
    Flying = 40,
    PROProblems = 50,
    Rejected = 60,
    NoNetwork = 90,
}

impl convert::Into<Status> for i32 {
    fn into(self) -> Status {
        unsafe { transmute::<i32, Status>(self) }
    }
}

pub static LOG_ERRORS: [VerbosityFlags; 2] = [VerbosityFlags::LogError,
                                              VerbosityFlags::LogManagerError];
pub static LOG_MANAGER: [VerbosityFlags; 2] = [VerbosityFlags::LogManagerError,
                                               VerbosityFlags::LogManagerInfo];
pub static LOG_CONNS: [VerbosityFlags; 2] = [VerbosityFlags::LogBeConns,
                                             VerbosityFlags::LogTunnelConns];
pub static LOG_NORMAL: [VerbosityFlags; 7] = [VerbosityFlags::LogError,
                                              VerbosityFlags::LogManagerError,
                                              VerbosityFlags::LogBeConns,
                                              VerbosityFlags::LogTunnelConns,
                                              VerbosityFlags::LogManagerError,
                                              VerbosityFlags::LogManagerInfo,
                                              VerbosityFlags::LogLuaInfo];
pub static LOG_ALL: [VerbosityFlags; 13] = [VerbosityFlags::LogTunnelData,
                                            VerbosityFlags::LogTunnelHeaders,
                                            VerbosityFlags::LogTunnelConns,
                                            VerbosityFlags::LogBeData,
                                            VerbosityFlags::LogBeHeaders,
                                            VerbosityFlags::LogBeConns,
                                            VerbosityFlags::LogManagerError,
                                            VerbosityFlags::LogManagerInfo,
                                            VerbosityFlags::LogManagerDebug,
                                            VerbosityFlags::LogTrace,
                                            VerbosityFlags::LogLuaDebug,
                                            VerbosityFlags::LogLuaInfo,
                                            VerbosityFlags::LogError];

#[derive(Clone)]
pub struct PageKite {
    inner: pagekite_mgr,
}

unsafe impl Send for PageKite {}

macro_rules! str_cstring(
    ($a:ident) => ( CString::new($a).unwrap().as_ptr() )
);

macro_rules! build_flag(
    ($flag:ident, $array:ident) => (
        let mut $flag = 0;
        for item in $array {
            $flag |= *item as i32;
        }
    )
);

#[inline]
fn bool2int(val: bool) -> i32 {
    if val { 1 } else { 0 }
}

impl PageKite {
    pub fn init(app_id: Option<&str>,
                max_kites: i32,
                max_frontends: i32,
                max_conns: i32,
                dyndns_url: Option<&str>,
                flags: &[InitFlags],
                verbosity: &[VerbosityFlags])
                -> Option<Self> {

        build_flag!(c_flags, flags);
        build_flag!(c_verbosity, verbosity);

        let c_app_id = match app_id {
            Some(value) => str_cstring!(value),
            None => ptr::null(),
        };

        let c_dyndns_url = match dyndns_url {
            Some(value) => str_cstring!(value),
            None => ptr::null(),
        };

        let raw = unsafe {
            pagekite_init(c_app_id,
                          max_kites,
                          max_frontends,
                          max_conns,
                          c_dyndns_url,
                          c_flags,
                          c_verbosity)
        };
        if raw.is_null() {
            return None;
        }
        Some(PageKite { inner: raw })
    }

    pub fn init_pagekitenet(app_id: Option<&str>,
                            max_kites: i32,
                            max_conns: i32,
                            flags: &[InitFlags],
                            verbosity: &[VerbosityFlags])
                            -> Option<Self> {

        build_flag!(c_flags, flags);
        build_flag!(c_verbosity, verbosity);

        let c_app_id = match app_id {
            Some(value) => str_cstring!(value),
            None => ptr::null(),
        };

        let raw = unsafe {
            pagekite_init_pagekitenet(c_app_id, max_kites, max_conns, c_flags, c_verbosity)
        };
        if raw.is_null() {
            return None;
        }
        Some(PageKite { inner: raw })
    }

    pub fn init_whitelabel(app_id: Option<&str>,
                           max_kites: i32,
                           max_conns: i32,
                           flags: &[InitFlags],
                           verbosity: &[VerbosityFlags],
                           whitelabel_tld: Option<&str>)
                           -> Option<Self> {

        build_flag!(c_flags, flags);
        build_flag!(c_verbosity, verbosity);

        let c_app_id = match app_id {
            Some(value) => str_cstring!(value),
            None => ptr::null(),
        };

        let c_tld = match whitelabel_tld {
            Some(value) => str_cstring!(value),
            None => ptr::null(),
        };

        let raw = unsafe {
            pagekite_init_whitelabel(c_app_id, max_kites, max_conns, c_flags, c_verbosity, c_tld)
        };
        if raw.is_null() {
            return None;
        }
        Some(PageKite { inner: raw })
    }

    pub fn add_kite(&self,
                    proto: &str,
                    kitename: &str,
                    public_port: i32,
                    secret: &str,
                    backend: &str,
                    local_port: i32)
                    -> bool {

        return unsafe {
                   pagekite_add_kite(self.inner,
                                     str_cstring!(proto),
                                     str_cstring!(kitename),
                                     public_port,
                                     str_cstring!(secret),
                                     str_cstring!(backend),
                                     local_port)
               } == 0;
    }

    /// Useful flags are WithDefaults, WithIpv4, WithIpv6, WithDynamicFeList
    /// Returns the number of frontend ips, or an empty error.
    pub fn add_service_frontends(&self, flags: &[InitFlags]) -> Result<usize, ()> {
        build_flag!(c_flags, flags);
        let ret = unsafe { pagekite_add_service_frontends(self.inner, c_flags) };
        if ret == -1 { Err(()) } else { Ok(ret as usize) }
    }

    pub fn add_whitelabel_frontends(&self,
                                    flags: &[InitFlags],
                                    whitelabel_tld: Option<&str>)
                                    -> Result<usize, ()> {
        build_flag!(c_flags, flags);
        let c_tld = match whitelabel_tld {
            Some(value) => str_cstring!(value),
            None => ptr::null(),
        };
        let ret = unsafe { pagekite_add_whitelabel_frontends(self.inner, c_flags, c_tld) };
        if ret == -1 { Err(()) } else { Ok(ret as usize) }
    }

    pub fn lookup_and_add_frontend(&self,
                                   domain: &str,
                                   port: i32,
                                   update_from_dns: bool)
                                   -> Option<i32> {
        let count = unsafe {
            pagekite_lookup_and_add_frontend(self.inner,
                                             str_cstring!(domain),
                                             port,
                                             if update_from_dns { 1 } else { 0 })
        };
        if count == -1 { None } else { Some(count) }
    }

    pub fn add_frontend(&self, domain: &str, port: i32) -> Option<i32> {
        let count = unsafe { pagekite_add_frontend(self.inner, str_cstring!(domain), port) };
        if count == -1 { None } else { Some(count) }
    }

    pub fn set_log_mask(&self, flags: &[VerbosityFlags]) {
        build_flag!(c_verbosity, flags);
        unsafe {
            pagekite_set_log_mask(self.inner, c_verbosity);
        }
    }

    pub fn set_housekeeping_min_interval(&self, interval: Duration) -> Duration {
        let ret = unsafe {
            pagekite_set_housekeeping_min_interval(self.inner, interval.as_secs() as i32)
        };
        Duration::new(ret as u64, 0)
    }

    pub fn set_housekeeping_max_interval(&self, interval: Duration) -> Duration {
        let ret = unsafe {
            pagekite_set_housekeeping_max_interval(self.inner, interval.as_secs() as i32)
        };
        Duration::new(ret as u64, 0)
    }

    pub fn enable_http_forwarding_headers(&self, enable: bool) -> &Self {
        unsafe {
            pagekite_enable_http_forwarding_headers(self.inner, bool2int(enable));
        }
        self
    }

    pub fn enable_fake_ping(&self, enable: bool) -> &Self {
        unsafe {
            pagekite_enable_fake_ping(self.inner, bool2int(enable));
        }
        self
    }

    pub fn enable_watchdog(&self, enable: bool) -> &Self {
        unsafe {
            pagekite_enable_watchdog(self.inner, bool2int(enable));
        }
        self
    }

    pub fn enable_tick_timer(&self, enable: bool) -> &Self {
        unsafe {
            pagekite_enable_tick_timer(self.inner, bool2int(enable));
        }
        self
    }

    pub fn set_conn_eviction_idle_s(&self, seconds: Duration) -> &Self {
        unsafe {
            pagekite_set_conn_eviction_idle_s(self.inner, seconds.as_secs() as i32);
        }
        self
    }

    pub fn set_openssl_ciphers(&self, ciphers: &str) -> &Self {
        unsafe {
            pagekite_set_openssl_ciphers(self.inner, str_cstring!(ciphers));
        }
        self
    }

    pub fn want_spare_frontends(&self, spares: i32) -> &Self {
        unsafe {
            pagekite_want_spare_frontends(self.inner, spares);
        }
        self
    }

    pub fn thread_start(&self) -> bool {
        return unsafe { pagekite_thread_start(self.inner) } == 0;
    }

    pub fn thread_wait(&self) -> bool {
        return unsafe { pagekite_thread_wait(self.inner) } == 0;
    }

    pub fn thread_stop(&self) -> bool {
        return unsafe { pagekite_thread_stop(self.inner) } == 0;
    }

    pub fn get_status(&self) -> Status {
        return unsafe { pagekite_get_status(self.inner) }.into();
    }

    pub fn get_log(&self) -> String {
        unsafe {
            CStr::from_ptr(pagekite_get_log(self.inner))
                .to_string_lossy()
                .into_owned()
        }
    }

    pub fn dump_state_to_log(&self) -> &Self {
        unsafe {
            pagekite_dump_state_to_log(self.inner);
        }
        self
    }

    pub fn poll(&self, timeout: Duration) -> bool {
        return unsafe { pagekite_poll(self.inner, timeout.as_secs() as i32) } == 0;
    }

    pub fn tick(&self) -> bool {
        return unsafe { pagekite_tick(self.inner) } == 0;
    }
}

impl Drop for PageKite {
    fn drop(&mut self) {
        unsafe {
            pagekite_thread_stop(self.inner);
            pagekite_free(self.inner);
        }
    }
}
<|endoftext|>


<commit_before>use collectors;
use events;
use std::sync::mpsc::{channel, Sender};
use std::thread;
use std::mem;
use std::sync;
use log;

pub enum Item {
    Done,
    Emit(events::Event)
}

pub struct PipelineRef {
    chan: sync::Mutex<Sender<Item>>,
    filter: log::LogLevelFilter
}

static mut PIPELINE: *const PipelineRef = 0 as *const PipelineRef;

pub struct Pipeline {
    chan: Sender<Item>,
    worker: Option<thread::JoinHandle<()>>
}

impl Drop for Pipeline {
    fn drop(&mut self) {
        self.chan.send(Item::Done).is_ok();
        let thread = mem::replace(&mut self.worker, None);
        if let Some(handle) = thread {
            handle.join().is_ok();
        }
    }
}

pub fn is_enabled(level: log::LogLevel) -> bool {
    // Should be an atomic read, etc.
    let p = unsafe { PIPELINE };
    if p != 0 as *const PipelineRef {
        unsafe {
            (*p).filter >= level
        }
    } else {
        false
    }
}

pub fn emit(event: events::Event) {
    // Should be an atomic read, etc.
    let p = unsafe { PIPELINE };
    if p != 0 as *const PipelineRef {
        unsafe {
            (*p).chan.lock().unwrap().send(Item::Emit(event)).is_ok();
        }
    }
}

pub fn init<T: collectors::Collector + Send + 'static>(collector: T, level: log::LogLevel) -> Pipeline {
    let (tx, rx) = channel::<Item>();
    unsafe {
        let pr = Box::new(PipelineRef {
                chan: sync::Mutex::new(tx.clone()),
                filter: level.to_log_level_filter()
            });

        // Should be atomic CAS etc.
        PIPELINE = mem::transmute::<Box<PipelineRef>, *const PipelineRef>(pr);
    }

    let coll = collector;
    let child = thread::spawn(move|| {
        loop {
            let done = match rx.recv().unwrap() {
                Item::Done => true,
                Item::Emit(payload) => {
                    if let Err(e) = coll.dispatch(&vec![payload]) {
                        error!("Could not dispatch events: {}", e);
                    }
                    false
                }
            };

            if done {
                break;
            }
        }
    });

    Pipeline {
         worker: Some(child),
         chan: tx
    }
}

#[cfg(test)]
mod tests {
    use pipeline;
    use collectors::silent::SilentCollector;
    use log;

    #[test]
    fn info_is_enabled_at_info() {
        let _flush = pipeline::init(SilentCollector::new(), log::LogLevel::Info);
        assert!(pipeline::is_enabled(log::LogLevel::Info));
    }

    #[test]
    fn warn_is_enabled_at_info() {
        let _flush = pipeline::init(SilentCollector::new(), log::LogLevel::Info);
        assert!(pipeline::is_enabled(log::LogLevel::Warn));
    }

    #[test]
    fn debug_is_disabled_at_info() {
        let _flush = pipeline::init(SilentCollector::new(), log::LogLevel::Info);
        assert!(!pipeline::is_enabled(log::LogLevel::Debug));
    }
}<commit_msg>Atomic operations on the shared pipeline; less unsafe, not necessarily more safe :-)<commit_after>use collectors;
use events;
use std::sync::mpsc::{channel, Sender};
use std::thread;
use std::mem;
use std::sync;
use std::sync::atomic;
use log;

pub enum Item {
    Done,
    Emit(events::Event)
}

pub struct PipelineRef {
    chan: sync::Mutex<Sender<Item>>,
    filter: log::LogLevelFilter
}

static PIPELINE: atomic::AtomicUsize = atomic::ATOMIC_USIZE_INIT;

pub struct Pipeline {
    chan: Sender<Item>,
    worker: Option<thread::JoinHandle<()>>
}

impl Drop for Pipeline {
    fn drop(&mut self) {
        self.chan.send(Item::Done).is_ok();
        let thread = mem::replace(&mut self.worker, None);
        if let Some(handle) = thread {
            handle.join().is_ok();
        }
    }
}

pub fn is_enabled(level: log::LogLevel) -> bool {
    let p = PIPELINE.load(atomic::Ordering::Relaxed) as *const PipelineRef;
    if p != 0 as *const PipelineRef {
        unsafe {
            (*p).filter >= level
        }
    } else {
        false
    }
}

pub fn emit(event: events::Event) {
    let p = PIPELINE.load(atomic::Ordering::Relaxed) as *const PipelineRef;
    if p != 0 as *const PipelineRef {
        unsafe {
            (*p).chan.lock().unwrap().send(Item::Emit(event)).is_ok();
        }
    }
}

pub fn init<T: collectors::Collector + Send + 'static>(collector: T, level: log::LogLevel) -> Pipeline {
    let (tx, rx) = channel::<Item>();
    let pr = Box::new(PipelineRef {
            chan: sync::Mutex::new(tx.clone()),
            filter: level.to_log_level_filter()
        });

    PIPELINE.store(unsafe { mem::transmute::<Box<PipelineRef>, *const PipelineRef>(pr) } as usize, atomic::Ordering::SeqCst);

    let coll = collector;
    let child = thread::spawn(move|| {
        loop {
            let done = match rx.recv().unwrap() {
                Item::Done => true,
                Item::Emit(payload) => {
                    if let Err(e) = coll.dispatch(&vec![payload]) {
                        error!("Could not dispatch events: {}", e);
                    }
                    false
                }
            };

            if done {
                break;
            }
        }
    });

    Pipeline {
         worker: Some(child),
         chan: tx
    }
}

#[cfg(test)]
mod tests {
    use pipeline;
    use collectors::silent::SilentCollector;
    use log;

    #[test]
    fn info_is_enabled_at_info() {
        let _flush = pipeline::init(SilentCollector::new(), log::LogLevel::Info);
        assert!(pipeline::is_enabled(log::LogLevel::Info));
    }

    #[test]
    fn warn_is_enabled_at_info() {
        let _flush = pipeline::init(SilentCollector::new(), log::LogLevel::Info);
        assert!(pipeline::is_enabled(log::LogLevel::Warn));
    }

    #[test]
    fn debug_is_disabled_at_info() {
        let _flush = pipeline::init(SilentCollector::new(), log::LogLevel::Info);
        assert!(!pipeline::is_enabled(log::LogLevel::Debug));
    }
}<|endoftext|>


<commit_before>extern crate rustogram;
const HIGHEST_TRACKABLE_VALUE: i64 = 3600 * 1000 * 1000;
const NUMBER_OF_SIGNIFICANT_VALUE_DIGITS: i32 = 3;

#[test]
fn test_get_total_count() {
    let histogram = get_histogram();
    let raw_histogram = get_raw_histogram();
    assert_eq!(10_001, raw_histogram.get_total_count());
    assert_eq!(20_000, histogram.get_total_count());
}

#[test]
fn test_get_max_value() {
    let histogram = get_histogram();
    assert!(histogram.values_are_equivalent(100_000_000, histogram.get_max_value()));
}

#[test]
fn test_get_min_value() {
    let histogram = get_histogram();
    assert!(histogram.values_are_equivalent(1_000, histogram.get_min_value()));
}

#[test]
fn test_get_mean_value() {
    let mut histogram = get_histogram();
    let mut raw_histogram = get_raw_histogram();

    let expected_raw_mean = (10_000_000f64 + 100_000_000f64) / 10001f64;
    let expected_mean = (1_000f64 + 50_000_000f64) / 2f64;

    assert_float_eq(expected_raw_mean, raw_histogram.get_mean(), expected_raw_mean * 0.001);
    assert_float_eq(expected_mean, histogram.get_mean(), expected_mean * 0.001);
}

#[test]
fn test_get_value_at_percentile() {
    let histogram = get_histogram();
    let raw_histogram = get_raw_histogram();

    assert_eq!(1_000, raw_histogram.get_value_at_percentile(30f64));
}

fn assert_float_eq(expected: f64, actual: f64, delta: f64) {
    // TODO improve error message
    assert!(actual > expected - delta && actual < expected + delta);
}

fn get_histogram() -> rustogram::Histogram {
    let mut h = rustogram::new_histogram(HIGHEST_TRACKABLE_VALUE, NUMBER_OF_SIGNIFICANT_VALUE_DIGITS);

    let mut i = 10_000;
    while i != 0 {
        h.record_value_with_expected_interval(1_000, 10_000);
        i -= 1;
    }
    h.record_value_with_expected_interval(100_000_000, 10_000);
    h
}

fn get_raw_histogram() -> rustogram::Histogram {
     let mut h = rustogram::new_histogram(HIGHEST_TRACKABLE_VALUE, NUMBER_OF_SIGNIFICANT_VALUE_DIGITS);

    let mut i = 10_000;
    while i != 0 {
        h.record_value(1_000);
        i -= 1;
    }
    h.record_value(100_000_000);
    h
}
<commit_msg>failing get_std_deviation test<commit_after>extern crate rustogram;
const HIGHEST_TRACKABLE_VALUE: i64 = 3600 * 1000 * 1000;
const NUMBER_OF_SIGNIFICANT_VALUE_DIGITS: i32 = 3;

#[test]
fn test_get_total_count() {
    let histogram = get_histogram();
    let raw_histogram = get_raw_histogram();
    assert_eq!(10_001, raw_histogram.get_total_count());
    assert_eq!(20_000, histogram.get_total_count());
}

#[test]
fn test_get_max_value() {
    let histogram = get_histogram();
    assert!(histogram.values_are_equivalent(100_000_000, histogram.get_max_value()));
}

#[test]
fn test_get_min_value() {
    let histogram = get_histogram();
    assert!(histogram.values_are_equivalent(1_000, histogram.get_min_value()));
}

#[test]
fn test_get_mean_value() {
    let mut histogram = get_histogram();
    let mut raw_histogram = get_raw_histogram();

    let expected_raw_mean = (10_000_000f64 + 100_000_000f64) / 10001f64;
    let expected_mean = (1_000f64 + 50_000_000f64) / 2f64;

    assert_float_eq(expected_raw_mean, raw_histogram.get_mean(), expected_raw_mean * 0.001);
    assert_float_eq(expected_mean, histogram.get_mean(), expected_mean * 0.001);
}

#[test]
fn test_get_value_at_percentile() {
    let histogram = get_histogram();
    let raw_histogram = get_raw_histogram();

    assert_eq!(1_000, raw_histogram.get_value_at_percentile(30f64));
}

#[ignore]
#[test]
fn test_get_std_deviation() {
    let histogram = get_histogram();
    let raw_histogram = get_raw_histogram();

    let expected_raw_mean = (10_000_000f64 + 100_000_000f64) / 10001f64;
    let expected_raw_std_dev = (((10000.0 * (1000.0 - expected_raw_mean).powf(2f64)) +
                                (100000000.0 - expected_raw_mean).powf(2f64)) / 10001f64).sqrt();
    let expected_mean = (1_000f64 + 50_000_000f64) / 2f64;
    let mut expected_square_deviation_sum = 10_000f64 * (1_000f64 - expected_mean).powf(2f64);
    let mut value = 10_000;
    while value <= 100_000_000 {
        expected_square_deviation_sum += (value as f64 - expected_mean).powf(2f64);
        value += 10_000;
    }
    let expected_std_dev = (expected_square_deviation_sum as f64 / 20_000f64).sqrt();

    assert_float_eq(expected_raw_std_dev, raw_histogram.get_std_deviation(), expected_raw_std_dev * 0.001);
    assert_float_eq(expected_std_dev, histogram.get_std_deviation(), expected_std_dev * 0.001);
}

fn assert_float_eq(expected: f64, actual: f64, delta: f64) {
    // TODO improve error message
    assert!(actual > expected - delta && actual < expected + delta);
}

fn get_histogram() -> rustogram::Histogram {
    let mut h = rustogram::new_histogram(HIGHEST_TRACKABLE_VALUE, NUMBER_OF_SIGNIFICANT_VALUE_DIGITS);

    let mut i = 10_000;
    while i != 0 {
        h.record_value_with_expected_interval(1_000, 10_000);
        i -= 1;
    }
    h.record_value_with_expected_interval(100_000_000, 10_000);
    h
}

fn get_raw_histogram() -> rustogram::Histogram {
     let mut h = rustogram::new_histogram(HIGHEST_TRACKABLE_VALUE, NUMBER_OF_SIGNIFICANT_VALUE_DIGITS);

    let mut i = 10_000;
    while i != 0 {
        h.record_value(1_000);
        i -= 1;
    }
    h.record_value(100_000_000);
    h
}
<|endoftext|>


<commit_before>#![cfg(feature = "integration")]

use std::env;
use std::process::Command;

#[cfg_attr(feature = "integration", test)]
fn integration_test() {
    let repo_name = env::var("INTEGRATION").expect("`INTEGRATION` var not set");
    let repo_url = format!("https://github.com/{}", repo_name);
    let crate_name = repo_name
        .split('/')
        .nth(1)
        .expect("repo name should have format `<org>/<name>`");

    let repo_dir = tempfile::tempdir()
        .expect("couldn't create temp dir")
        .path()
        .join(crate_name);

    let st = Command::new("git")
        .args(&["clone", "--depth=1", &repo_url, repo_dir.to_str().unwrap()])
        .status()
        .expect("unable to run git");
    assert!(st.success());

    let root_dir = std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR"));
    let target_dir = std::path::Path::new(&root_dir).join("target");
    let clippy_binary = target_dir.join(env!("PROFILE")).join("cargo-clippy");

    let output = Command::new(clippy_binary)
        .current_dir(repo_dir)
        .env("RUST_BACKTRACE", "full")
        .env("CARGO_TARGET_DIR", target_dir)
        .args(&[
            "clippy",
            "--all-targets",
            "--all-features",
            "--",
            "--cap-lints",
            "warn",
            "-Wclippy::pedantic",
            "-Wclippy::nursery",
        ])
        .output()
        .expect("unable to run clippy");

    let stderr = String::from_utf8_lossy(&output.stderr);
    if stderr.contains("internal compiler error") {
        let backtrace_start = stderr
            .find("thread 'rustc' panicked at")
            .expect("start of backtrace not found");
        let backtrace_end = stderr
            .rfind("error: internal compiler error")
            .expect("end of backtrace not found");

        panic!(
            "internal compiler error\nBacktrace:\n\n{}",
            &stderr[backtrace_start..backtrace_end]
        );
    } else if stderr.contains("query stack during panic") {
        panic!("query stack during panic in the output");
    } else if stderr.contains("E0463") {
        panic!("error: E0463");
    } else if stderr.contains("E0514") {
        panic!("incompatible crate versions");
    } else if stderr.contains("failed to run `rustc` to learn about target-specific information") {
        panic!("couldn't find librustc_driver, consider setting `LD_LIBRARY_PATH`");
    }

    match output.status.code() {
        Some(code) => {
            if code == 0 {
                println!("Compilation successful");
            } else {
                eprintln!("Compilation failed. Exit code: {}", code);
            }
        },
        None => panic!("Process terminated by signal"),
    }
}
<commit_msg>Use pattern matching instead of manually checking condition<commit_after>#![cfg(feature = "integration")]

use std::env;
use std::process::Command;

#[cfg_attr(feature = "integration", test)]
fn integration_test() {
    let repo_name = env::var("INTEGRATION").expect("`INTEGRATION` var not set");
    let repo_url = format!("https://github.com/{}", repo_name);
    let crate_name = repo_name
        .split('/')
        .nth(1)
        .expect("repo name should have format `<org>/<name>`");

    let repo_dir = tempfile::tempdir()
        .expect("couldn't create temp dir")
        .path()
        .join(crate_name);

    let st = Command::new("git")
        .args(&["clone", "--depth=1", &repo_url, repo_dir.to_str().unwrap()])
        .status()
        .expect("unable to run git");
    assert!(st.success());

    let root_dir = std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR"));
    let target_dir = std::path::Path::new(&root_dir).join("target");
    let clippy_binary = target_dir.join(env!("PROFILE")).join("cargo-clippy");

    let output = Command::new(clippy_binary)
        .current_dir(repo_dir)
        .env("RUST_BACKTRACE", "full")
        .env("CARGO_TARGET_DIR", target_dir)
        .args(&[
            "clippy",
            "--all-targets",
            "--all-features",
            "--",
            "--cap-lints",
            "warn",
            "-Wclippy::pedantic",
            "-Wclippy::nursery",
        ])
        .output()
        .expect("unable to run clippy");

    let stderr = String::from_utf8_lossy(&output.stderr);
    if stderr.contains("internal compiler error") {
        let backtrace_start = stderr
            .find("thread 'rustc' panicked at")
            .expect("start of backtrace not found");
        let backtrace_end = stderr
            .rfind("error: internal compiler error")
            .expect("end of backtrace not found");

        panic!(
            "internal compiler error\nBacktrace:\n\n{}",
            &stderr[backtrace_start..backtrace_end]
        );
    } else if stderr.contains("query stack during panic") {
        panic!("query stack during panic in the output");
    } else if stderr.contains("E0463") {
        panic!("error: E0463");
    } else if stderr.contains("E0514") {
        panic!("incompatible crate versions");
    } else if stderr.contains("failed to run `rustc` to learn about target-specific information") {
        panic!("couldn't find librustc_driver, consider setting `LD_LIBRARY_PATH`");
    }

    match output.status.code() {
        Some(0) => println!("Compilation successful"),
        Some(code) => eprintln!("Compilation failed. Exit code: {}", code),
        None => panic!("Process terminated by signal"),
    }
}
<|endoftext|>


<commit_before>#![feature(link_args)]
#[link_args = "-flat_namespace -undefined suppress"]
extern {}

#[cfg(feature = "with-syntex")]
mod inner {
    extern crate rustler_codegen;

    use std::env;
    use std::path::Path;

    pub fn main() {
        let out_dir = env::var_os("OUT_DIR").unwrap();

        let src = Path::new("src/lib.rs.in");
        let dst = Path::new(&out_dir).join("lib.rs");

        rustler_codegen::expand(&src, &dst).unwrap();
    }
}

#[cfg(not(feature = "with-syntex"))]
mod inner {
    pub fn main() {}
}

fn main() {
    inner::main();
}
<commit_msg>Fix build on linux<commit_after>#![feature(link_args)]
#[cfg(any(target_os = "mac"))]
#[link_args = "-flat_namespace -undefined suppress"]
extern {}

#[cfg(feature = "with-syntex")]
mod inner {
    extern crate rustler_codegen;

    use std::env;
    use std::path::Path;

    pub fn main() {
        let out_dir = env::var_os("OUT_DIR").unwrap();

        let src = Path::new("src/lib.rs.in");
        let dst = Path::new(&out_dir).join("lib.rs");

        rustler_codegen::expand(&src, &dst).unwrap();
    }
}

#[cfg(not(feature = "with-syntex"))]
mod inner {
    pub fn main() {}
}

fn main() {
    inner::main();
}
<|endoftext|>


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

use std::io::Write;
use tink::keyset::{Reader, Writer};

#[test]
fn test_json_io_unencrypted() {
    tink_mac::init();

    let manager = tink_testutil::new_hmac_keyset_manager();
    let h = manager.handle().expect("cannot get keyset handle");
    let ks1 = tink::keyset::insecure::keyset_material(&h);

    let mut buf = Vec::new();
    {
        let mut w = tink::keyset::JsonWriter::new(&mut buf);
        w.write(&ks1).expect("cannot write keyset");
    }

    let mut r = tink::keyset::JsonReader::new(&buf[..]);
    let ks2 = r.read().expect("cannot read keyset");
    assert_eq!(
        ks1, ks2,
        "written keyset ({:?}) doesn't match read keyset ({:?})",
        ks1, ks2
    );
}

#[test]
fn test_json_reader() {
    tink_mac::init();
    let gcm_key = tink_testutil::proto_encode(&tink_testutil::new_aes_gcm_key(0, 16));
    let eax_key = tink_testutil::proto_encode(&tink_testutil::new_hmac_key(
        tink::proto::HashType::Sha512,
        32,
    ));
    let json_keyset = format!(
        r#"{{
         "primaryKeyId":42,
         "key":[
            {{
               "keyData":{{
                  "typeUrl":"type.googleapis.com/google.crypto.tink.AesGcmKey",
                  "keyMaterialType":"SYMMETRIC",
                  "value": "{}"
               }},
               "outputPrefixType":"TINK",
               "keyId":42,
               "status":"ENABLED"
            }},
            {{
               "keyData":{{
                  "typeUrl":"type.googleapis.com/google.crypto.tink.AesEaxKey",
                  "keyMaterialType":"SYMMETRIC",
                  "value": "{}"
               }},
               "outputPrefixType":"RAW",
               "keyId":711,
               "status":"ENABLED"
            }}
         ]
      }}"#,
        base64::encode(&gcm_key),
        base64::encode(&eax_key)
    );

    let mut buf = Vec::new();
    buf.write_all(json_keyset.as_bytes()).unwrap();
    let mut r = tink::keyset::JsonReader::new(&buf[..]);

    let got = r.read().expect("cannot read keyset");

    let want = tink::proto::Keyset {
        primary_key_id: 42,
        key: vec![
            tink::proto::keyset::Key {
                key_data: Some(tink::proto::KeyData {
                    type_url: "type.googleapis.com/google.crypto.tink.AesGcmKey".to_string(),
                    key_material_type: tink::proto::key_data::KeyMaterialType::Symmetric as i32,
                    value: gcm_key,
                }),
                output_prefix_type: tink::proto::OutputPrefixType::Tink as i32,
                key_id: 42,
                status: tink::proto::KeyStatusType::Enabled as i32,
            },
            tink::proto::keyset::Key {
                key_data: Some(tink::proto::KeyData {
                    type_url: "type.googleapis.com/google.crypto.tink.AesEaxKey".to_string(),
                    key_material_type: tink::proto::key_data::KeyMaterialType::Symmetric as i32,
                    value: eax_key,
                }),
                output_prefix_type: tink::proto::OutputPrefixType::Raw as i32,
                key_id: 711,
                status: tink::proto::KeyStatusType::Enabled as i32,
            },
        ],
    };
    assert_eq!(got, want, "written keyset doesn't match expected keyset");
}

#[test]
fn test_json_reader_large_ids() {
    tink_mac::init();
    let gcm_key = tink_testutil::proto_encode(&tink_testutil::new_aes_gcm_key(0, 16));
    let json_keyset = format!(
        r#"{{
         "primaryKeyId":4294967275,
         "key":[
            {{
               "keyData":{{
                  "typeUrl":"type.googleapis.com/google.crypto.tink.AesGcmKey",
                  "keyMaterialType":"SYMMETRIC",
                  "value": "{}"
               }},
               "outputPrefixType":"TINK",
               "keyId":4294967275,
               "status":"ENABLED"
            }}
         ]
      }}"#,
        base64::encode(&gcm_key),
    );
    let mut buf = Vec::new();
    buf.write_all(json_keyset.as_bytes()).unwrap();
    let mut r = tink::keyset::JsonReader::new(&buf[..]);

    let got = r.read().expect("cannot read keyset");

    let want = tink::proto::Keyset {
        primary_key_id: 4294967275,
        key: vec![tink::proto::keyset::Key {
            key_data: Some(tink::proto::KeyData {
                type_url: "type.googleapis.com/google.crypto.tink.AesGcmKey".to_string(),
                key_material_type: tink::proto::key_data::KeyMaterialType::Symmetric as i32,
                value: gcm_key,
            }),
            output_prefix_type: tink::proto::OutputPrefixType::Tink as i32,
            key_id: 4294967275,
            status: tink::proto::KeyStatusType::Enabled as i32,
        }],
    };

    assert_eq!(got, want, "written keyset doesn't match expected keyset");
}

#[test]
fn test_json_reader_negative_ids() {
    tink_mac::init();
    let gcm_key = tink_testutil::proto_encode(&tink_testutil::new_aes_gcm_key(0, 16));
    let json_keyset = format!(
        r#"{{
         "primaryKeyId": -10,
         "key":[
            {{
               "keyData":{{
                  "typeUrl":"type.googleapis.com/google.crypto.tink.AesGcmKey",
                  "keyMaterialType":"SYMMETRIC",
                  "value": "{}"
               }},
               "outputPrefixType":"TINK",
               "keyId": -10,
               "status":"ENABLED"
            }}
         ]
      }}"#,
        base64::encode(&gcm_key),
    );
    let mut buf = Vec::new();
    buf.write_all(json_keyset.as_bytes()).unwrap();
    let mut r = tink::keyset::JsonReader::new(&buf[..]);

    assert!(r.read().is_err(), "Expected failure due to negative key id");
}

// Tests that large IDs (>2^31) are written correctly.
#[test]
fn test_json_writer_large_id() {
    tink_mac::init();
    let eax_key = tink_testutil::proto_encode(&tink_testutil::new_hmac_key(
        tink::proto::HashType::Sha512,
        32,
    ));

    let ks = tink::proto::Keyset {
        primary_key_id: 4294967275,
        key: vec![tink::proto::keyset::Key {
            key_data: Some(tink::proto::KeyData {
                type_url: "type.googleapis.com/google.crypto.tink.AesEaxKey".to_string(),
                key_material_type: tink::proto::key_data::KeyMaterialType::Symmetric as i32,
                value: eax_key,
            }),
            output_prefix_type: tink::proto::OutputPrefixType::Raw as i32,
            key_id: 4294967275,
            status: tink::proto::KeyStatusType::Enabled as i32,
        }],
    };

    let mut buf = Vec::new();
    {
        let mut w = tink::keyset::JsonWriter::new(&mut buf);
        w.write(&ks).expect("cannot write keyset");
    }

    let contents = String::from_utf8(buf).unwrap();
    assert!(
        contents.contains("\"keyId\": 4294967275"),
        "written keyset does not contain a key with keyId 4294967275"
    );
    assert!(
        contents.contains("\"primaryKeyId\": 4294967275"),
        "written keyset does not contain have primaryKeyId 4294967275"
    );
}

#[test]
fn test_json_io_encrypted() {
    tink_mac::init();
    let mut buf = Vec::new();

    let kse1 = tink::proto::EncryptedKeyset {
        encrypted_keyset: vec![b'A'; 32],
        keyset_info: None,
    };
    {
        let mut w = tink::keyset::JsonWriter::new(&mut buf);
        w.write_encrypted(&kse1)
            .expect("cannot write encrypted keyset");
    }

    let mut r = tink::keyset::JsonReader::new(&buf[..]);
    let kse2 = r.read_encrypted().expect("cannot read encrypted keyset");
    assert_eq!(
        kse1, kse2,
        "written encrypted keyset ({:?}) doesn't match read encrypted keyset ({:?})",
        kse1, kse2
    );
}
<commit_msg>tink::keyset: more JSON tests<commit_after>// Copyright 2020 The Tink-Rust Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
////////////////////////////////////////////////////////////////////////////////

use std::io::Write;
use tink::{
    keyset::{Reader, Writer},
    proto::{key_data::KeyMaterialType, KeyStatusType, OutputPrefixType},
};

#[test]
fn test_json_io_unencrypted() {
    tink_mac::init();

    let manager = tink_testutil::new_hmac_keyset_manager();
    let h = manager.handle().expect("cannot get keyset handle");
    let ks1 = tink::keyset::insecure::keyset_material(&h);

    let mut buf = Vec::new();
    {
        let mut w = tink::keyset::JsonWriter::new(&mut buf);
        w.write(&ks1).expect("cannot write keyset");
    }

    let mut r = tink::keyset::JsonReader::new(&buf[..]);
    let ks2 = r.read().expect("cannot read keyset");
    assert_eq!(
        ks1, ks2,
        "written keyset ({:?}) doesn't match read keyset ({:?})",
        ks1, ks2
    );
}

#[test]
fn test_json_reader() {
    tink_mac::init();
    let gcm_key = tink_testutil::proto_encode(&tink_testutil::new_aes_gcm_key(0, 16));
    let eax_key = tink_testutil::proto_encode(&tink_testutil::new_hmac_key(
        tink::proto::HashType::Sha512,
        32,
    ));

    let json_keyset = format!(
        r#"{{
         "primaryKeyId":42,
         "key":[
            {{
               "keyData":{{
                  "typeUrl":"type.googleapis.com/google.crypto.tink.AesGcmKey",
                  "keyMaterialType":"SYMMETRIC",
                  "value": "{}"
               }},
               "outputPrefixType":"TINK",
               "keyId":42,
               "status":"ENABLED"
            }},
            {{
               "keyData":{{
                  "typeUrl":"type.googleapis.com/google.crypto.tink.AesEaxKey",
                  "keyMaterialType":"SYMMETRIC",
                  "value": "{}"
               }},
               "outputPrefixType":"RAW",
               "keyId":711,
               "status":"ENABLED"
            }}
         ]
      }}"#,
        base64::encode(&gcm_key),
        base64::encode(&eax_key)
    );

    let mut buf = Vec::new();
    buf.write_all(json_keyset.as_bytes()).unwrap();
    let mut r = tink::keyset::JsonReader::new(&buf[..]);

    let got = r.read().expect("cannot read keyset");

    let want = tink::proto::Keyset {
        primary_key_id: 42,
        key: vec![
            tink::proto::keyset::Key {
                key_data: Some(tink::proto::KeyData {
                    type_url: "type.googleapis.com/google.crypto.tink.AesGcmKey".to_string(),
                    key_material_type: KeyMaterialType::Symmetric as i32,
                    value: gcm_key,
                }),
                output_prefix_type: OutputPrefixType::Tink as i32,
                key_id: 42,
                status: KeyStatusType::Enabled as i32,
            },
            tink::proto::keyset::Key {
                key_data: Some(tink::proto::KeyData {
                    type_url: "type.googleapis.com/google.crypto.tink.AesEaxKey".to_string(),
                    key_material_type: KeyMaterialType::Symmetric as i32,
                    value: eax_key,
                }),
                output_prefix_type: OutputPrefixType::Raw as i32,
                key_id: 711,
                status: KeyStatusType::Enabled as i32,
            },
        ],
    };
    assert_eq!(got, want, "written keyset doesn't match expected keyset");
}

#[test]
fn test_json_reader_large_ids() {
    tink_mac::init();
    let gcm_key = tink_testutil::proto_encode(&tink_testutil::new_aes_gcm_key(0, 16));
    let json_keyset = format!(
        r#"{{
         "primaryKeyId":4294967275,
         "key":[
            {{
               "keyData":{{
                  "typeUrl":"type.googleapis.com/google.crypto.tink.AesGcmKey",
                  "keyMaterialType":"SYMMETRIC",
                  "value": "{}"
               }},
               "outputPrefixType":"TINK",
               "keyId":4294967275,
               "status":"ENABLED"
            }}
         ]
      }}"#,
        base64::encode(&gcm_key),
    );
    let mut buf = Vec::new();
    buf.write_all(json_keyset.as_bytes()).unwrap();
    let mut r = tink::keyset::JsonReader::new(&buf[..]);

    let got = r.read().expect("cannot read keyset");

    let want = tink::proto::Keyset {
        primary_key_id: 4294967275,
        key: vec![tink::proto::keyset::Key {
            key_data: Some(tink::proto::KeyData {
                type_url: "type.googleapis.com/google.crypto.tink.AesGcmKey".to_string(),
                key_material_type: KeyMaterialType::Symmetric as i32,
                value: gcm_key,
            }),
            output_prefix_type: OutputPrefixType::Tink as i32,
            key_id: 4294967275,
            status: KeyStatusType::Enabled as i32,
        }],
    };

    assert_eq!(got, want, "written keyset doesn't match expected keyset");
}

#[test]
fn test_json_reader_negative_ids() {
    tink_mac::init();
    let gcm_key = tink_testutil::proto_encode(&tink_testutil::new_aes_gcm_key(0, 16));
    let json_keyset = format!(
        r#"{{
         "primaryKeyId": -10,
         "key":[
            {{
               "keyData":{{
                  "typeUrl":"type.googleapis.com/google.crypto.tink.AesGcmKey",
                  "keyMaterialType":"SYMMETRIC",
                  "value": "{}"
               }},
               "outputPrefixType":"TINK",
               "keyId": -10,
               "status":"ENABLED"
            }}
         ]
      }}"#,
        base64::encode(&gcm_key),
    );
    let mut buf = Vec::new();
    buf.write_all(json_keyset.as_bytes()).unwrap();
    let mut r = tink::keyset::JsonReader::new(&buf[..]);

    assert!(r.read().is_err(), "Expected failure due to negative key id");
}

// Tests that large IDs (>2^31) are written correctly.
#[test]
fn test_json_writer_large_id() {
    tink_mac::init();
    let eax_key = tink_testutil::proto_encode(&tink_testutil::new_hmac_key(
        tink::proto::HashType::Sha512,
        32,
    ));

    let ks = tink::proto::Keyset {
        primary_key_id: 4294967275,
        key: vec![tink::proto::keyset::Key {
            key_data: Some(tink::proto::KeyData {
                type_url: "type.googleapis.com/google.crypto.tink.AesEaxKey".to_string(),
                key_material_type: KeyMaterialType::Symmetric as i32,
                value: eax_key,
            }),
            output_prefix_type: OutputPrefixType::Raw as i32,
            key_id: 4294967275,
            status: KeyStatusType::Enabled as i32,
        }],
    };

    let mut buf = Vec::new();
    {
        let mut w = tink::keyset::JsonWriter::new(&mut buf);
        w.write(&ks).expect("cannot write keyset");
    }

    let contents = String::from_utf8(buf).unwrap();
    assert!(
        contents.contains("\"keyId\": 4294967275"),
        "written keyset does not contain a key with keyId 4294967275"
    );
    assert!(
        contents.contains("\"primaryKeyId\": 4294967275"),
        "written keyset does not contain have primaryKeyId 4294967275"
    );
}

#[test]
fn test_json_io_encrypted() {
    tink_mac::init();
    let mut buf = Vec::new();

    let kse1 = tink::proto::EncryptedKeyset {
        encrypted_keyset: vec![b'A'; 32],
        keyset_info: None,
    };
    {
        let mut w = tink::keyset::JsonWriter::new(&mut buf);
        w.write_encrypted(&kse1)
            .expect("cannot write encrypted keyset");
    }

    let mut r = tink::keyset::JsonReader::new(&buf[..]);
    let kse2 = r.read_encrypted().expect("cannot read encrypted keyset");
    assert_eq!(
        kse1, kse2,
        "written encrypted keyset ({:?}) doesn't match read encrypted keyset ({:?})",
        kse1, kse2
    );
}

#[test]
fn test_json_io_read_fail_decode() {
    tink_mac::init();
    let buf = vec![1, 2, 3];
    let mut r = tink::keyset::JsonReader::new(&buf[..]);
    assert!(r.read().is_err());

    let buf = vec![1, 2, 3];
    let mut r = tink::keyset::JsonReader::new(&buf[..]);
    assert!(r.read_encrypted().is_err());
}

#[test]
fn test_json_io_fail() {
    let eax_key = tink_testutil::proto_encode(&tink_testutil::new_hmac_key(
        tink::proto::HashType::Sha512,
        32,
    ));
    let ks = tink::proto::Keyset {
        primary_key_id: 4294967275,
        key: vec![tink::proto::keyset::Key {
            key_data: Some(tink::proto::KeyData {
                type_url: "type.googleapis.com/google.crypto.tink.AesEaxKey".to_string(),
                key_material_type: KeyMaterialType::Symmetric as i32,
                value: eax_key,
            }),
            output_prefix_type: OutputPrefixType::Raw as i32,
            key_id: 4294967275,
            status: KeyStatusType::Enabled as i32,
        }],
    };
    let kse = tink::proto::EncryptedKeyset {
        encrypted_keyset: vec![b'A'; 32],
        keyset_info: None,
    };

    let mut sink = tink_testutil::IoFailure {};
    let mut w = tink::keyset::JsonWriter::new(&mut sink);
    assert!(w.write(&ks).is_err());

    let mut sink = tink_testutil::IoFailure {};
    let mut w = tink::keyset::JsonWriter::new(&mut sink);
    assert!(w.write_encrypted(&kse).is_err());

    let src = tink_testutil::IoFailure {};
    let mut r = tink::keyset::JsonReader::new(src);
    assert!(r.read().is_err());

    let src = tink_testutil::IoFailure {};
    let mut r = tink::keyset::JsonReader::new(src);
    assert!(r.read_encrypted().is_err());
}

#[test]
fn test_json_reader_all_enums() {
    tink_mac::init();
    let gcm_key = tink_testutil::proto_encode(&tink_testutil::new_aes_gcm_key(0, 16));

    let materials = vec![
        ("SYMMETRIC", KeyMaterialType::Symmetric),
        ("ASYMMETRIC_PRIVATE", KeyMaterialType::AsymmetricPrivate),
        ("ASYMMETRIC_PUBLIC", KeyMaterialType::AsymmetricPublic),
        ("REMOTE", KeyMaterialType::Remote),
        ("BURBLE", KeyMaterialType::UnknownKeymaterial),
    ];
    let key_statuses = vec![
        ("ENABLED", KeyStatusType::Enabled),
        ("DISABLED", KeyStatusType::Disabled),
        ("DESTROYED", KeyStatusType::Destroyed),
        ("BURBLE", KeyStatusType::UnknownStatus),
    ];
    let prefix_types = vec![
        ("TINK", OutputPrefixType::Tink),
        ("LEGACY", OutputPrefixType::Legacy),
        ("RAW", OutputPrefixType::Raw),
        ("CRUNCHY", OutputPrefixType::Crunchy),
        ("BURBLE", OutputPrefixType::UnknownPrefix),
    ];

    for (material_name, material_type) in &materials {
        for (status_name, status_type) in &key_statuses {
            for (prefix_name, prefix_type) in &prefix_types {
                let json_keyset = format!(
                    r#"{{
                          "primaryKeyId":42,
                          "key":[
                             {{
                                "keyData":{{
                                   "typeUrl":"type.googleapis.com/google.crypto.tink.AesGcmKey",
                                   "keyMaterialType":"{}",
                                   "value": "{}"
                                }},
                                "outputPrefixType":"{}",
                                "keyId":42,
                                "status":"{}"
                             }}
                          ]
                       }}"#,
                    material_name,
                    base64::encode(&gcm_key),
                    prefix_name,
                    status_name
                );
                let want = tink::proto::Keyset {
                    primary_key_id: 42,
                    key: vec![tink::proto::keyset::Key {
                        key_data: Some(tink::proto::KeyData {
                            type_url: "type.googleapis.com/google.crypto.tink.AesGcmKey"
                                .to_string(),
                            key_material_type: *material_type as i32,
                            value: gcm_key.clone(),
                        }),
                        output_prefix_type: *prefix_type as i32,
                        key_id: 42,
                        status: *status_type as i32,
                    }],
                };

                // Read from hand-crafted JSON
                let mut buf = Vec::new();
                buf.write_all(json_keyset.as_bytes()).unwrap();
                let mut r = tink::keyset::JsonReader::new(&buf[..]);
                let got = r.read().expect("cannot read keyset");
                assert_eq!(got, want, "written keyset doesn't match expected keyset");

                // Write to JSON and read back.
                let mut buf = Vec::new();
                {
                    let mut w = tink::keyset::JsonWriter::new(&mut buf);
                    w.write(&want).expect("cannot write keyset");
                }

                let mut r = tink::keyset::JsonReader::new(&buf[..]);
                let got = r.read().expect("cannot read keyset");
                assert_eq!(got, want, "written keyset doesn't match expected keyset");
            }
        }
    }
}

#[test]
fn test_json_read_invalid_b64() {
    let json_keyset = r#"{
         "primaryKeyId":42,
         "key":[
            {
               "keyData":{
                  "typeUrl":"type.googleapis.com/google.crypto.tink.AesGcmKey",
                  "keyMaterialType":"SYMMETRIC",
                  "value": "non base64 data ^&*%"
               },
               "outputPrefixType":"TINK",
               "keyId":42,
               "status":"ENABLED"
            }
         ]
      }"#;

    let mut buf = Vec::new();
    buf.write_all(json_keyset.as_bytes()).unwrap();
    let mut r = tink::keyset::JsonReader::new(&buf[..]);

    let result = r.read();
    tink_testutil::expect_err(result, "base64");
}
<|endoftext|>


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

<%namespace name="helpers" file="/helpers.mako.rs" />

<% data.new_style_struct("Color", inherited=True) %>

<% from data import to_rust_ident %>

${helpers.predefined_type(
    "color",
    "ColorPropertyValue",
    "::cssparser::RGBA::new(0, 0, 0, 255)",
    animation_value_type="AnimatedRGBA",
    flags="APPLIES_TO_FIRST_LETTER APPLIES_TO_FIRST_LINE APPLIES_TO_PLACEHOLDER",
    ignored_when_colors_disabled="True",
    spec="https://drafts.csswg.org/css-color/#color"
)}

// FIXME(#15973): Add servo support for system colors
//
// FIXME(emilio): Move outside of mako.
% if product == "gecko":
pub mod system_colors {
    <%
        # These are actually parsed. See nsCSSProps::kColorKTable
        system_colors = """activeborder activecaption appworkspace background buttonface
                           buttonhighlight buttonshadow buttontext captiontext graytext highlight
                           highlighttext inactiveborder inactivecaption inactivecaptiontext
                           infobackground infotext menu menutext scrollbar threeddarkshadow
                           threedface threedhighlight threedlightshadow threedshadow window
                           windowframe windowtext -moz-buttondefault -moz-buttonhoverface
                           -moz-buttonhovertext -moz-cellhighlight -moz-cellhighlighttext
                           -moz-eventreerow -moz-field -moz-fieldtext -moz-dialog -moz-dialogtext
                           -moz-dragtargetzone -moz-gtk-info-bar-text -moz-html-cellhighlight
                           -moz-html-cellhighlighttext -moz-mac-buttonactivetext
                           -moz-mac-chrome-active -moz-mac-chrome-inactive
                           -moz-mac-defaultbuttontext -moz-mac-focusring -moz-mac-menuselect
                           -moz-mac-menushadow -moz-mac-menutextdisable -moz-mac-menutextselect
                           -moz-mac-disabledtoolbartext -moz-mac-secondaryhighlight
                           -moz-mac-vibrancy-light -moz-mac-vibrancy-dark -moz-mac-menupopup
                           -moz-mac-menuitem -moz-mac-active-menuitem -moz-mac-source-list
                           -moz-mac-source-list-selection -moz-mac-active-source-list-selection
                           -moz-mac-tooltip
                           -moz-menuhover -moz-menuhovertext -moz-menubartext -moz-menubarhovertext
                           -moz-oddtreerow -moz-win-mediatext -moz-win-communicationstext
                           -moz-win-accentcolor -moz-win-accentcolortext
                           -moz-nativehyperlinktext -moz-comboboxtext -moz-combobox""".split()

        # These are not parsed but must be serialized
        # They are only ever set directly by Gecko
        extra_colors = """WindowBackground WindowForeground WidgetBackground WidgetForeground
                          WidgetSelectBackground WidgetSelectForeground Widget3DHighlight Widget3DShadow
                          TextBackground TextForeground TextSelectBackground TextSelectForeground
                          TextSelectForegroundCustom TextSelectBackgroundDisabled TextSelectBackgroundAttention
                          TextHighlightBackground TextHighlightForeground IMERawInputBackground
                          IMERawInputForeground IMERawInputUnderline IMESelectedRawTextBackground
                          IMESelectedRawTextForeground IMESelectedRawTextUnderline
                          IMEConvertedTextBackground IMEConvertedTextForeground IMEConvertedTextUnderline
                          IMESelectedConvertedTextBackground IMESelectedConvertedTextForeground
                          IMESelectedConvertedTextUnderline SpellCheckerUnderline""".split()
    %>
    use cssparser::Parser;
    use gecko_bindings::bindings::Gecko_GetLookAndFeelSystemColor;
    use gecko_bindings::structs::root::mozilla::LookAndFeel_ColorID;
    use std::fmt;
    use style_traits::ToCss;
    use values::computed::{Context, ToComputedValue};

    pub type SystemColor = LookAndFeel_ColorID;

    // It's hard to implement MallocSizeOf for LookAndFeel_ColorID because it
    // is a bindgen type. So we implement it on the typedef instead.
    malloc_size_of_is_0!(SystemColor);

    impl ToCss for SystemColor {
        fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
            let s = match *self {
                % for color in system_colors + extra_colors:
                    LookAndFeel_ColorID::eColorID_${to_rust_ident(color)} => "${color}",
                % endfor
                LookAndFeel_ColorID::eColorID_LAST_COLOR => unreachable!(),
            };
            dest.write_str(s)
        }
    }

    impl ToComputedValue for SystemColor {
        type ComputedValue = u32; // nscolor

        #[inline]
        fn to_computed_value(&self, cx: &Context) -> Self::ComputedValue {
            unsafe {
                Gecko_GetLookAndFeelSystemColor(*self as i32,
                                                cx.device().pres_context())
            }
        }

        #[inline]
        fn from_computed_value(_: &Self::ComputedValue) -> Self {
            unreachable!()
        }
    }

    impl SystemColor {
        pub fn parse<'i, 't>(input: &mut Parser<'i, 't>,) -> Result<Self, ()> {
            ascii_case_insensitive_phf_map! {
                color_name -> SystemColor = {
                    % for color in system_colors:
                        "${color}" => LookAndFeel_ColorID::eColorID_${to_rust_ident(color)},
                    % endfor
                }
            }

            let ident = input.expect_ident().map_err(|_| ())?;
            color_name(ident).cloned().ok_or(())
        }
    }
}
% endif
<commit_msg>Servo changes for system colors -moz-mac-vibrant-titlebar-light/dark<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

<%namespace name="helpers" file="/helpers.mako.rs" />

<% data.new_style_struct("Color", inherited=True) %>

<% from data import to_rust_ident %>

${helpers.predefined_type(
    "color",
    "ColorPropertyValue",
    "::cssparser::RGBA::new(0, 0, 0, 255)",
    animation_value_type="AnimatedRGBA",
    flags="APPLIES_TO_FIRST_LETTER APPLIES_TO_FIRST_LINE APPLIES_TO_PLACEHOLDER",
    ignored_when_colors_disabled="True",
    spec="https://drafts.csswg.org/css-color/#color"
)}

// FIXME(#15973): Add servo support for system colors
//
// FIXME(emilio): Move outside of mako.
% if product == "gecko":
pub mod system_colors {
    <%
        # These are actually parsed. See nsCSSProps::kColorKTable
        system_colors = """activeborder activecaption appworkspace background buttonface
                           buttonhighlight buttonshadow buttontext captiontext graytext highlight
                           highlighttext inactiveborder inactivecaption inactivecaptiontext
                           infobackground infotext menu menutext scrollbar threeddarkshadow
                           threedface threedhighlight threedlightshadow threedshadow window
                           windowframe windowtext -moz-buttondefault -moz-buttonhoverface
                           -moz-buttonhovertext -moz-cellhighlight -moz-cellhighlighttext
                           -moz-eventreerow -moz-field -moz-fieldtext -moz-dialog -moz-dialogtext
                           -moz-dragtargetzone -moz-gtk-info-bar-text -moz-html-cellhighlight
                           -moz-html-cellhighlighttext -moz-mac-buttonactivetext
                           -moz-mac-chrome-active -moz-mac-chrome-inactive
                           -moz-mac-defaultbuttontext -moz-mac-focusring -moz-mac-menuselect
                           -moz-mac-menushadow -moz-mac-menutextdisable -moz-mac-menutextselect
                           -moz-mac-disabledtoolbartext -moz-mac-secondaryhighlight
                           -moz-mac-vibrancy-light -moz-mac-vibrancy-dark
                           -moz-mac-vibrant-titlebar-light -moz-mac-vibrant-titlebar-dark
                           -moz-mac-menupopup
                           -moz-mac-menuitem -moz-mac-active-menuitem -moz-mac-source-list
                           -moz-mac-source-list-selection -moz-mac-active-source-list-selection
                           -moz-mac-tooltip
                           -moz-menuhover -moz-menuhovertext -moz-menubartext -moz-menubarhovertext
                           -moz-oddtreerow -moz-win-mediatext -moz-win-communicationstext
                           -moz-win-accentcolor -moz-win-accentcolortext
                           -moz-nativehyperlinktext -moz-comboboxtext -moz-combobox""".split()

        # These are not parsed but must be serialized
        # They are only ever set directly by Gecko
        extra_colors = """WindowBackground WindowForeground WidgetBackground WidgetForeground
                          WidgetSelectBackground WidgetSelectForeground Widget3DHighlight Widget3DShadow
                          TextBackground TextForeground TextSelectBackground TextSelectForeground
                          TextSelectForegroundCustom TextSelectBackgroundDisabled TextSelectBackgroundAttention
                          TextHighlightBackground TextHighlightForeground IMERawInputBackground
                          IMERawInputForeground IMERawInputUnderline IMESelectedRawTextBackground
                          IMESelectedRawTextForeground IMESelectedRawTextUnderline
                          IMEConvertedTextBackground IMEConvertedTextForeground IMEConvertedTextUnderline
                          IMESelectedConvertedTextBackground IMESelectedConvertedTextForeground
                          IMESelectedConvertedTextUnderline SpellCheckerUnderline""".split()
    %>
    use cssparser::Parser;
    use gecko_bindings::bindings::Gecko_GetLookAndFeelSystemColor;
    use gecko_bindings::structs::root::mozilla::LookAndFeel_ColorID;
    use std::fmt;
    use style_traits::ToCss;
    use values::computed::{Context, ToComputedValue};

    pub type SystemColor = LookAndFeel_ColorID;

    // It's hard to implement MallocSizeOf for LookAndFeel_ColorID because it
    // is a bindgen type. So we implement it on the typedef instead.
    malloc_size_of_is_0!(SystemColor);

    impl ToCss for SystemColor {
        fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
            let s = match *self {
                % for color in system_colors + extra_colors:
                    LookAndFeel_ColorID::eColorID_${to_rust_ident(color)} => "${color}",
                % endfor
                LookAndFeel_ColorID::eColorID_LAST_COLOR => unreachable!(),
            };
            dest.write_str(s)
        }
    }

    impl ToComputedValue for SystemColor {
        type ComputedValue = u32; // nscolor

        #[inline]
        fn to_computed_value(&self, cx: &Context) -> Self::ComputedValue {
            unsafe {
                Gecko_GetLookAndFeelSystemColor(*self as i32,
                                                cx.device().pres_context())
            }
        }

        #[inline]
        fn from_computed_value(_: &Self::ComputedValue) -> Self {
            unreachable!()
        }
    }

    impl SystemColor {
        pub fn parse<'i, 't>(input: &mut Parser<'i, 't>,) -> Result<Self, ()> {
            ascii_case_insensitive_phf_map! {
                color_name -> SystemColor = {
                    % for color in system_colors:
                        "${color}" => LookAndFeel_ColorID::eColorID_${to_rust_ident(color)},
                    % endfor
                }
            }

            let ident = input.expect_ident().map_err(|_| ())?;
            color_name(ident).cloned().ok_or(())
        }
    }
}
% endif
<|endoftext|>


<commit_before>#[cfg(feature = "rustcrypto_api")]
pub use stream_cipher::generic_array;

pub use ppv_lite86::Machine;
use ppv_lite86::{vec128_storage, ArithOps, BitOps32, LaneWords4, MultiLane, StoreBytes, Vec4};

pub(crate) const BLOCK: usize = 64;
pub(crate) const BLOCK64: u64 = BLOCK as u64;
const LOG2_BUFBLOCKS: u64 = 2;
const BUFBLOCKS: u64 = 1 << LOG2_BUFBLOCKS;
pub(crate) const BUFSZ64: u64 = BLOCK64 * BUFBLOCKS;
pub(crate) const BUFSZ: usize = BUFSZ64 as usize;

#[derive(Clone)]
pub struct ChaCha {
    pub(crate) b: vec128_storage,
    pub(crate) c: vec128_storage,
    pub(crate) d: vec128_storage,
}

#[derive(Clone)]
pub struct State<V> {
    pub(crate) a: V,
    pub(crate) b: V,
    pub(crate) c: V,
    pub(crate) d: V,
}

#[inline(always)]
pub(crate) fn round<V: ArithOps + BitOps32>(mut x: State<V>) -> State<V> {
    x.a += x.b;
    x.d = (x.d ^ x.a).rotate_each_word_right16();
    x.c += x.d;
    x.b = (x.b ^ x.c).rotate_each_word_right20();
    x.a += x.b;
    x.d = (x.d ^ x.a).rotate_each_word_right24();
    x.c += x.d;
    x.b = (x.b ^ x.c).rotate_each_word_right25();
    x
}

#[inline(always)]
pub(crate) fn diagonalize<V: LaneWords4>(mut x: State<V>) -> State<V> {
    // Since b has the critical data dependency, avoid rotating b to hide latency.
    //
    // The order of these statements is important for performance on pre-AVX2 Intel machines, which
    // are throughput-bound and operating near their superscalar limits during refill_wide. The
    // permutations here and in undiagonalize have been found in testing on Nehalem to be optimal.
    x.a = x.a.shuffle_lane_words1230();
    x.c = x.c.shuffle_lane_words3012();
    x.d = x.d.shuffle_lane_words2301();
    x
}

#[inline(always)]
pub(crate) fn undiagonalize<V: LaneWords4>(mut x: State<V>) -> State<V> {
    // The order of these statements is magic. See comment in diagonalize.
    x.c = x.c.shuffle_lane_words1230();
    x.d = x.d.shuffle_lane_words2301();
    x.a = x.a.shuffle_lane_words3012();
    x
}

impl ChaCha {
    #[inline(always)]
    pub fn new(key: &[u8; 32], nonce: &[u8]) -> Self {
        init_chacha(key, nonce)
    }

    #[inline(always)]
    fn pos64<M: Machine>(&self, m: M) -> u64 {
        let d: M::u32x4 = m.unpack(self.d);
        ((d.extract(1) as u64) << 32) | d.extract(0) as u64
    }

    /// Set 64-bit block count, affecting next refill.
    #[inline(always)]
    pub(crate) fn seek64<M: Machine>(&mut self, m: M, blockct: u64) {
        let d: M::u32x4 = m.unpack(self.d);
        self.d = d
            .insert((blockct >> 32) as u32, 1)
            .insert(blockct as u32, 0)
            .into();
    }

    /// Set 32-bit block count, affecting next refill.
    #[inline(always)]
    pub(crate) fn seek32<M: Machine>(&mut self, m: M, blockct: u32) {
        let d: M::u32x4 = m.unpack(self.d);
        self.d = d.insert(blockct, 0).into();
    }

    /// Produce output from the current state.
    #[inline(always)]
    fn output_narrow<M: Machine>(&mut self, m: M, x: State<M::u32x4>, out: &mut [u8; BLOCK]) {
        let k = m.vec([0x6170_7865, 0x3320_646e, 0x7962_2d32, 0x6b20_6574]);
        (x.a + k).write_le(&mut out[0..16]);
        (x.b + m.unpack(self.b)).write_le(&mut out[16..32]);
        (x.c + m.unpack(self.c)).write_le(&mut out[32..48]);
        (x.d + m.unpack(self.d)).write_le(&mut out[48..64]);
    }

    /// Add one to the block counter (no overflow check).
    #[inline(always)]
    fn inc_block_ct<M: Machine>(&mut self, m: M) {
        let mut pos = self.pos64(m);
        let d0: M::u32x4 = m.unpack(self.d);
        pos += 1;
        let d1 = d0.insert((pos >> 32) as u32, 1).insert(pos as u32, 0);
        self.d = d1.into();
    }

    /// Produce 4 blocks of output, advancing the state
    #[inline(always)]
    pub fn refill4(&mut self, drounds: u32, out: &mut [u8; BUFSZ]) {
        refill_wide(self, drounds, out)
    }

    /// Produce a block of output, advancing the state
    #[inline(always)]
    pub fn refill(&mut self, drounds: u32, out: &mut [u8; BLOCK]) {
        refill_narrow(self, drounds, out)
    }

    #[inline(always)]
    pub(crate) fn refill_rounds(&mut self, drounds: u32) -> State<vec128_storage> {
        refill_narrow_rounds(self, drounds)
    }

    #[inline(always)]
    pub fn set_stream_param(&mut self, param: u32, value: u64) {
        set_stream_param(self, param, value)
    }

    #[inline(always)]
    pub fn get_stream_param(&self, param: u32) -> u64 {
        get_stream_param(self, param)
    }
}

#[inline(always)]
fn refill_wide_impl<Mach: Machine>(
    m: Mach,
    state: &mut ChaCha,
    drounds: u32,
    out: &mut [u8; BUFSZ],
) {
    let k = m.vec([0x6170_7865, 0x3320_646e, 0x7962_2d32, 0x6b20_6574]);
    let mut pos = state.pos64(m);
    let d0: Mach::u32x4 = m.unpack(state.d);
    pos += 1;
    let d1 = d0.insert((pos >> 32) as u32, 1).insert(pos as u32, 0);
    pos += 1;
    let d2 = d0.insert((pos >> 32) as u32, 1).insert(pos as u32, 0);
    pos += 1;
    let d3 = d0.insert((pos >> 32) as u32, 1).insert(pos as u32, 0);

    let b = m.unpack(state.b);
    let c = m.unpack(state.c);
    let mut x = State {
        a: Mach::u32x4x4::from_lanes([k, k, k, k]),
        b: Mach::u32x4x4::from_lanes([b, b, b, b]),
        c: Mach::u32x4x4::from_lanes([c, c, c, c]),
        d: m.unpack(Mach::u32x4x4::from_lanes([d0, d1, d2, d3]).into()),
    };
    for _ in 0..drounds {
        x = round(x);
        x = undiagonalize(round(diagonalize(x)));
    }
    let mut pos = state.pos64(m);
    let d0: Mach::u32x4 = m.unpack(state.d);
    pos += 1;
    let d1 = d0.insert((pos >> 32) as u32, 1).insert(pos as u32, 0);
    pos += 1;
    let d2 = d0.insert((pos >> 32) as u32, 1).insert(pos as u32, 0);
    pos += 1;
    let d3 = d0.insert((pos >> 32) as u32, 1).insert(pos as u32, 0);
    pos += 1;
    let d4 = d0.insert((pos >> 32) as u32, 1).insert(pos as u32, 0);

    let (a, b, c, d) = (
        x.a.to_lanes(),
        x.b.to_lanes(),
        x.c.to_lanes(),
        x.d.to_lanes(),
    );
    let sb = m.unpack(state.b);
    let sc = m.unpack(state.c);
    let sd = [m.unpack(state.d), d1, d2, d3];
    state.d = d4.into();
    let mut words = out.chunks_exact_mut(16);
    for ((((&a, &b), &c), &d), &sd) in a.iter().zip(&b).zip(&c).zip(&d).zip(&sd) {
        (a + k).write_le(words.next().unwrap());
        (b + sb).write_le(words.next().unwrap());
        (c + sc).write_le(words.next().unwrap());
        (d + sd).write_le(words.next().unwrap());
    }
}

dispatch!(m, Mach, {
    fn refill_wide(state: &mut ChaCha, drounds: u32, out: &mut [u8; BUFSZ]) {
        refill_wide_impl(m, state, drounds, out);
    }
});

/// Refill the buffer from a single-block round, updating the block count.
dispatch_light128!(m, Mach, {
    fn refill_narrow(state: &mut ChaCha, drounds: u32, out: &mut [u8; BLOCK]) {
        let x = refill_narrow_rounds(state, drounds);
        let x = State {
            a: m.unpack(x.a),
            b: m.unpack(x.b),
            c: m.unpack(x.c),
            d: m.unpack(x.d),
        };
        state.output_narrow(m, x, out);
        state.inc_block_ct(m);
    }
});

/// Single-block, rounds-only; shared by try_apply_keystream for tails shorter than BUFSZ
/// and XChaCha's setup step.
dispatch!(m, Mach, {
    fn refill_narrow_rounds(state: &mut ChaCha, drounds: u32) -> State<vec128_storage> {
        let k: Mach::u32x4 = m.vec([0x6170_7865, 0x3320_646e, 0x7962_2d32, 0x6b20_6574]);
        let mut x = State {
            a: k,
            b: m.unpack(state.b),
            c: m.unpack(state.c),
            d: m.unpack(state.d),
        };
        for _ in 0..drounds {
            x = round(x);
            x = undiagonalize(round(diagonalize(x)));
        }
        State {
            a: x.a.into(),
            b: x.b.into(),
            c: x.c.into(),
            d: x.d.into(),
        }
    }
});

dispatch_light128!(m, Mach, {
    fn set_stream_param(state: &mut ChaCha, param: u32, value: u64) {
        let d: Mach::u32x4 = m.unpack(state.d);
        state.d = d
            .insert((value >> 32) as u32, (param << 1) | 1)
            .insert(value as u32, param << 1)
            .into();
    }
});

dispatch_light128!(m, Mach, {
    fn get_stream_param(state: &ChaCha, param: u32) -> u64 {
        let d: Mach::u32x4 = m.unpack(state.d);
        ((d.extract((param << 1) | 1) as u64) << 32) | d.extract(param << 1) as u64
    }
});

fn read_u32le(xs: &[u8]) -> u32 {
    assert_eq!(xs.len(), 4);
    u32::from(xs[0]) | (u32::from(xs[1]) << 8) | (u32::from(xs[2]) << 16) | (u32::from(xs[3]) << 24)
}

dispatch_light128!(m, Mach, {
    fn init_chacha(key: &[u8; 32], nonce: &[u8]) -> ChaCha {
        let ctr_nonce = [
            0,
            if nonce.len() == 12 {
                read_u32le(&nonce[0..4])
            } else {
                0
            },
            read_u32le(&nonce[nonce.len() - 8..nonce.len() - 4]),
            read_u32le(&nonce[nonce.len() - 4..]),
        ];
        let key0: Mach::u32x4 = m.read_le(&key[..16]);
        let key1: Mach::u32x4 = m.read_le(&key[16..]);
        ChaCha {
            b: key0.into(),
            c: key1.into(),
            d: ctr_nonce.into(),
        }
    }
});

dispatch_light128!(m, Mach, {
    fn init_chacha_x(key: &[u8; 32], nonce: &[u8; 24], rounds: u32) -> ChaCha {
        let key0: Mach::u32x4 = m.read_le(&key[..16]);
        let key1: Mach::u32x4 = m.read_le(&key[16..]);
        let nonce0: Mach::u32x4 = m.read_le(&nonce[..16]);
        let mut state = ChaCha {
            b: key0.into(),
            c: key1.into(),
            d: nonce0.into(),
        };
        let x = refill_narrow_rounds(&mut state, rounds);
        let ctr_nonce1 = [0, 0, read_u32le(&nonce[16..20]), read_u32le(&nonce[20..24])];
        state.b = x.a;
        state.c = x.d;
        state.d = ctr_nonce1.into();
        state
    }
});
<commit_msg>forgo simd for non-performance-sensitive functions<commit_after>#[cfg(feature = "rustcrypto_api")]
pub use stream_cipher::generic_array;

pub use ppv_lite86::Machine;
use ppv_lite86::{vec128_storage, ArithOps, BitOps32, LaneWords4, MultiLane, StoreBytes, Vec4};

pub(crate) const BLOCK: usize = 64;
pub(crate) const BLOCK64: u64 = BLOCK as u64;
const LOG2_BUFBLOCKS: u64 = 2;
const BUFBLOCKS: u64 = 1 << LOG2_BUFBLOCKS;
pub(crate) const BUFSZ64: u64 = BLOCK64 * BUFBLOCKS;
pub(crate) const BUFSZ: usize = BUFSZ64 as usize;

#[derive(Clone)]
pub struct ChaCha {
    pub(crate) b: vec128_storage,
    pub(crate) c: vec128_storage,
    pub(crate) d: vec128_storage,
}

#[derive(Clone)]
pub struct State<V> {
    pub(crate) a: V,
    pub(crate) b: V,
    pub(crate) c: V,
    pub(crate) d: V,
}

#[inline(always)]
pub(crate) fn round<V: ArithOps + BitOps32>(mut x: State<V>) -> State<V> {
    x.a += x.b;
    x.d = (x.d ^ x.a).rotate_each_word_right16();
    x.c += x.d;
    x.b = (x.b ^ x.c).rotate_each_word_right20();
    x.a += x.b;
    x.d = (x.d ^ x.a).rotate_each_word_right24();
    x.c += x.d;
    x.b = (x.b ^ x.c).rotate_each_word_right25();
    x
}

#[inline(always)]
pub(crate) fn diagonalize<V: LaneWords4>(mut x: State<V>) -> State<V> {
    // Since b has the critical data dependency, avoid rotating b to hide latency.
    //
    // The order of these statements is important for performance on pre-AVX2 Intel machines, which
    // are throughput-bound and operating near their superscalar limits during refill_wide. The
    // permutations here and in undiagonalize have been found in testing on Nehalem to be optimal.
    x.a = x.a.shuffle_lane_words1230();
    x.c = x.c.shuffle_lane_words3012();
    x.d = x.d.shuffle_lane_words2301();
    x
}

#[inline(always)]
pub(crate) fn undiagonalize<V: LaneWords4>(mut x: State<V>) -> State<V> {
    // The order of these statements is magic. See comment in diagonalize.
    x.c = x.c.shuffle_lane_words1230();
    x.d = x.d.shuffle_lane_words2301();
    x.a = x.a.shuffle_lane_words3012();
    x
}

impl ChaCha {
    pub fn new(key: &[u8; 32], nonce: &[u8]) -> Self {
        let ctr_nonce = [
            0,
            if nonce.len() == 12 {
                read_u32le(&nonce[0..4])
            } else {
                0
            },
            read_u32le(&nonce[nonce.len() - 8..nonce.len() - 4]),
            read_u32le(&nonce[nonce.len() - 4..]),
        ];
        let key0 = [
            read_u32le(&key[0..4]),
            read_u32le(&key[4..8]),
            read_u32le(&key[8..12]),
            read_u32le(&key[12..16]),
        ];
        let key1 = [
            read_u32le(&key[16..20]),
            read_u32le(&key[20..24]),
            read_u32le(&key[24..28]),
            read_u32le(&key[28..32]),
        ];

        ChaCha {
            b: key0.into(),
            c: key1.into(),
            d: ctr_nonce.into(),
        }
    }

    #[inline(always)]
    fn pos64<M: Machine>(&self, m: M) -> u64 {
        let d: M::u32x4 = m.unpack(self.d);
        ((d.extract(1) as u64) << 32) | d.extract(0) as u64
    }

    /// Set 64-bit block count, affecting next refill.
    #[inline(always)]
    pub(crate) fn seek64<M: Machine>(&mut self, m: M, blockct: u64) {
        let d: M::u32x4 = m.unpack(self.d);
        self.d = d
            .insert((blockct >> 32) as u32, 1)
            .insert(blockct as u32, 0)
            .into();
    }

    /// Set 32-bit block count, affecting next refill.
    #[inline(always)]
    pub(crate) fn seek32<M: Machine>(&mut self, m: M, blockct: u32) {
        let d: M::u32x4 = m.unpack(self.d);
        self.d = d.insert(blockct, 0).into();
    }

    /// Produce output from the current state.
    #[inline(always)]
    fn output_narrow<M: Machine>(&mut self, m: M, x: State<M::u32x4>, out: &mut [u8; BLOCK]) {
        let k = m.vec([0x6170_7865, 0x3320_646e, 0x7962_2d32, 0x6b20_6574]);
        (x.a + k).write_le(&mut out[0..16]);
        (x.b + m.unpack(self.b)).write_le(&mut out[16..32]);
        (x.c + m.unpack(self.c)).write_le(&mut out[32..48]);
        (x.d + m.unpack(self.d)).write_le(&mut out[48..64]);
    }

    /// Add one to the block counter (no overflow check).
    #[inline(always)]
    fn inc_block_ct<M: Machine>(&mut self, m: M) {
        let mut pos = self.pos64(m);
        let d0: M::u32x4 = m.unpack(self.d);
        pos += 1;
        let d1 = d0.insert((pos >> 32) as u32, 1).insert(pos as u32, 0);
        self.d = d1.into();
    }

    /// Produce 4 blocks of output, advancing the state
    #[inline(always)]
    pub fn refill4(&mut self, drounds: u32, out: &mut [u8; BUFSZ]) {
        refill_wide(self, drounds, out)
    }

    /// Produce a block of output, advancing the state
    #[inline(always)]
    pub fn refill(&mut self, drounds: u32, out: &mut [u8; BLOCK]) {
        refill_narrow(self, drounds, out)
    }

    #[inline(always)]
    pub(crate) fn refill_rounds(&mut self, drounds: u32) -> State<vec128_storage> {
        refill_narrow_rounds(self, drounds)
    }

    #[inline]
    pub fn set_stream_param(&mut self, param: u32, value: u64) {
        let mut d: [u32; 4] = self.d.into();
        let p0 = ((param << 1) | 1) as usize;
        let p1 = (param << 1) as usize;
        d[p0] = (value >> 32) as u32;
        d[p1] = value as u32;
        self.d = d.into();
    }

    #[inline]
    pub fn get_stream_param(&self, param: u32) -> u64 {
        let d: [u32; 4] = self.d.into();
        let p0 = ((param << 1) | 1) as usize;
        let p1 = (param << 1) as usize;
        ((d[p0] as u64) << 32) | d[p1] as u64
    }
}

#[inline(always)]
fn refill_wide_impl<Mach: Machine>(
    m: Mach,
    state: &mut ChaCha,
    drounds: u32,
    out: &mut [u8; BUFSZ],
) {
    let k = m.vec([0x6170_7865, 0x3320_646e, 0x7962_2d32, 0x6b20_6574]);
    let mut pos = state.pos64(m);
    let d0: Mach::u32x4 = m.unpack(state.d);
    pos += 1;
    let d1 = d0.insert((pos >> 32) as u32, 1).insert(pos as u32, 0);
    pos += 1;
    let d2 = d0.insert((pos >> 32) as u32, 1).insert(pos as u32, 0);
    pos += 1;
    let d3 = d0.insert((pos >> 32) as u32, 1).insert(pos as u32, 0);

    let b = m.unpack(state.b);
    let c = m.unpack(state.c);
    let mut x = State {
        a: Mach::u32x4x4::from_lanes([k, k, k, k]),
        b: Mach::u32x4x4::from_lanes([b, b, b, b]),
        c: Mach::u32x4x4::from_lanes([c, c, c, c]),
        d: m.unpack(Mach::u32x4x4::from_lanes([d0, d1, d2, d3]).into()),
    };
    for _ in 0..drounds {
        x = round(x);
        x = undiagonalize(round(diagonalize(x)));
    }
    let mut pos = state.pos64(m);
    let d0: Mach::u32x4 = m.unpack(state.d);
    pos += 1;
    let d1 = d0.insert((pos >> 32) as u32, 1).insert(pos as u32, 0);
    pos += 1;
    let d2 = d0.insert((pos >> 32) as u32, 1).insert(pos as u32, 0);
    pos += 1;
    let d3 = d0.insert((pos >> 32) as u32, 1).insert(pos as u32, 0);
    pos += 1;
    let d4 = d0.insert((pos >> 32) as u32, 1).insert(pos as u32, 0);

    let (a, b, c, d) = (
        x.a.to_lanes(),
        x.b.to_lanes(),
        x.c.to_lanes(),
        x.d.to_lanes(),
    );
    let sb = m.unpack(state.b);
    let sc = m.unpack(state.c);
    let sd = [m.unpack(state.d), d1, d2, d3];
    state.d = d4.into();
    let mut words = out.chunks_exact_mut(16);
    for ((((&a, &b), &c), &d), &sd) in a.iter().zip(&b).zip(&c).zip(&d).zip(&sd) {
        (a + k).write_le(words.next().unwrap());
        (b + sb).write_le(words.next().unwrap());
        (c + sc).write_le(words.next().unwrap());
        (d + sd).write_le(words.next().unwrap());
    }
}

dispatch!(m, Mach, {
    fn refill_wide(state: &mut ChaCha, drounds: u32, out: &mut [u8; BUFSZ]) {
        refill_wide_impl(m, state, drounds, out);
    }
});

/// Refill the buffer from a single-block round, updating the block count.
dispatch_light128!(m, Mach, {
    fn refill_narrow(state: &mut ChaCha, drounds: u32, out: &mut [u8; BLOCK]) {
        let x = refill_narrow_rounds(state, drounds);
        let x = State {
            a: m.unpack(x.a),
            b: m.unpack(x.b),
            c: m.unpack(x.c),
            d: m.unpack(x.d),
        };
        state.output_narrow(m, x, out);
        state.inc_block_ct(m);
    }
});

/// Single-block, rounds-only; shared by try_apply_keystream for tails shorter than BUFSZ
/// and XChaCha's setup step.
dispatch!(m, Mach, {
    fn refill_narrow_rounds(state: &mut ChaCha, drounds: u32) -> State<vec128_storage> {
        let k: Mach::u32x4 = m.vec([0x6170_7865, 0x3320_646e, 0x7962_2d32, 0x6b20_6574]);
        let mut x = State {
            a: k,
            b: m.unpack(state.b),
            c: m.unpack(state.c),
            d: m.unpack(state.d),
        };
        for _ in 0..drounds {
            x = round(x);
            x = undiagonalize(round(diagonalize(x)));
        }
        State {
            a: x.a.into(),
            b: x.b.into(),
            c: x.c.into(),
            d: x.d.into(),
        }
    }
});

fn read_u32le(xs: &[u8]) -> u32 {
    assert_eq!(xs.len(), 4);
    u32::from(xs[0]) | (u32::from(xs[1]) << 8) | (u32::from(xs[2]) << 16) | (u32::from(xs[3]) << 24)
}

dispatch_light128!(m, Mach, {
    fn init_chacha_x(key: &[u8; 32], nonce: &[u8; 24], rounds: u32) -> ChaCha {
        let key0: Mach::u32x4 = m.read_le(&key[..16]);
        let key1: Mach::u32x4 = m.read_le(&key[16..]);
        let nonce0: Mach::u32x4 = m.read_le(&nonce[..16]);
        let mut state = ChaCha {
            b: key0.into(),
            c: key1.into(),
            d: nonce0.into(),
        };
        let x = refill_narrow_rounds(&mut state, rounds);
        let ctr_nonce1 = [0, 0, read_u32le(&nonce[16..20]), read_u32le(&nonce[20..24])];
        state.b = x.a;
        state.c = x.d;
        state.d = ctr_nonce1.into();
        state
    }
});
<|endoftext|>