<commit_before>#![feature(box_syntax)]

#![unstable]

#[macro_use]
#[no_link]
extern crate compile_msg;

extern crate libc;

use std::ffi::{CString};
use std::sync::mpsc::{Sender};
use std::sync::Mutex;
use std::thread::Thread;

#[doc(hidden)]
pub mod ffi;

/// This static variable  will store the android_app* on creation, and set it back to 0 at
///  destruction.
/// Apart from this, the static is never written, so there is no risk of race condition.
static mut ANDROID_APP: *mut ffi::android_app = 0 as *mut ffi::android_app;

/// This is the structure that serves as user data in the android_app*
#[doc(hidden)]
struct Context {
    senders: Mutex<Vec<Sender<Event>>>,
}

/// An event triggered by the Android environment.
pub enum Event {
    EventUp,
    EventDown,
    EventMove(i32, i32),
}

impl Copy for Event {}

#[cfg(not(target_os = "android"))]
compile_note!("You are not compiling for Android");

#[macro_export]
macro_rules! android_start(
    ($main: ident) => (
        pub mod __android_start {
            extern crate android_glue;

            // this function is here because we are sure that it will be included by the linker
            // so we call app_dummy in it, in order to be sure that the native glue will be included
            #[start]
            pub fn start(_: int, _: *const *const u8) -> int {
                unsafe { android_glue::ffi::app_dummy() };
                1
            }

            #[no_mangle]
            #[inline(never)]
            #[allow(non_snake_case)]
            pub extern "C" fn android_main(app: *mut ()) {
                android_glue::android_main2(app, move|| super::$main());
            }
        }
    )
);

/// This is the function that must be called by `android_main`
#[doc(hidden)]
pub fn android_main2<F>(app: *mut (), main_function: F)
    where F: FnOnce(), F: Send
{
    use std::{mem, ptr};

    write_log("Entering android_main");

    unsafe { ANDROID_APP = std::mem::transmute(app) };
    let app: &mut ffi::android_app = unsafe { std::mem::transmute(app) };

    // creating the context that will be passed to the callback
    let context = Context { senders: Mutex::new(Vec::new()) };
    app.onAppCmd = commands_callback;
    app.onInputEvent = inputs_callback;
    app.userData = unsafe { std::mem::transmute(&context) };

    // executing the main function in parallel
    let g = Thread::spawn(move|| {
        std::io::stdio::set_stdout(box std::io::LineBufferedWriter::new(ToLogWriter));
        std::io::stdio::set_stderr(box std::io::LineBufferedWriter::new(ToLogWriter));
        main_function()
    });

    // polling for events forever
    // note that this must be done in the same thread as android_main because ALooper are
    //  thread-local
    unsafe {
        loop {
            let mut events = mem::uninitialized();
            let mut source = mem::uninitialized();

            // passing -1 means that we are blocking
            let ident = ffi::ALooper_pollAll(-1, ptr::null_mut(), &mut events,
                &mut source);

            // processing the event
            if !source.is_null() {
                let source: *mut ffi::android_poll_source = mem::transmute(source);
                ((*source).process)(ANDROID_APP, source);
            }
        }
    }

    // terminating the application
    unsafe { ANDROID_APP = 0 as *mut ffi::android_app };
}

/// Writer that will redirect what is written to it to the logs.
struct ToLogWriter;

impl Writer for ToLogWriter {
    fn write(&mut self, buf: &[u8]) -> std::io::IoResult<()> {
        let message = CString::from_slice(buf).as_slice_with_nul().as_ptr();
        let tag = b"RustAndroidGlueStdouterr";
        let tag = CString::from_slice(tag).as_slice_with_nul().as_ptr();
        unsafe { ffi::__android_log_write(3, tag, message) };
        Ok(())
    }
}

/// The callback for inputs.
pub extern fn inputs_callback(_: *mut ffi::android_app, event: *const ffi::AInputEvent)
    -> libc::int32_t
{
    fn send_event(event: Event) {
        let senders = get_context().senders.lock().ok().unwrap();
        for sender in senders.iter() {
            sender.send(event);
        }
    }
    fn get_xy(event: *const ffi::AInputEvent) -> (i32, i32) {
        let x = unsafe { ffi::AMotionEvent_getX(event, 0) };
        let y = unsafe { ffi::AMotionEvent_getY(event, 0) };
        (x as i32, y as i32)
    }
    let action = unsafe { ffi::AMotionEvent_getAction(event) };
    let action_code = action & ffi::AMOTION_EVENT_ACTION_MASK;
    match action_code {
        ffi::AMOTION_EVENT_ACTION_UP
            | ffi::AMOTION_EVENT_ACTION_OUTSIDE
            | ffi::AMOTION_EVENT_ACTION_CANCEL
            | ffi::AMOTION_EVENT_ACTION_POINTER_UP =>
        {
            send_event(Event::EventUp);
        },
        ffi::AMOTION_EVENT_ACTION_DOWN
            | ffi::AMOTION_EVENT_ACTION_POINTER_DOWN =>
        {
            let (x, y) = get_xy(event);
            send_event(Event::EventMove(x, y));
            send_event(Event::EventDown);
        },
        _ => {
            let (x, y) = get_xy(event);
            send_event(Event::EventMove(x, y));
        },
    }
    0
}

/// The callback for commands.
#[doc(hidden)]
pub extern fn commands_callback(_: *mut ffi::android_app, command: libc::int32_t) {
    let context = get_context();

    match command {
        ffi::APP_CMD_INIT_WINDOW => {

        },

        ffi::APP_CMD_SAVE_STATE => {

        },

        ffi::APP_CMD_TERM_WINDOW => {

        },

        ffi::APP_CMD_GAINED_FOCUS => {

        },

        ffi::APP_CMD_LOST_FOCUS => {

        },

        _ => ()
    }
}

/// Returns the current Context.
fn get_context() -> &'static Context {
    let context = unsafe { (*ANDROID_APP).userData };
    unsafe { std::mem::transmute(context) }
}

/// Adds a sender where events will be sent to.
pub fn add_sender(sender: Sender<Event>) {
    get_context().senders.lock().ok().unwrap().push(sender);
}

/// Returns a handle to the native window.
pub unsafe fn get_native_window() -> ffi::NativeWindowType {
    if ANDROID_APP.is_null() {
        panic!("The application was not initialized from android_main");
    }

    loop {
        let value = (*ANDROID_APP).window;
        if !value.is_null() {
            return value;
        }

        // spin-locking
        std::io::timer::sleep(std::time::Duration::milliseconds(10));
    }
}

///
pub fn write_log(message: &str) {
    let message = message.as_bytes();
    let message = CString::from_slice(message).as_slice_with_nul().as_ptr();
    let tag = b"RustAndroidGlueStdouterr";
    let tag = CString::from_slice(tag).as_slice_with_nul().as_ptr();
    unsafe { ffi::__android_log_write(3, tag, message) };
}

pub enum AssetError {
    AssetMissing,
    EmptyBuffer,
}

pub fn load_asset(filename: &str) -> Result<Vec<u8>, AssetError> {
    struct AssetCloser {
        asset: *const ffi::Asset,
    }

    impl Drop for AssetCloser {
        fn drop(&mut self) {
            unsafe {
                ffi::AAsset_close(self.asset)
            };
        }
    }

    unsafe fn get_asset_manager() -> *const ffi::AAssetManager {
        let app = &*ANDROID_APP;
        let activity = &*app.activity;
        activity.assetManager
    }

    let filename_c_str = CString::from_slice(filename.as_bytes())
        .as_slice_with_nul().as_ptr();
    let asset = unsafe {
        ffi::AAssetManager_open(
            get_asset_manager(), filename_c_str, ffi::MODE_STREAMING)
    };
    if asset.is_null() {
        return Err(AssetError::AssetMissing);
    }
    let _asset_closer = AssetCloser{asset: asset};
    let len = unsafe {
        ffi::AAsset_getLength(asset)
    };
    let buff = unsafe {
        ffi::AAsset_getBuffer(asset)
    };
    if buff.is_null() {
        return Err(AssetError::EmptyBuffer);
    }
    let vec = unsafe {
        Vec::from_raw_buf(buff as *const u8, len as usize)
    };
    Ok(vec)
}
<commit_msg>Replace #[macro_use] by #[plugin]<commit_after>#![feature(box_syntax)]
#![feature(plugin)]

#![unstable]

#[plugin]
#[no_link]
extern crate compile_msg;

extern crate libc;

use std::ffi::{CString};
use std::sync::mpsc::{Sender};
use std::sync::Mutex;
use std::thread::Thread;

#[doc(hidden)]
pub mod ffi;

/// This static variable  will store the android_app* on creation, and set it back to 0 at
///  destruction.
/// Apart from this, the static is never written, so there is no risk of race condition.
static mut ANDROID_APP: *mut ffi::android_app = 0 as *mut ffi::android_app;

/// This is the structure that serves as user data in the android_app*
#[doc(hidden)]
struct Context {
    senders: Mutex<Vec<Sender<Event>>>,
}

/// An event triggered by the Android environment.
pub enum Event {
    EventUp,
    EventDown,
    EventMove(i32, i32),
}

impl Copy for Event {}

#[cfg(not(target_os = "android"))]
compile_note!("You are not compiling for Android");

#[macro_export]
macro_rules! android_start(
    ($main: ident) => (
        pub mod __android_start {
            extern crate android_glue;

            // this function is here because we are sure that it will be included by the linker
            // so we call app_dummy in it, in order to be sure that the native glue will be included
            #[start]
            pub fn start(_: int, _: *const *const u8) -> int {
                unsafe { android_glue::ffi::app_dummy() };
                1
            }

            #[no_mangle]
            #[inline(never)]
            #[allow(non_snake_case)]
            pub extern "C" fn android_main(app: *mut ()) {
                android_glue::android_main2(app, move|| super::$main());
            }
        }
    )
);

/// This is the function that must be called by `android_main`
#[doc(hidden)]
pub fn android_main2<F>(app: *mut (), main_function: F)
    where F: FnOnce(), F: Send
{
    use std::{mem, ptr};

    write_log("Entering android_main");

    unsafe { ANDROID_APP = std::mem::transmute(app) };
    let app: &mut ffi::android_app = unsafe { std::mem::transmute(app) };

    // creating the context that will be passed to the callback
    let context = Context { senders: Mutex::new(Vec::new()) };
    app.onAppCmd = commands_callback;
    app.onInputEvent = inputs_callback;
    app.userData = unsafe { std::mem::transmute(&context) };

    // executing the main function in parallel
    let g = Thread::spawn(move|| {
        std::io::stdio::set_stdout(box std::io::LineBufferedWriter::new(ToLogWriter));
        std::io::stdio::set_stderr(box std::io::LineBufferedWriter::new(ToLogWriter));
        main_function()
    });

    // polling for events forever
    // note that this must be done in the same thread as android_main because ALooper are
    //  thread-local
    unsafe {
        loop {
            let mut events = mem::uninitialized();
            let mut source = mem::uninitialized();

            // passing -1 means that we are blocking
            let ident = ffi::ALooper_pollAll(-1, ptr::null_mut(), &mut events,
                &mut source);

            // processing the event
            if !source.is_null() {
                let source: *mut ffi::android_poll_source = mem::transmute(source);
                ((*source).process)(ANDROID_APP, source);
            }
        }
    }

    // terminating the application
    unsafe { ANDROID_APP = 0 as *mut ffi::android_app };
}

/// Writer that will redirect what is written to it to the logs.
struct ToLogWriter;

impl Writer for ToLogWriter {
    fn write(&mut self, buf: &[u8]) -> std::io::IoResult<()> {
        let message = CString::from_slice(buf).as_slice_with_nul().as_ptr();
        let tag = b"RustAndroidGlueStdouterr";
        let tag = CString::from_slice(tag).as_slice_with_nul().as_ptr();
        unsafe { ffi::__android_log_write(3, tag, message) };
        Ok(())
    }
}

/// The callback for inputs.
pub extern fn inputs_callback(_: *mut ffi::android_app, event: *const ffi::AInputEvent)
    -> libc::int32_t
{
    fn send_event(event: Event) {
        let senders = get_context().senders.lock().ok().unwrap();
        for sender in senders.iter() {
            sender.send(event);
        }
    }
    fn get_xy(event: *const ffi::AInputEvent) -> (i32, i32) {
        let x = unsafe { ffi::AMotionEvent_getX(event, 0) };
        let y = unsafe { ffi::AMotionEvent_getY(event, 0) };
        (x as i32, y as i32)
    }
    let action = unsafe { ffi::AMotionEvent_getAction(event) };
    let action_code = action & ffi::AMOTION_EVENT_ACTION_MASK;
    match action_code {
        ffi::AMOTION_EVENT_ACTION_UP
            | ffi::AMOTION_EVENT_ACTION_OUTSIDE
            | ffi::AMOTION_EVENT_ACTION_CANCEL
            | ffi::AMOTION_EVENT_ACTION_POINTER_UP =>
        {
            send_event(Event::EventUp);
        },
        ffi::AMOTION_EVENT_ACTION_DOWN
            | ffi::AMOTION_EVENT_ACTION_POINTER_DOWN =>
        {
            let (x, y) = get_xy(event);
            send_event(Event::EventMove(x, y));
            send_event(Event::EventDown);
        },
        _ => {
            let (x, y) = get_xy(event);
            send_event(Event::EventMove(x, y));
        },
    }
    0
}

/// The callback for commands.
#[doc(hidden)]
pub extern fn commands_callback(_: *mut ffi::android_app, command: libc::int32_t) {
    let context = get_context();

    match command {
        ffi::APP_CMD_INIT_WINDOW => {

        },

        ffi::APP_CMD_SAVE_STATE => {

        },

        ffi::APP_CMD_TERM_WINDOW => {

        },

        ffi::APP_CMD_GAINED_FOCUS => {

        },

        ffi::APP_CMD_LOST_FOCUS => {

        },

        _ => ()
    }
}

/// Returns the current Context.
fn get_context() -> &'static Context {
    let context = unsafe { (*ANDROID_APP).userData };
    unsafe { std::mem::transmute(context) }
}

/// Adds a sender where events will be sent to.
pub fn add_sender(sender: Sender<Event>) {
    get_context().senders.lock().ok().unwrap().push(sender);
}

/// Returns a handle to the native window.
pub unsafe fn get_native_window() -> ffi::NativeWindowType {
    if ANDROID_APP.is_null() {
        panic!("The application was not initialized from android_main");
    }

    loop {
        let value = (*ANDROID_APP).window;
        if !value.is_null() {
            return value;
        }

        // spin-locking
        std::io::timer::sleep(std::time::Duration::milliseconds(10));
    }
}

///
pub fn write_log(message: &str) {
    let message = message.as_bytes();
    let message = CString::from_slice(message).as_slice_with_nul().as_ptr();
    let tag = b"RustAndroidGlueStdouterr";
    let tag = CString::from_slice(tag).as_slice_with_nul().as_ptr();
    unsafe { ffi::__android_log_write(3, tag, message) };
}

pub enum AssetError {
    AssetMissing,
    EmptyBuffer,
}

pub fn load_asset(filename: &str) -> Result<Vec<u8>, AssetError> {
    struct AssetCloser {
        asset: *const ffi::Asset,
    }

    impl Drop for AssetCloser {
        fn drop(&mut self) {
            unsafe {
                ffi::AAsset_close(self.asset)
            };
        }
    }

    unsafe fn get_asset_manager() -> *const ffi::AAssetManager {
        let app = &*ANDROID_APP;
        let activity = &*app.activity;
        activity.assetManager
    }

    let filename_c_str = CString::from_slice(filename.as_bytes())
        .as_slice_with_nul().as_ptr();
    let asset = unsafe {
        ffi::AAssetManager_open(
            get_asset_manager(), filename_c_str, ffi::MODE_STREAMING)
    };
    if asset.is_null() {
        return Err(AssetError::AssetMissing);
    }
    let _asset_closer = AssetCloser{asset: asset};
    let len = unsafe {
        ffi::AAsset_getLength(asset)
    };
    let buff = unsafe {
        ffi::AAsset_getBuffer(asset)
    };
    if buff.is_null() {
        return Err(AssetError::EmptyBuffer);
    }
    let vec = unsafe {
        Vec::from_raw_buf(buff as *const u8, len as usize)
    };
    Ok(vec)
}
<|endoftext|>


<commit_before>//! This module is strictly internal.
//!
//! These functions are used by `date()`, `time()` and `datetime()`.
//! They are currently not private, because the need to be accessible,
//! but are not useful by themselves.
//!
//! Please refer to the top-level functions instead, as they offer a better abstraction.
//!
//! **These functions may be made private later.**

use core::str;

use nom::{
    branch::alt,
    bytes::complete::{tag, take_while, take_while_m_n},
    character::complete::one_of,
    character::is_digit,
    combinator::{map, not, opt},
    sequence::{preceded, terminated},
    IResult,
};

use crate::{Date, DateTime, Duration, Time};

#[cfg(test)]
mod tests;

// UTILITY

fn take_digits(i: &[u8]) -> IResult<&[u8], u32> {
    let (i, digits) = take_while(is_digit)(i)?;

    if digits.is_empty() {
        return Err(nom::Err::Error((i, nom::error::ErrorKind::Eof)));
    }

    let s = str::from_utf8(digits).expect("Invalid data, expected UTF-8 string");
    let res = s
        .parse()
        .expect("Invalid string, expected ASCII representation of a number");

    Ok((i, res))
}

fn take_n_digits(i: &[u8], n: usize) -> IResult<&[u8], u32> {
    let (i, digits) = take_while_m_n(n, n, is_digit)(i)?;

    let s = str::from_utf8(digits).expect("Invalid data, expected UTF-8 string");
    let res = s
        .parse()
        .expect("Invalid string, expected ASCII representation of a number");

    Ok((i, res))
}

fn take_m_to_n_digits(i: &[u8], m: usize, n: usize) -> IResult<&[u8], u32> {
    let (i, digits) = take_while_m_n(m, n, is_digit)(i)?;

    let s = str::from_utf8(digits).expect("Invalid data, expected UTF-8 string");
    let res = s
        .parse()
        .expect("Invalid string, expected ASCII representation of a number");

    Ok((i, res))
}

fn n_digit_in_range(
    i: &[u8],
    n: usize,
    range: impl core::ops::RangeBounds<u32>,
) -> IResult<&[u8], u32> {
    let (new_i, number) = take_n_digits(i, n)?;

    if range.contains(&number) {
        Ok((new_i, number))
    } else {
        Err(nom::Err::Error((i, nom::error::ErrorKind::Eof)))
    }
}

fn m_to_n_digit_in_range(
    i: &[u8],
    m: usize,
    n: usize,
    range: impl core::ops::RangeBounds<u32>,
) -> IResult<&[u8], u32> {
    let (new_i, number) = take_m_to_n_digits(i, m, n)?;

    if range.contains(&number) {
        Ok((new_i, number))
    } else {
        Err(nom::Err::Error((i, nom::error::ErrorKind::Eof)))
    }
}

fn sign(i: &[u8]) -> IResult<&[u8], i32> {
    map(alt((tag(b"-"), tag(b"+"))), |s: &[u8]| match s {
        b"-" => -1,
        _ => 1,
    })(i)
}

fn fractions(i: &[u8]) -> IResult<&[u8], f32> {
    let (i, digits) = take_while(is_digit)(i)?;
    let digits = str::from_utf8(digits).unwrap(); // This can't panic, `digits` will only include digits.
    let f = format!("0.{}", digits).parse().unwrap(); // This can't panic, the string is a valid `f32`.

    Ok((i, f))
}

// DATE

// [+/-]YYYY
fn date_year(i: &[u8]) -> IResult<&[u8], i32> {
    // The sign is optional, but defaults to `+`
    let (i, s) = sign(i).unwrap_or((i, 1));
    let (i, year) = take_n_digits(i, 4)?;
    let year = s * year as i32;

    Ok((i, year))
}

// MM
fn date_month(i: &[u8]) -> IResult<&[u8], u32> {
    n_digit_in_range(i, 2, 1..=12)
}

// DD
fn date_day(i: &[u8]) -> IResult<&[u8], u32> {
    n_digit_in_range(i, 2, 1..=31)
}

// WW
fn date_week(i: &[u8]) -> IResult<&[u8], u32> {
    n_digit_in_range(i, 2, 1..=52)
}

fn date_week_day(i: &[u8]) -> IResult<&[u8], u32> {
    n_digit_in_range(i, 1, 1..=7)
}

// ordinal DDD
fn date_ord_day(i: &[u8]) -> IResult<&[u8], u32> {
    n_digit_in_range(i, 3, 1..=366)
}

// YYYY-MM-DD
fn date_ymd(i: &[u8]) -> IResult<&[u8], Date> {
    let (i, y) = date_year(i)?;
    let (i, _) = opt(tag(b"-"))(i)?;
    let (i, m) = date_month(i)?;
    let (i, _) = opt(tag(b"-"))(i)?;
    let (i, d) = date_day(i)?;

    Ok((
        i,
        Date::YMD {
            year: y,
            month: m,
            day: d,
        },
    ))
}

// YYYY-DDD
fn date_ordinal(i: &[u8]) -> IResult<&[u8], Date> {
    let (i, y) = date_year(i)?;
    let (i, _) = opt(tag(b"-"))(i)?;
    let (i, d) = date_ord_day(i)?;

    Ok((i, Date::Ordinal { year: y, ddd: d }))
}

// YYYY-"W"WW-D
fn date_iso_week(i: &[u8]) -> IResult<&[u8], Date> {
    let (i, y) = date_year(i)?;
    let (i, _) = opt(tag(b"-"))(i)?;
    let (i, _) = tag(b"W")(i)?;
    let (i, w) = date_week(i)?;
    let (i, _) = opt(tag(b"-"))(i)?;
    let (i, d) = date_week_day(i)?;

    Ok((
        i,
        Date::Week {
            year: y,
            ww: w,
            d: d,
        },
    ))
}

pub fn parse_date(i: &[u8]) -> IResult<&[u8], Date> {
    alt((date_ymd, date_iso_week, date_ordinal))(i)
}

// TIME

// HH
fn time_hour(i: &[u8]) -> IResult<&[u8], u32> {
    n_digit_in_range(i, 2, 0..=24)
}

// MM
fn time_minute(i: &[u8]) -> IResult<&[u8], u32> {
    n_digit_in_range(i, 2, 0..=59)
}

// SS
fn time_second(i: &[u8]) -> IResult<&[u8], u32> {
    n_digit_in_range(i, 2, 0..=60)
}

fn time_millisecond(fraction: f32) -> u32 {
    (1000.0 * fraction) as u32
}

// HH:MM:[SS][.(m*)][(Z|+...|-...)]
pub fn parse_time(i: &[u8]) -> IResult<&[u8], Time> {
    let (i, h) = time_hour(i)?;
    let (i, _) = opt(tag(b":"))(i)?;
    let (i, m) = time_minute(i)?;
    let (i, s) = opt(preceded(opt(tag(b":")), time_second))(i)?;
    let (i, ms) = opt(map(preceded(one_of(",."), fractions), time_millisecond))(i)?;
    let (i, z) = match opt(alt((timezone_hour, timezone_utc)))(i) {
        Ok(ok) => ok,
        Err(nom::Err::Incomplete(_)) => (i, None),
        Err(e) => return Err(e),
    };

    let (tz_offset_hours, tz_offset_minutes) = z.unwrap_or((0, 0));

    Ok((
        i,
        Time {
            hour: h,
            minute: m,
            second: s.unwrap_or(0),
            millisecond: ms.unwrap_or(0),
            tz_offset_hours,
            tz_offset_minutes,
        },
    ))
}

fn timezone_hour(i: &[u8]) -> IResult<&[u8], (i32, i32)> {
    let (i, s) = sign(i)?;
    let (i, h) = time_hour(i)?;
    let (i, m) = if i.is_empty() {
        (i, 0)
    } else {
        let (i, _) = opt(tag(b":"))(i)?;
        time_minute(i)?
    };

    Ok((i, ((s * (h as i32), s * (m as i32)))))
}

fn timezone_utc(i: &[u8]) -> IResult<&[u8], (i32, i32)> {
    map(tag(b"Z"), |_| (0, 0))(i)
}

// Full ISO8601 datetime
pub fn parse_datetime(i: &[u8]) -> IResult<&[u8], DateTime> {
    let (i, d) = parse_date(i)?;
    let (i, _) = tag(b"T")(i)?;
    let (i, t) = parse_time(i)?;

    Ok((i, DateTime { date: d, time: t }))
}

// DURATION

// Y[YYY...]
fn duration_year(i: &[u8]) -> IResult<&[u8], u32> {
    take_digits(i)
}

// M[M]
fn duration_month(i: &[u8]) -> IResult<&[u8], u32> {
    m_to_n_digit_in_range(i, 1, 2, 0..=12)
}

// W[W]
fn duration_week(i: &[u8]) -> IResult<&[u8], u32> {
    m_to_n_digit_in_range(i, 1, 2, 0..=52)
}

// D[D]
fn duration_day(i: &[u8]) -> IResult<&[u8], u32> {
    m_to_n_digit_in_range(i, 1, 2, 0..=31)
}

// H[H]
fn duration_hour(i: &[u8]) -> IResult<&[u8], u32> {
    m_to_n_digit_in_range(i, 1, 2, 0..=24)
}

// M[M]
fn duration_minute(i: &[u8]) -> IResult<&[u8], u32> {
    m_to_n_digit_in_range(i, 1, 2, 0..=60)
}

// S[S][[,.][MS]]
fn duration_second_and_millisecond(i: &[u8]) -> IResult<&[u8], (u32, u32)> {
    let (i, s) = m_to_n_digit_in_range(i, 1, 2, 0..=60)?;
    let (i, ms) = opt(map(preceded(one_of(",."), fractions), duration_millisecond))(i)?;

    Ok((i, (s, ms.unwrap_or(0))))
}

fn duration_millisecond(fraction: f32) -> u32 {
    (1000.0 * fraction) as u32
}

fn duration_time(i: &[u8]) -> IResult<&[u8], (u32, u32, u32, u32)> {
    let (i, h) = opt(terminated(duration_hour, tag(b"H")))(i)?;
    let (i, m) = opt(terminated(duration_minute, tag(b"M")))(i)?;
    let (i, s) = opt(terminated(duration_second_and_millisecond, tag(b"S")))(i)?;
    let (s, ms) = s.unwrap_or((0, 0));

    Ok((i, (h.unwrap_or(0), m.unwrap_or(0), s, ms)))
}

fn duration_ymdhms(i: &[u8]) -> IResult<&[u8], Duration> {
    let (i, _) = tag(b"P")(i)?;
    let (i, y) = opt(terminated(duration_year, tag(b"Y")))(i)?;
    let (i, mo) = opt(terminated(duration_month, tag(b"M")))(i)?;
    let (i, d) = opt(terminated(duration_day, tag(b"D")))(i)?;
    let (i, time) = opt(preceded(tag(b"T"), duration_time))(i)?;

    // at least one element must be present for a valid duration representation
    if y.is_none() && mo.is_none() && d.is_none() && time.is_none() {
        return Err(nom::Err::Error((i, nom::error::ErrorKind::Eof)));
    }

    let (h, mi, s, ms) = time.unwrap_or((0, 0, 0, 0));

    Ok((
        i,
        Duration::YMDHMS {
            year: y.unwrap_or(0),
            month: mo.unwrap_or(0),
            day: d.unwrap_or(0),
            hour: h,
            minute: mi,
            second: s,
            millisecond: ms,
        },
    ))
}

fn duration_weeks(i: &[u8]) -> IResult<&[u8], Duration> {
    let (i, _) = tag(b"P")(i)?;
    let (i, w) = terminated(duration_week, tag(b"W"))(i)?;

    Ok((i, Duration::Weeks(w)))
}

// YYYY, no sign
fn duration_datetime_year(i: &[u8]) -> IResult<&[u8], u32> {
    take_n_digits(i, 4)
}

fn duration_datetime(i: &[u8]) -> IResult<&[u8], Duration> {
    let (i, _) = tag(b"P")(i)?;
    let (i, _) = not(sign)(i)?;
    let (i, y) = duration_datetime_year(i)?;
    let (i, _) = opt(tag(b"-"))(i)?;
    let (i, m) = date_month(i)?;
    let (i, _) = opt(tag(b"-"))(i)?;
    let (i, d) = date_day(i)?;
    let (i, _) = tag(b"T")(i)?;
    let (i, t) = parse_time(i)?;

    Ok((
        i,
        Duration::YMDHMS {
            year: y,
            month: m,
            day: d,
            hour: t.hour,
            minute: t.minute,
            second: t.second,
            millisecond: t.millisecond,
        },
    ))
}

pub fn parse_duration(i: &[u8]) -> IResult<&[u8], Duration> {
    alt((duration_ymdhms, duration_weeks, duration_datetime))(i)
}
<commit_msg>apply some higher level parsers<commit_after>//! This module is strictly internal.
//!
//! These functions are used by `date()`, `time()` and `datetime()`.
//! They are currently not private, because the need to be accessible,
//! but are not useful by themselves.
//!
//! Please refer to the top-level functions instead, as they offer a better abstraction.
//!
//! **These functions may be made private later.**

use core::str;

use nom::{
    branch::alt,
    bytes::complete::{tag, take_while, take_while_m_n},
    character::complete::one_of,
    character::is_digit,
    combinator::{map, map_res, not, opt},
    sequence::{preceded, separated_pair, terminated, tuple},
    IResult,
};

use crate::{Date, DateTime, Duration, Time};

#[cfg(test)]
mod tests;

// UTILITY

fn take_digits(i: &[u8]) -> IResult<&[u8], u32> {
    let (i, digits) = take_while(is_digit)(i)?;

    if digits.is_empty() {
        return Err(nom::Err::Error((i, nom::error::ErrorKind::Eof)));
    }

    let s = str::from_utf8(digits).expect("Invalid data, expected UTF-8 string");
    let res = s
        .parse()
        .expect("Invalid string, expected ASCII representation of a number");

    Ok((i, res))
}

fn take_n_digits(i: &[u8], n: usize) -> IResult<&[u8], u32> {
    let (i, digits) = take_while_m_n(n, n, is_digit)(i)?;

    let s = str::from_utf8(digits).expect("Invalid data, expected UTF-8 string");
    let res = s
        .parse()
        .expect("Invalid string, expected ASCII representation of a number");

    Ok((i, res))
}

fn take_m_to_n_digits(i: &[u8], m: usize, n: usize) -> IResult<&[u8], u32> {
    let (i, digits) = take_while_m_n(m, n, is_digit)(i)?;

    let s = str::from_utf8(digits).expect("Invalid data, expected UTF-8 string");
    let res = s
        .parse()
        .expect("Invalid string, expected ASCII representation of a number");

    Ok((i, res))
}

fn n_digit_in_range(
    i: &[u8],
    n: usize,
    range: impl core::ops::RangeBounds<u32>,
) -> IResult<&[u8], u32> {
    let (new_i, number) = take_n_digits(i, n)?;

    if range.contains(&number) {
        Ok((new_i, number))
    } else {
        Err(nom::Err::Error((i, nom::error::ErrorKind::Eof)))
    }
}

fn m_to_n_digit_in_range(
    i: &[u8],
    m: usize,
    n: usize,
    range: impl core::ops::RangeBounds<u32>,
) -> IResult<&[u8], u32> {
    let (new_i, number) = take_m_to_n_digits(i, m, n)?;

    if range.contains(&number) {
        Ok((new_i, number))
    } else {
        Err(nom::Err::Error((i, nom::error::ErrorKind::Eof)))
    }
}

fn sign(i: &[u8]) -> IResult<&[u8], i32> {
    map(alt((tag(b"-"), tag(b"+"))), |s: &[u8]| match s {
        b"-" => -1,
        _ => 1,
    })(i)
}

fn fractions(i: &[u8]) -> IResult<&[u8], f32> {
    let (i, digits) = take_while(is_digit)(i)?;
    let digits = str::from_utf8(digits).unwrap(); // This can't panic, `digits` will only include digits.
    let f = format!("0.{}", digits).parse().unwrap(); // This can't panic, the string is a valid `f32`.

    Ok((i, f))
}

// DATE

// [+/-]YYYY
fn date_year(i: &[u8]) -> IResult<&[u8], i32> {
    // The sign is optional, but defaults to `+`
    map(
        tuple((
            opt(sign),               // [+/-]
            |i| take_n_digits(i, 4), // year
        )),
        |(s, year)| s.unwrap_or(1) * year as i32,
    )(i)
}

// MM
fn date_month(i: &[u8]) -> IResult<&[u8], u32> {
    n_digit_in_range(i, 2, 1..=12)
}

// DD
fn date_day(i: &[u8]) -> IResult<&[u8], u32> {
    n_digit_in_range(i, 2, 1..=31)
}

// WW
fn date_week(i: &[u8]) -> IResult<&[u8], u32> {
    n_digit_in_range(i, 2, 1..=52)
}

fn date_week_day(i: &[u8]) -> IResult<&[u8], u32> {
    n_digit_in_range(i, 1, 1..=7)
}

// ordinal DDD
fn date_ord_day(i: &[u8]) -> IResult<&[u8], u32> {
    n_digit_in_range(i, 3, 1..=366)
}

// YYYY-MM-DD
fn date_ymd(i: &[u8]) -> IResult<&[u8], Date> {
    map(
        tuple((
            date_year,      // YYYY
            opt(tag(b"-")), // -
            date_month,     // MM
            opt(tag(b"-")), // -
            date_day,       //DD
        )),
        |(year, _, month, _, day)| Date::YMD { year, month, day },
    )(i)
}

// YYYY-DDD
fn date_ordinal(i: &[u8]) -> IResult<&[u8], Date> {
    map(
        separated_pair(date_year, opt(tag(b"-")), date_ord_day),
        |(year, ddd)| Date::Ordinal { year, ddd },
    )(i)
}

// YYYY-"W"WW-D
fn date_iso_week(i: &[u8]) -> IResult<&[u8], Date> {
    map(
        tuple((
            date_year,                          // y
            tuple((opt(tag(b"-")), tag(b"W"))), // [-]W
            date_week,                          // w
            opt(tag(b"-")),                     // [-]
            date_week_day,                      // d
        )),
        |(year, _, ww, _, d)| Date::Week { year, ww, d },
    )(i)
}

pub fn parse_date(i: &[u8]) -> IResult<&[u8], Date> {
    alt((date_ymd, date_iso_week, date_ordinal))(i)
}

// TIME

// HH
fn time_hour(i: &[u8]) -> IResult<&[u8], u32> {
    n_digit_in_range(i, 2, 0..=24)
}

// MM
fn time_minute(i: &[u8]) -> IResult<&[u8], u32> {
    n_digit_in_range(i, 2, 0..=59)
}

// SS
fn time_second(i: &[u8]) -> IResult<&[u8], u32> {
    n_digit_in_range(i, 2, 0..=60)
}

fn time_millisecond(fraction: f32) -> u32 {
    (1000.0 * fraction) as u32
}

// HH:MM:[SS][.(m*)][(Z|+...|-...)]
pub fn parse_time(i: &[u8]) -> IResult<&[u8], Time> {
    map(
        tuple((
            time_hour,                                                     // HH
            opt(tag(b":")),                                                // :
            time_minute,                                                   // MM
            opt(preceded(opt(tag(b":")), time_second)),                    // [SS]
            opt(map(preceded(one_of(",."), fractions), time_millisecond)), // [.(m*)]
            opt(alt((timezone_hour, timezone_utc))),                       // [(Z|+...|-...)]
        )),
        |(h, _, m, s, ms, z)| {
            let (tz_offset_hours, tz_offset_minutes) = z.unwrap_or((0, 0));

            Time {
                hour: h,
                minute: m,
                second: s.unwrap_or(0),
                millisecond: ms.unwrap_or(0),
                tz_offset_hours,
                tz_offset_minutes,
            }
        },
    )(i)
}

fn timezone_hour(i: &[u8]) -> IResult<&[u8], (i32, i32)> {
    map(
        tuple((sign, time_hour, opt(preceded(opt(tag(b":")), time_minute)))),
        |(s, h, m)| (s * (h as i32), s * (m.unwrap_or(0) as i32)),
    )(i)
}

fn timezone_utc(i: &[u8]) -> IResult<&[u8], (i32, i32)> {
    map(tag(b"Z"), |_| (0, 0))(i)
}

// Full ISO8601 datetime
pub fn parse_datetime(i: &[u8]) -> IResult<&[u8], DateTime> {
    map(
        separated_pair(parse_date, tag(b"T"), parse_time),
        |(d, t)| DateTime { date: d, time: t },
    )(i)
}

// DURATION

// Y[YYY...]
fn duration_year(i: &[u8]) -> IResult<&[u8], u32> {
    take_digits(i)
}

// M[M]
fn duration_month(i: &[u8]) -> IResult<&[u8], u32> {
    m_to_n_digit_in_range(i, 1, 2, 0..=12)
}

// W[W]
fn duration_week(i: &[u8]) -> IResult<&[u8], u32> {
    m_to_n_digit_in_range(i, 1, 2, 0..=52)
}

// D[D]
fn duration_day(i: &[u8]) -> IResult<&[u8], u32> {
    m_to_n_digit_in_range(i, 1, 2, 0..=31)
}

// H[H]
fn duration_hour(i: &[u8]) -> IResult<&[u8], u32> {
    m_to_n_digit_in_range(i, 1, 2, 0..=24)
}

// M[M]
fn duration_minute(i: &[u8]) -> IResult<&[u8], u32> {
    m_to_n_digit_in_range(i, 1, 2, 0..=60)
}

// S[S][[,.][MS]]
fn duration_second_and_millisecond(i: &[u8]) -> IResult<&[u8], (u32, u32)> {
    let (i, s) = m_to_n_digit_in_range(i, 1, 2, 0..=60)?;
    let (i, ms) = opt(map(preceded(one_of(",."), fractions), duration_millisecond))(i)?;

    Ok((i, (s, ms.unwrap_or(0))))
}

fn duration_millisecond(fraction: f32) -> u32 {
    (1000.0 * fraction) as u32
}

fn duration_time(i: &[u8]) -> IResult<&[u8], (u32, u32, u32, u32)> {
    map(
        tuple((
            opt(terminated(duration_hour, tag(b"H"))),
            opt(terminated(duration_minute, tag(b"M"))),
            opt(terminated(duration_second_and_millisecond, tag(b"S"))),
        )),
        |(h, m, s)| {
            let (s, ms) = s.unwrap_or((0, 0));

            (h.unwrap_or(0), m.unwrap_or(0), s, ms)
        },
    )(i)
}

fn duration_ymdhms(i: &[u8]) -> IResult<&[u8], Duration> {
    map_res(
        preceded(
            tag(b"P"),
            tuple((
                opt(terminated(duration_year, tag(b"Y"))),
                opt(terminated(duration_month, tag(b"M"))),
                opt(terminated(duration_day, tag(b"D"))),
                opt(preceded(tag(b"T"), duration_time)),
            )),
        ),
        |(y, mo, d, time)| {
            // at least one element must be present for a valid duration representation
            if y.is_none() && mo.is_none() && d.is_none() && time.is_none() {
                return Err(nom::Err::Error((i, nom::error::ErrorKind::Eof)));
            }

            let (h, mi, s, ms) = time.unwrap_or((0, 0, 0, 0));

            Ok(Duration::YMDHMS {
                year: y.unwrap_or(0),
                month: mo.unwrap_or(0),
                day: d.unwrap_or(0),
                hour: h,
                minute: mi,
                second: s,
                millisecond: ms,
            })
        },
    )(i)
}

fn duration_weeks(i: &[u8]) -> IResult<&[u8], Duration> {
    map(
        preceded(tag(b"P"), terminated(duration_week, tag(b"W"))),
        Duration::Weeks,
    )(i)
}

// YYYY, no sign
fn duration_datetime_year(i: &[u8]) -> IResult<&[u8], u32> {
    take_n_digits(i, 4)
}

fn duration_datetime(i: &[u8]) -> IResult<&[u8], Duration> {
    map(
        preceded(
            tuple((tag(b"P"), not(sign))),
            tuple((
                duration_datetime_year,
                opt(tag(b"-")),
                date_month,
                opt(tag(b"-")),
                date_day,
                tag(b"T"),
                parse_time,
            )),
        ),
        |(year, _, month, _, day, _, t)| Duration::YMDHMS {
            year,
            month,
            day,
            hour: t.hour,
            minute: t.minute,
            second: t.second,
            millisecond: t.millisecond,
        },
    )(i)
}

pub fn parse_duration(i: &[u8]) -> IResult<&[u8], Duration> {
    alt((duration_ymdhms, duration_weeks, duration_datetime))(i)
}
<|endoftext|>


<commit_before>use spin::Mutex;
use cpuio::{Port, UnsafePort};

// PIC ports
const PIC1_COMMAND: u16 = 0x20;
const PIC2_COMMAND: u16 = 0xA0;
const PIC1_DATA:    u16 = 0x21;
const PIC2_DATA:    u16 = 0xA1;

// PIC commands
const PIC_CMD_EOI:  u8 = 0x20;
const PIC_CMD_INIT: u8 = 0x11;

struct Pic {
    offset: u8,
    command_port: UnsafePort<u8>,
    data_port: UnsafePort<u8>,
}

impl Pic {
    fn handles_interrupt(&self, interupt_id: u8) -> bool {
        self.offset <= interupt_id && interupt_id < self.offset + 8
    }
    /// Send end of interrupt signal to pic
    unsafe fn send_eoi(&mut self) {
        self.command_port.write(PIC_CMD_EOI);
    }
}

pub struct ChainedPics {
    pics: [Pic; 2],
}

impl ChainedPics {
    pub const unsafe fn new(pic1_offset: u8, pic2_offset: u8) -> ChainedPics {
        ChainedPics {
            pics: [
                Pic {
                    offset: pic1_offset,
                    command_port:   UnsafePort::new(PIC1_COMMAND),
                    data_port:      UnsafePort::new(PIC1_DATA),
                },
                Pic {
                    offset: pic2_offset,
                    command_port:   UnsafePort::new(PIC2_COMMAND),
                    data_port:      UnsafePort::new(PIC2_DATA),
                },
            ]
        }
    }
    /// Init - remap irqs (http://wiki.osdev.org/PIC#Initialisation, https://pdos.csail.mit.edu/6.828/2005/readings/hardware/8259A.pdf)
    pub unsafe fn init(&mut self) {
        // Create local IO wait function
        let mut io_wait_port: Port<u8> = Port::new(0x80);
        let mut io_wait = || { io_wait_port.write(0) };

        // Save masks
        let mask1_orig = self.pics[0].data_port.read();
        let mask2_orig = self.pics[1].data_port.read();

        // Initialization sequence
        self.pics[0].command_port.write(PIC_CMD_INIT);
        io_wait();
        self.pics[1].command_port.write(PIC_CMD_INIT);
        io_wait();

        // Set interrupt offset
        self.pics[0].data_port.write(self.pics[0].offset);
        io_wait();
        self.pics[1].data_port.write(self.pics[1].offset);
        io_wait();

        // Introduce PICs to each other
        self.pics[0].data_port.write(4);
        io_wait();
        self.pics[1].data_port.write(2);
        io_wait();

        // Use 8086/88 (MCS-80/85) mode (http://forum.osdev.org/viewtopic.php?f=1&t=12960&start=0)
        self.pics[0].data_port.write(1);
        io_wait();
        self.pics[1].data_port.write(1);
        io_wait();

        // Restore masks
        self.pics[0].data_port.write(mask1_orig);
        self.pics[1].data_port.write(mask2_orig);
    }
    pub fn handles_interrupt(&self, interrupt_id: u8) -> bool {
        self.pics.iter().any(|p| p.handles_interrupt(interrupt_id))
    }
    pub unsafe fn notify_eoi(&mut self, interrupt_id: u8) {
        if self.handles_interrupt(interrupt_id) {
            // chain
            if self.pics[1].handles_interrupt(interrupt_id) {
                self.pics[1].send_eoi();
            }
            self.pics[0].send_eoi();
        }
    }
}

pub static PICS: Mutex<ChainedPics> = Mutex::new(unsafe { ChainedPics::new(0x20, 0x28) });
<commit_msg>Add init function<commit_after>use spin::Mutex;
use cpuio::{Port, UnsafePort};

// PIC ports
const PIC1_COMMAND: u16 = 0x20;
const PIC2_COMMAND: u16 = 0xA0;
const PIC1_DATA:    u16 = 0x21;
const PIC2_DATA:    u16 = 0xA1;

// PIC commands
const PIC_CMD_EOI:  u8 = 0x20;
const PIC_CMD_INIT: u8 = 0x11;

struct Pic {
    offset: u8,
    command_port: UnsafePort<u8>,
    data_port: UnsafePort<u8>,
}

impl Pic {
    fn handles_interrupt(&self, interupt_id: u8) -> bool {
        self.offset <= interupt_id && interupt_id < self.offset + 8
    }
    /// Send end of interrupt signal to pic
    unsafe fn send_eoi(&mut self) {
        self.command_port.write(PIC_CMD_EOI);
    }
}

pub struct ChainedPics {
    pics: [Pic; 2],
}

impl ChainedPics {
    pub const unsafe fn new(pic1_offset: u8, pic2_offset: u8) -> ChainedPics {
        ChainedPics {
            pics: [
                Pic {
                    offset: pic1_offset,
                    command_port:   UnsafePort::new(PIC1_COMMAND),
                    data_port:      UnsafePort::new(PIC1_DATA),
                },
                Pic {
                    offset: pic2_offset,
                    command_port:   UnsafePort::new(PIC2_COMMAND),
                    data_port:      UnsafePort::new(PIC2_DATA),
                },
            ]
        }
    }
    /// Init - remap irqs (http://wiki.osdev.org/PIC#Initialisation, https://pdos.csail.mit.edu/6.828/2005/readings/hardware/8259A.pdf)
    pub unsafe fn init(&mut self) {
        // Create local IO wait function
        let mut io_wait_port: Port<u8> = Port::new(0x80);
        let mut io_wait = || { io_wait_port.write(0) };

        // Save masks
        let mask1_orig = self.pics[0].data_port.read();
        let mask2_orig = self.pics[1].data_port.read();

        // Initialization sequence
        self.pics[0].command_port.write(PIC_CMD_INIT);
        io_wait();
        self.pics[1].command_port.write(PIC_CMD_INIT);
        io_wait();

        // Set interrupt offset
        self.pics[0].data_port.write(self.pics[0].offset);
        io_wait();
        self.pics[1].data_port.write(self.pics[1].offset);
        io_wait();

        // Introduce PICs to each other
        self.pics[0].data_port.write(4);
        io_wait();
        self.pics[1].data_port.write(2);
        io_wait();

        // Use 8086/88 (MCS-80/85) mode (http://forum.osdev.org/viewtopic.php?f=1&t=12960&start=0)
        self.pics[0].data_port.write(1);
        io_wait();
        self.pics[1].data_port.write(1);
        io_wait();

        // Restore masks
        self.pics[0].data_port.write(mask1_orig);
        self.pics[1].data_port.write(mask2_orig);
    }
    pub fn handles_interrupt(&self, interrupt_id: u8) -> bool {
        self.pics.iter().any(|p| p.handles_interrupt(interrupt_id))
    }
    pub unsafe fn notify_eoi(&mut self, interrupt_id: u8) {
        if self.handles_interrupt(interrupt_id) {
            // chain
            if self.pics[1].handles_interrupt(interrupt_id) {
                self.pics[1].send_eoi();
            }
            self.pics[0].send_eoi();
        }
    }
}

pub static PICS: Mutex<ChainedPics> = Mutex::new(unsafe { ChainedPics::new(0x20, 0x28) });

pub fn init() {
    unsafe {
        PICS.lock().init();
    }
}
<|endoftext|>


<commit_before>use std::{io, slice, str, fmt};

use bytes::BytesMut;

use httparse;

pub struct Request {
    method: Slice,
    path: Slice,
    version: u8,
    headers: Vec<(Slice, Slice)>,
    data: BytesMut,
}

type Slice = (usize, usize);

pub struct RequestHeaders<'req> {
    headers: slice::Iter<'req, (Slice, Slice)>,
    req: &'req Request,
}

impl Request {
    pub fn method(&self) -> &str {
        str::from_utf8(self.slice(&self.method)).unwrap()
    }

    pub fn path(&self) -> &str {
        str::from_utf8(self.slice(&self.path)).unwrap()
    }

    pub fn version(&self) -> u8 {
        self.version
    }

    pub fn headers(&self) -> RequestHeaders {
        RequestHeaders {
            headers: self.headers.iter(),
            req: self,
        }
    }

    fn slice(&self, slice: &Slice) -> &[u8] {
        &self.data[slice.0..slice.1]
    }
}

impl fmt::Debug for Request {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "<HTTP Request {} {}>", self.method(), self.path())
    }
}

pub fn decode(buf: &mut BytesMut) -> io::Result<Option<Request>> {
    let (method, path, version, headers, amt) =
        {
            let mut headers = [httparse::EMPTY_HEADER; 16];
            let mut r = httparse::Request::new(&mut headers);
            let status = try!(r.parse(buf).map_err(|e| {
                let msg = format!("failed to parse http request: {:?}", e);
                io::Error::new(io::ErrorKind::Other, msg)
            }));

            let amt = match status {
                httparse::Status::Complete(amt) => amt,
                httparse::Status::Partial => return Ok(None),
            };

            let toslice = |a: &[u8]| {
                let start = a.as_ptr() as usize - buf.as_ptr() as usize;
                assert!(start < buf.len());
                (start, start + a.len())
            };

            (toslice(r.method.unwrap().as_bytes()),
             toslice(r.path.unwrap().as_bytes()),
             r.version.unwrap(),
             r.headers
                 .iter()
                 .map(|h| (toslice(h.name.as_bytes()), toslice(h.value)))
                 .collect(),
             amt)
        };

    Ok(Request {
               method: method,
               path: path,
               version: version,
               headers: headers,
               data: buf.split_to(amt),
           }
           .into())
}

impl<'req> Iterator for RequestHeaders<'req> {
    type Item = (&'req str, &'req [u8]);

    fn next(&mut self) -> Option<(&'req str, &'req [u8])> {
        self.headers
            .next()
            .map(|&(ref a, ref b)| {
                     let a = self.req.slice(a);
                     let b = self.req.slice(b);
                     (str::from_utf8(a).unwrap(), b)
                 })
    }
}
<commit_msg>Starting the work on request parsing<commit_after>use std::{io, slice, str};

use bytes::BytesMut;

use httparse;

pub struct Request {
    method: Slice,
    path: Slice,
    version: u8,
    headers: Vec<(Slice, Slice)>,
    data: BytesMut,
}

type Slice = (usize, usize);

pub struct RequestHeaders<'req> {
    headers: slice::Iter<'req, (Slice, Slice)>,
    req: &'req Request,
}

impl Request {
    pub fn method(&self) -> &str {
        str::from_utf8(self.slice(&self.method)).unwrap()
    }

    pub fn path(&self) -> &str {
        str::from_utf8(self.slice(&self.path)).unwrap()
    }

    pub fn version(&self) -> u8 {
        self.version
    }

    pub fn headers(&self) -> RequestHeaders {
        RequestHeaders {
            headers: self.headers.iter(),
            req: self,
        }
    }

    fn slice(&self, slice: &Slice) -> &[u8] {
        &self.data[slice.0..slice.1]
    }
}

pub fn decode(buf: &mut BytesMut) -> io::Result<Option<Request>> {
    let (method, path, version, headers, amt) =
        {
            let mut headers = [httparse::EMPTY_HEADER; 16];
            let mut r = httparse::Request::new(&mut headers);
            let status = try!(r.parse(buf).map_err(|e| {
                let msg = format!("failed to parse http request: {:?}", e);
                io::Error::new(io::ErrorKind::Other, msg)
            }));

            let amt = match status {
                httparse::Status::Complete(amt) => amt,
                httparse::Status::Partial => return Ok(None),
            };

            let toslice = |a: &[u8]| {
                let start = a.as_ptr() as usize - buf.as_ptr() as usize;
                assert!(start < buf.len());
                (start, start + a.len())
            };

            (toslice(r.method.unwrap().as_bytes()),
             toslice(r.path.unwrap().as_bytes()),
             r.version.unwrap(),
             r.headers
                 .iter()
                 .map(|h| (toslice(h.name.as_bytes()), toslice(h.value)))
                 .collect(),
             amt)
        };

    Ok(Request {
               method: method,
               path: path,
               version: version,
               headers: headers,
               data: buf.split_to(amt),
           }
           .into())
}

impl<'req> Iterator for RequestHeaders<'req> {
    type Item = (&'req str, &'req [u8]);

    fn next(&mut self) -> Option<(&'req str, &'req [u8])> {
        self.headers
            .next()
            .map(|&(ref a, ref b)| {
                     let a = self.req.slice(a);
                     let b = self.req.slice(b);
                     (str::from_utf8(a).unwrap(), b)
                 })
    }
}
<|endoftext|>


<commit_before>#![no_std]
#![feature(lang_items)]
#![feature(unique)]
#![feature(const_fn)]
#![feature(asm)]

extern crate rlibc;
extern crate spin;

#[macro_use]
mod vga_buffer;
mod util;
mod ram_map;

use vga_buffer::{Color, CellColor};

/// The kernel main function
#[no_mangle]
pub extern fn rust_main() {
    use core::fmt::Write;

    // test
    rreset!();
    rprintln!("Tuubaaja");

    // startup message
    rprintln!("Dimension 7 OS\n");
    rprintln!("Initializing system...");

    // read memory map
    let mmap_ok = ram_map::load_memory_map();

    // hang
    rprintln!("System ready.");
    loop {}
}

#[cfg(not(test))]
#[lang = "eh_personality"]
extern "C" fn eh_personality() {}

#[cfg(not(test))]
#[lang = "panic_fmt"]
extern "C" fn panic_fmt(fmt: core::fmt::Arguments, file: &str, line: u32) -> ! {
    unsafe {
        asm!("jmp panic"::::"intel");
    }
    loop {}
}
<commit_msg>Improve panic macro<commit_after>#![no_std]
#![feature(lang_items)]
#![feature(unique)]
#![feature(const_fn)]
#![feature(asm)]

extern crate rlibc;
extern crate spin;

#[macro_use]
mod vga_buffer;
mod util;
mod ram_map;

use vga_buffer::{Color, CellColor};

/// The kernel main function
#[no_mangle]
pub extern fn rust_main() {
    use core::fmt::Write;

    // test
    rreset!();
    rprintln!("Tuubaaja");

    // startup message
    rprintln!("Dimension 7 OS\n");
    rprintln!("Initializing system...");

    // read memory map
    let mmap_ok = ram_map::load_memory_map();

    // hang
    rprintln!("System ready.");
    loop {}
}

#[cfg(not(test))]
#[lang = "eh_personality"]
extern "C" fn eh_personality() {}

#[cfg(not(test))]
#[lang = "panic_fmt"]
// VirtualBox does not like panics, and most likely guru meditates instead
extern "C" fn panic_fmt(fmt: core::fmt::Arguments, file: &str, line: u32) -> ! {
    // unsafe {
    //     asm!("jmp panic"::::"intel");
    // }
    rreset!();
    rprintln!("Kernel Panic: file: '{}', line {}", file, line);
    rprintln!("    {}\n", fmt);
    loop {}
}
<|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/. */

//! Bindings for CSS Rule objects

use computed_values::{font_style, font_weight, font_stretch};
use computed_values::font_family::FamilyName;
use counter_style;
use cssparser::UnicodeRange;
use font_face::{FontFaceRuleData, Source};
use gecko_bindings::bindings;
use gecko_bindings::structs::{self, nsCSSFontFaceRule, nsCSSValue};
use gecko_bindings::structs::{nsCSSCounterDesc, nsCSSCounterStyleRule};
use gecko_bindings::sugar::ns_css_value::ToNsCssValue;
use gecko_bindings::sugar::refptr::{RefPtr, UniqueRefPtr};
use shared_lock::{ToCssWithGuard, SharedRwLockReadGuard};
use std::fmt;

/// A @font-face rule
pub type FontFaceRule = RefPtr<nsCSSFontFaceRule>;

impl ToNsCssValue for FamilyName {
    fn convert(self, nscssvalue: &mut nsCSSValue) {
        nscssvalue.set_string_from_atom(&self.name)
    }
}

impl ToNsCssValue for font_weight::T {
    fn convert(self, nscssvalue: &mut nsCSSValue) {
        nscssvalue.set_integer(self as i32)
    }
}

macro_rules! map_enum {
    (
        $(
            $prop:ident {
                $($servo:ident => $gecko:ident,)+
            }
        )+
    ) => {
        $(
            impl ToNsCssValue for $prop::T {
                fn convert(self, nscssvalue: &mut nsCSSValue) {
                    nscssvalue.set_enum(match self {
                        $( $prop::T::$servo => structs::$gecko as i32, )+
                    })
                }
            }
        )+
    }
}

map_enum! {
    font_style {
        normal => NS_FONT_STYLE_NORMAL,
        italic => NS_FONT_STYLE_ITALIC,
        oblique => NS_FONT_STYLE_OBLIQUE,
    }

    font_stretch {
        normal          => NS_FONT_STRETCH_NORMAL,
        ultra_condensed => NS_FONT_STRETCH_ULTRA_CONDENSED,
        extra_condensed => NS_FONT_STRETCH_EXTRA_CONDENSED,
        condensed       => NS_FONT_STRETCH_CONDENSED,
        semi_condensed  => NS_FONT_STRETCH_SEMI_CONDENSED,
        semi_expanded   => NS_FONT_STRETCH_SEMI_EXPANDED,
        expanded        => NS_FONT_STRETCH_EXPANDED,
        extra_expanded  => NS_FONT_STRETCH_EXTRA_EXPANDED,
        ultra_expanded  => NS_FONT_STRETCH_ULTRA_EXPANDED,
    }
}

impl ToNsCssValue for Vec<Source> {
    fn convert(self, nscssvalue: &mut nsCSSValue) {
        let src_len = self.iter().fold(0, |acc, src| {
            acc + match *src {
                // Each format hint takes one position in the array of mSrc.
                Source::Url(ref url) => url.format_hints.len() + 1,
                Source::Local(_) => 1,
            }
        });
        let mut target_srcs =
            nscssvalue.set_array(src_len as i32).as_mut_slice().iter_mut();
        macro_rules! next { () => {
            target_srcs.next().expect("Length of target_srcs should be enough")
        } }
        for src in self.into_iter() {
            match src {
                Source::Url(url) => {
                    next!().set_url(&url.url);
                    for hint in url.format_hints.iter() {
                        next!().set_font_format(&hint);
                    }
                }
                Source::Local(family) => {
                    next!().set_local_font(&family.name);
                }
            }
        }
        debug_assert!(target_srcs.next().is_none(), "Should have filled all slots");
    }
}

impl ToNsCssValue for Vec<UnicodeRange> {
    fn convert(self, nscssvalue: &mut nsCSSValue) {
        let target_ranges = nscssvalue
            .set_array((self.len() * 2) as i32)
            .as_mut_slice().chunks_mut(2);
        for (range, target) in self.iter().zip(target_ranges) {
            target[0].set_integer(range.start as i32);
            target[1].set_integer(range.end as i32);
        }
    }
}

impl From<FontFaceRuleData> for FontFaceRule {
    fn from(data: FontFaceRuleData) -> FontFaceRule {
        let mut result = unsafe {
            UniqueRefPtr::from_addrefed(bindings::Gecko_CSSFontFaceRule_Create(
                data.source_location.line as u32, data.source_location.column as u32
            ))
        };
        data.set_descriptors(&mut result.mDecl.mDescriptors);
        result.get()
    }
}

impl ToCssWithGuard for FontFaceRule {
    fn to_css<W>(&self, _guard: &SharedRwLockReadGuard, dest: &mut W) -> fmt::Result
    where W: fmt::Write {
        ns_auto_string!(css_text);
        unsafe {
            bindings::Gecko_CSSFontFaceRule_GetCssText(self.get(), &mut *css_text);
        }
        write!(dest, "{}", css_text)
    }
}

/// A @counter-style rule
pub type CounterStyleRule = RefPtr<nsCSSCounterStyleRule>;

impl From<counter_style::CounterStyleRuleData> for CounterStyleRule {
    fn from(data: counter_style::CounterStyleRuleData) -> CounterStyleRule {
        let mut result = unsafe {
            UniqueRefPtr::from_addrefed(
                bindings::Gecko_CSSCounterStyle_Create(data.name().0.as_ptr()))
        };
        data.set_descriptors(&mut result.mValues);
        result.get()
    }
}

impl ToCssWithGuard for CounterStyleRule {
    fn to_css<W>(&self, _guard: &SharedRwLockReadGuard, dest: &mut W) -> fmt::Result
    where W: fmt::Write {
        ns_auto_string!(css_text);
        unsafe {
            bindings::Gecko_CSSCounterStyle_GetCssText(self.get(), &mut *css_text);
        }
        write!(dest, "{}", css_text)
    }
}

/// The type of nsCSSCounterStyleRule::mValues
pub type CounterStyleDescriptors = [nsCSSValue; nsCSSCounterDesc::eCSSCounterDesc_COUNT as usize];

impl ToNsCssValue for counter_style::System {
    fn convert(self, nscssvalue: &mut nsCSSValue) {
        use counter_style::System::*;
        match self {
            Cyclic => nscssvalue.set_enum(structs::NS_STYLE_COUNTER_SYSTEM_CYCLIC as i32),
            Numeric => nscssvalue.set_enum(structs::NS_STYLE_COUNTER_SYSTEM_NUMERIC as i32),
            Alphabetic => nscssvalue.set_enum(structs::NS_STYLE_COUNTER_SYSTEM_ALPHABETIC as i32),
            Symbolic => nscssvalue.set_enum(structs::NS_STYLE_COUNTER_SYSTEM_SYMBOLIC as i32),
            Additive => nscssvalue.set_enum(structs::NS_STYLE_COUNTER_SYSTEM_ADDITIVE as i32),
            Fixed { first_symbol_value } => {
                let mut a = nsCSSValue::null();
                let mut b = nsCSSValue::null();
                a.set_enum(structs::NS_STYLE_COUNTER_SYSTEM_FIXED as i32);
                b.set_integer(first_symbol_value.unwrap_or(1));
                nscssvalue.set_pair(&a, &b);
            }
            Extends(other) => {
                let mut a = nsCSSValue::null();
                let mut b = nsCSSValue::null();
                a.set_enum(structs::NS_STYLE_COUNTER_SYSTEM_EXTENDS as i32);
                b.set_string_from_atom(&other.0);
                nscssvalue.set_pair(&a, &b);
            }
        }
    }
}

impl ToNsCssValue for counter_style::Negative {
    fn convert(self, nscssvalue: &mut nsCSSValue) {
        if let Some(second) = self.1 {
            let mut a = nsCSSValue::null();
            let mut b = nsCSSValue::null();
            a.set_from(self.0);
            b.set_from(second);
            nscssvalue.set_pair(&a, &b);
        } else {
            nscssvalue.set_from(self.0)
        }
    }
}

impl ToNsCssValue for counter_style::Symbol {
    fn convert(self, nscssvalue: &mut nsCSSValue) {
        match self {
            counter_style::Symbol::String(s) => nscssvalue.set_string(&s),
            counter_style::Symbol::Ident(s) => nscssvalue.set_ident(&s),
        }
    }
}

impl ToNsCssValue for counter_style::Ranges {
    fn convert(self, nscssvalue: &mut nsCSSValue) {
        if self.0.is_empty() {
            nscssvalue.set_auto();
        } else {
            nscssvalue.set_pair_list(self.0.into_iter().map(|range| {
                fn set_bound(bound: Option<i32>, nscssvalue: &mut nsCSSValue) {
                    if let Some(finite) = bound {
                        nscssvalue.set_integer(finite)
                    } else {
                        nscssvalue.set_enum(structs::NS_STYLE_COUNTER_RANGE_INFINITE as i32)
                    }
                }
                let mut start = nsCSSValue::null();
                let mut end = nsCSSValue::null();
                set_bound(range.start, &mut start);
                set_bound(range.end, &mut end);
                (start, end)
            }));
        }
    }
}

impl ToNsCssValue for counter_style::Pad {
    fn convert(self, nscssvalue: &mut nsCSSValue) {
        let mut min_length = nsCSSValue::null();
        let mut pad_with = nsCSSValue::null();
        min_length.set_integer(self.0 as i32);
        pad_with.set_from(self.1);
        nscssvalue.set_pair(&min_length, &pad_with);
    }
}

impl ToNsCssValue for counter_style::Fallback {
    fn convert(self, nscssvalue: &mut nsCSSValue) {
        nscssvalue.set_ident_from_atom(&self.0 .0)
    }
}

impl ToNsCssValue for counter_style::Symbols {
    fn convert(self, nscssvalue: &mut nsCSSValue) {
        nscssvalue.set_list(self.0.into_iter().map(|item| {
            let mut value = nsCSSValue::null();
            value.set_from(item);
            value
        }));
    }
}

impl ToNsCssValue for counter_style::AdditiveSymbols {
    fn convert(self, nscssvalue: &mut nsCSSValue) {
        nscssvalue.set_pair_list(self.0.into_iter().map(|tuple| {
            let mut weight = nsCSSValue::null();
            let mut symbol = nsCSSValue::null();
            weight.set_integer(tuple.weight as i32);
            symbol.set_from(tuple.symbol);
            (weight, symbol)
        }));
    }
}

impl ToNsCssValue for counter_style::SpeakAs {
    fn convert(self, nscssvalue: &mut nsCSSValue) {
        use counter_style::SpeakAs::*;
        match self {
            Auto => nscssvalue.set_auto(),
            Bullets => nscssvalue.set_enum(structs::NS_STYLE_COUNTER_SPEAKAS_BULLETS as i32),
            Numbers => nscssvalue.set_enum(structs::NS_STYLE_COUNTER_SPEAKAS_NUMBERS as i32),
            Words => nscssvalue.set_enum(structs::NS_STYLE_COUNTER_SPEAKAS_WORDS as i32),
            Other(other) => nscssvalue.set_ident_from_atom(&other.0),
        }
    }
}
<commit_msg>Set atom identifier for counter style names in @counter-style rule.<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/. */

//! Bindings for CSS Rule objects

use computed_values::{font_style, font_weight, font_stretch};
use computed_values::font_family::FamilyName;
use counter_style;
use cssparser::UnicodeRange;
use font_face::{FontFaceRuleData, Source};
use gecko_bindings::bindings;
use gecko_bindings::structs::{self, nsCSSFontFaceRule, nsCSSValue};
use gecko_bindings::structs::{nsCSSCounterDesc, nsCSSCounterStyleRule};
use gecko_bindings::sugar::ns_css_value::ToNsCssValue;
use gecko_bindings::sugar::refptr::{RefPtr, UniqueRefPtr};
use shared_lock::{ToCssWithGuard, SharedRwLockReadGuard};
use std::fmt;

/// A @font-face rule
pub type FontFaceRule = RefPtr<nsCSSFontFaceRule>;

impl ToNsCssValue for FamilyName {
    fn convert(self, nscssvalue: &mut nsCSSValue) {
        nscssvalue.set_string_from_atom(&self.name)
    }
}

impl ToNsCssValue for font_weight::T {
    fn convert(self, nscssvalue: &mut nsCSSValue) {
        nscssvalue.set_integer(self as i32)
    }
}

macro_rules! map_enum {
    (
        $(
            $prop:ident {
                $($servo:ident => $gecko:ident,)+
            }
        )+
    ) => {
        $(
            impl ToNsCssValue for $prop::T {
                fn convert(self, nscssvalue: &mut nsCSSValue) {
                    nscssvalue.set_enum(match self {
                        $( $prop::T::$servo => structs::$gecko as i32, )+
                    })
                }
            }
        )+
    }
}

map_enum! {
    font_style {
        normal => NS_FONT_STYLE_NORMAL,
        italic => NS_FONT_STYLE_ITALIC,
        oblique => NS_FONT_STYLE_OBLIQUE,
    }

    font_stretch {
        normal          => NS_FONT_STRETCH_NORMAL,
        ultra_condensed => NS_FONT_STRETCH_ULTRA_CONDENSED,
        extra_condensed => NS_FONT_STRETCH_EXTRA_CONDENSED,
        condensed       => NS_FONT_STRETCH_CONDENSED,
        semi_condensed  => NS_FONT_STRETCH_SEMI_CONDENSED,
        semi_expanded   => NS_FONT_STRETCH_SEMI_EXPANDED,
        expanded        => NS_FONT_STRETCH_EXPANDED,
        extra_expanded  => NS_FONT_STRETCH_EXTRA_EXPANDED,
        ultra_expanded  => NS_FONT_STRETCH_ULTRA_EXPANDED,
    }
}

impl ToNsCssValue for Vec<Source> {
    fn convert(self, nscssvalue: &mut nsCSSValue) {
        let src_len = self.iter().fold(0, |acc, src| {
            acc + match *src {
                // Each format hint takes one position in the array of mSrc.
                Source::Url(ref url) => url.format_hints.len() + 1,
                Source::Local(_) => 1,
            }
        });
        let mut target_srcs =
            nscssvalue.set_array(src_len as i32).as_mut_slice().iter_mut();
        macro_rules! next { () => {
            target_srcs.next().expect("Length of target_srcs should be enough")
        } }
        for src in self.into_iter() {
            match src {
                Source::Url(url) => {
                    next!().set_url(&url.url);
                    for hint in url.format_hints.iter() {
                        next!().set_font_format(&hint);
                    }
                }
                Source::Local(family) => {
                    next!().set_local_font(&family.name);
                }
            }
        }
        debug_assert!(target_srcs.next().is_none(), "Should have filled all slots");
    }
}

impl ToNsCssValue for Vec<UnicodeRange> {
    fn convert(self, nscssvalue: &mut nsCSSValue) {
        let target_ranges = nscssvalue
            .set_array((self.len() * 2) as i32)
            .as_mut_slice().chunks_mut(2);
        for (range, target) in self.iter().zip(target_ranges) {
            target[0].set_integer(range.start as i32);
            target[1].set_integer(range.end as i32);
        }
    }
}

impl From<FontFaceRuleData> for FontFaceRule {
    fn from(data: FontFaceRuleData) -> FontFaceRule {
        let mut result = unsafe {
            UniqueRefPtr::from_addrefed(bindings::Gecko_CSSFontFaceRule_Create(
                data.source_location.line as u32, data.source_location.column as u32
            ))
        };
        data.set_descriptors(&mut result.mDecl.mDescriptors);
        result.get()
    }
}

impl ToCssWithGuard for FontFaceRule {
    fn to_css<W>(&self, _guard: &SharedRwLockReadGuard, dest: &mut W) -> fmt::Result
    where W: fmt::Write {
        ns_auto_string!(css_text);
        unsafe {
            bindings::Gecko_CSSFontFaceRule_GetCssText(self.get(), &mut *css_text);
        }
        write!(dest, "{}", css_text)
    }
}

/// A @counter-style rule
pub type CounterStyleRule = RefPtr<nsCSSCounterStyleRule>;

impl From<counter_style::CounterStyleRuleData> for CounterStyleRule {
    fn from(data: counter_style::CounterStyleRuleData) -> CounterStyleRule {
        let mut result = unsafe {
            UniqueRefPtr::from_addrefed(
                bindings::Gecko_CSSCounterStyle_Create(data.name().0.as_ptr()))
        };
        data.set_descriptors(&mut result.mValues);
        result.get()
    }
}

impl ToCssWithGuard for CounterStyleRule {
    fn to_css<W>(&self, _guard: &SharedRwLockReadGuard, dest: &mut W) -> fmt::Result
    where W: fmt::Write {
        ns_auto_string!(css_text);
        unsafe {
            bindings::Gecko_CSSCounterStyle_GetCssText(self.get(), &mut *css_text);
        }
        write!(dest, "{}", css_text)
    }
}

/// The type of nsCSSCounterStyleRule::mValues
pub type CounterStyleDescriptors = [nsCSSValue; nsCSSCounterDesc::eCSSCounterDesc_COUNT as usize];

impl ToNsCssValue for counter_style::System {
    fn convert(self, nscssvalue: &mut nsCSSValue) {
        use counter_style::System::*;
        match self {
            Cyclic => nscssvalue.set_enum(structs::NS_STYLE_COUNTER_SYSTEM_CYCLIC as i32),
            Numeric => nscssvalue.set_enum(structs::NS_STYLE_COUNTER_SYSTEM_NUMERIC as i32),
            Alphabetic => nscssvalue.set_enum(structs::NS_STYLE_COUNTER_SYSTEM_ALPHABETIC as i32),
            Symbolic => nscssvalue.set_enum(structs::NS_STYLE_COUNTER_SYSTEM_SYMBOLIC as i32),
            Additive => nscssvalue.set_enum(structs::NS_STYLE_COUNTER_SYSTEM_ADDITIVE as i32),
            Fixed { first_symbol_value } => {
                let mut a = nsCSSValue::null();
                let mut b = nsCSSValue::null();
                a.set_enum(structs::NS_STYLE_COUNTER_SYSTEM_FIXED as i32);
                b.set_integer(first_symbol_value.unwrap_or(1));
                nscssvalue.set_pair(&a, &b);
            }
            Extends(other) => {
                let mut a = nsCSSValue::null();
                let mut b = nsCSSValue::null();
                a.set_enum(structs::NS_STYLE_COUNTER_SYSTEM_EXTENDS as i32);
                b.set_atom_ident(other.0);
                nscssvalue.set_pair(&a, &b);
            }
        }
    }
}

impl ToNsCssValue for counter_style::Negative {
    fn convert(self, nscssvalue: &mut nsCSSValue) {
        if let Some(second) = self.1 {
            let mut a = nsCSSValue::null();
            let mut b = nsCSSValue::null();
            a.set_from(self.0);
            b.set_from(second);
            nscssvalue.set_pair(&a, &b);
        } else {
            nscssvalue.set_from(self.0)
        }
    }
}

impl ToNsCssValue for counter_style::Symbol {
    fn convert(self, nscssvalue: &mut nsCSSValue) {
        match self {
            counter_style::Symbol::String(s) => nscssvalue.set_string(&s),
            counter_style::Symbol::Ident(s) => nscssvalue.set_ident(&s),
        }
    }
}

impl ToNsCssValue for counter_style::Ranges {
    fn convert(self, nscssvalue: &mut nsCSSValue) {
        if self.0.is_empty() {
            nscssvalue.set_auto();
        } else {
            nscssvalue.set_pair_list(self.0.into_iter().map(|range| {
                fn set_bound(bound: Option<i32>, nscssvalue: &mut nsCSSValue) {
                    if let Some(finite) = bound {
                        nscssvalue.set_integer(finite)
                    } else {
                        nscssvalue.set_enum(structs::NS_STYLE_COUNTER_RANGE_INFINITE as i32)
                    }
                }
                let mut start = nsCSSValue::null();
                let mut end = nsCSSValue::null();
                set_bound(range.start, &mut start);
                set_bound(range.end, &mut end);
                (start, end)
            }));
        }
    }
}

impl ToNsCssValue for counter_style::Pad {
    fn convert(self, nscssvalue: &mut nsCSSValue) {
        let mut min_length = nsCSSValue::null();
        let mut pad_with = nsCSSValue::null();
        min_length.set_integer(self.0 as i32);
        pad_with.set_from(self.1);
        nscssvalue.set_pair(&min_length, &pad_with);
    }
}

impl ToNsCssValue for counter_style::Fallback {
    fn convert(self, nscssvalue: &mut nsCSSValue) {
        nscssvalue.set_atom_ident(self.0 .0)
    }
}

impl ToNsCssValue for counter_style::Symbols {
    fn convert(self, nscssvalue: &mut nsCSSValue) {
        nscssvalue.set_list(self.0.into_iter().map(|item| {
            let mut value = nsCSSValue::null();
            value.set_from(item);
            value
        }));
    }
}

impl ToNsCssValue for counter_style::AdditiveSymbols {
    fn convert(self, nscssvalue: &mut nsCSSValue) {
        nscssvalue.set_pair_list(self.0.into_iter().map(|tuple| {
            let mut weight = nsCSSValue::null();
            let mut symbol = nsCSSValue::null();
            weight.set_integer(tuple.weight as i32);
            symbol.set_from(tuple.symbol);
            (weight, symbol)
        }));
    }
}

impl ToNsCssValue for counter_style::SpeakAs {
    fn convert(self, nscssvalue: &mut nsCSSValue) {
        use counter_style::SpeakAs::*;
        match self {
            Auto => nscssvalue.set_auto(),
            Bullets => nscssvalue.set_enum(structs::NS_STYLE_COUNTER_SPEAKAS_BULLETS as i32),
            Numbers => nscssvalue.set_enum(structs::NS_STYLE_COUNTER_SPEAKAS_NUMBERS as i32),
            Words => nscssvalue.set_enum(structs::NS_STYLE_COUNTER_SPEAKAS_WORDS as i32),
            Other(other) => nscssvalue.set_atom_ident(other.0),
        }
    }
}
<|endoftext|>


<commit_before>use std::io;
use std::sync::{Arc, Mutex};
use std::sync::atomic::{AtomicUsize, Ordering};

use futures::{future, Future, BoxFuture, Stream};
use tokio_proto::streaming::{Message, Body};
use tokio_service::Service;

use bytes::{BufMut, Bytes, BytesMut};

use admin;
use codec::PacketHeader;
use job::Job;
use packet::PacketMagic;
use queues::{HandleJobStorage, JobQueuePriority, SharedJobStorage};
use worker::{SharedWorkers, Worker, Wake};
use constants::*;

pub type GearmanBody = Body<BytesMut, io::Error>;
pub type GearmanMessage = Message<PacketHeader, GearmanBody>;

fn new_res(ptype: u32, data: BytesMut) -> GearmanMessage {
    Message::WithBody(PacketHeader {
                          magic: PacketMagic::RES,
                          ptype: ptype,
                          psize: data.len() as u32,
                      },
                      Body::from(data))
}

pub struct GearmanService {
    pub conn_id: usize,
    pub queues: SharedJobStorage,
    pub workers: SharedWorkers,
    pub worker: Arc<Mutex<Worker>>,
    pub job_count: Arc<AtomicUsize>,
}

fn next_field(buf: &mut BytesMut) -> Result<Bytes, io::Error> {
    match buf[..].iter().position(|b| *b == b'\0') {
        Some(null_pos) => {
            let value = buf.split_to(null_pos);
            buf.split_to(1);
            Ok(value.freeze())
        }
        None => Err(io::Error::new(io::ErrorKind::Other, "Can't find null")),
    }
}

impl GearmanService {
    /// Things that don't require a body should use this
    fn response_from_header(&self,
                            header: &PacketHeader)
                            -> Message<PacketHeader, Body<BytesMut, io::Error>> {
        match header.ptype {
            ADMIN_VERSION => {
                let resp_str = "OK some-rustygear-version\n";
                let mut resp_body = BytesMut::with_capacity(resp_str.len());
                resp_body.put(&resp_str[..]);
                let resp_body = Body::from(resp_body);
                Message::WithBody(PacketHeader {
                                      magic: PacketMagic::TEXT,
                                      ptype: header.ptype,
                                      psize: resp_str.len() as u32,
                                  },
                                  resp_body)
            }
            ADMIN_STATUS => admin::admin_command_status(self.queues.clone(), self.workers.clone()),
            _ => {
                panic!("response_from_header called with invalid ptype: {}",
                       header.ptype)
            }
        }
    }

    pub fn new(conn_id: usize,
               queues: SharedJobStorage,
               workers: SharedWorkers,
               job_count: Arc<AtomicUsize>)
               -> GearmanService {
        GearmanService {
            conn_id: conn_id,
            queues: queues.clone(),
            worker: Arc::new(Mutex::new((Worker::new()))),
            workers: workers.clone(),
            job_count: job_count.clone(),
        }
    }

    fn no_response() -> GearmanMessage {
        Message::WithBody(PacketHeader {
                              magic: PacketMagic::TEXT,
                              ptype: ADMIN_RESPONSE,
                              psize: 0,
                          },
                          Body::from(BytesMut::new()))
    }

    fn handle_can_do(&self, body: GearmanBody) -> BoxFuture<GearmanMessage, io::Error> {
        let worker = self.worker.clone();
        let workers = self.workers.clone();
        let conn_id = self.conn_id;
        trace!("handle_can_do");
        body.concat2()
            .and_then(move |fname| {
                let fname = fname.freeze();
                debug!("CAN_DO fname = {:?}", fname);
                let mut worker = worker.lock().unwrap();
                worker.can_do(fname);
                workers.clone().wakeup(&mut worker, conn_id);
                future::finished(Self::no_response())
            })
            .boxed()
    }

    fn handle_cant_do(&self, body: GearmanBody) -> BoxFuture<GearmanMessage, io::Error> {
        let worker = self.worker.clone();
        body.concat2()
            .and_then(move |fname| {
                let fname = fname.freeze();
                debug!("CANT_DO fname = {:?}", fname);
                let mut worker = worker.lock().unwrap();
                worker.cant_do(&fname);
                future::finished(Self::no_response())
            })
            .boxed()
    }

    fn handle_grab_job_all(&self, body: GearmanBody) -> BoxFuture<GearmanMessage, io::Error> {
        let mut queues = self.queues.clone();
        let worker = self.worker.clone();
        trace!("handle_grab_job_all");
        body.concat2()
            .and_then(move |_| {
                let mut worker = worker.lock().unwrap();
                let ref mut worker = worker;
                if queues.get_job(worker) {
                    match worker.job() {
                        Some(ref j) => {
                            let mut data = BytesMut::with_capacity(4 + j.handle.len() +
                                                                   j.fname.len() +
                                                                   j.unique.len() +
                                                                   j.data.len());
                            data.extend(&j.handle);
                            data.put_slice(b"\0");
                            data.extend(&j.fname);
                            data.put_slice(b"\0");
                            data.extend(&j.unique);
                            data.put_slice(b"\0");
                            // reducer not implemented
                            data.put_slice(b"\0");
                            data.extend(&j.data);
                            return future::finished(new_res(JOB_ASSIGN_ALL, data)).boxed();
                        }
                        None => {}
                    }
                };
                future::finished(new_res(NO_JOB, BytesMut::new())).boxed()
            })
            .boxed()
    }

    fn handle_grab_job_uniq(&self, body: GearmanBody) -> BoxFuture<GearmanMessage, io::Error> {
        let mut queues = self.queues.clone();
        let worker = self.worker.clone();
        trace!("handle_grab_job_uniq");
        body.concat2()
            .and_then(move |_| {
                let mut worker = worker.lock().unwrap();
                let ref mut worker = worker;
                if queues.get_job(worker) {
                    match worker.job() {
                        Some(ref j) => {
                            let mut data = BytesMut::with_capacity(3 + j.handle.len() +
                                                                   j.fname.len() +
                                                                   j.unique.len() +
                                                                   j.data.len());
                            data.extend(&j.handle);
                            data.put_slice(b"\0");
                            data.extend(&j.fname);
                            data.put_slice(b"\0");
                            data.extend(&j.unique);
                            data.put_slice(b"\0");
                            data.extend(&j.data);
                            return future::finished(new_res(JOB_ASSIGN_UNIQ, data)).boxed();
                        }
                        None => {}
                    }
                };
                future::finished(new_res(NO_JOB, BytesMut::new())).boxed()
            })
            .boxed()
    }

    fn handle_grab_job(&self, body: GearmanBody) -> BoxFuture<GearmanMessage, io::Error> {
        let mut queues = self.queues.clone();
        let worker = self.worker.clone();
        trace!("handle_grab_job");
        body.concat2()
            .and_then(move |_| {
                let mut worker = worker.lock().unwrap();
                let ref mut worker = worker;
                if queues.get_job(worker) {
                    match worker.job() {
                        Some(ref j) => {
                            let mut data = BytesMut::with_capacity(2 + j.handle.len() +
                                                                   j.fname.len() +
                                                                   j.data.len());
                            data.extend(&j.handle);
                            data.put_slice(b"\0");
                            data.extend(&j.fname);
                            data.put_slice(b"\0");
                            data.extend(&j.data);
                            return future::finished(new_res(JOB_ASSIGN, data)).boxed();
                        }
                        None => {}
                    }
                };
                future::finished(new_res(NO_JOB, BytesMut::new())).boxed()
            })
            .boxed()
    }

    fn handle_pre_sleep(&self) -> BoxFuture<GearmanMessage, io::Error> {
        let worker = self.worker.clone();
        let ref mut w = worker.lock().unwrap();
        self.workers.clone().sleep(w, self.conn_id);
        future::finished(Self::no_response()).boxed()
    }

    fn handle_submit_job(&self,
                         priority: JobQueuePriority,
                         wait: bool,
                         body: GearmanBody)
                         -> BoxFuture<GearmanMessage, io::Error> {
        let mut queues = self.queues.clone();
        let conn_id = match wait {
            true => Some(self.conn_id),
            false => None,
        };
        let mut workers = self.workers.clone();
        let job_count = self.job_count.clone();

        body.concat2()
            .and_then(move |mut fields| {
                let fname = next_field(&mut fields).unwrap();
                let unique = next_field(&mut fields).unwrap();
                let data = fields.freeze();
                let mut add = false;
                let handle = match queues.coalesce_unique(&unique, conn_id) {
                    Some(handle) => handle,
                    None => {
                        workers.queue_wake(&fname);
                        // H:091234567890
                        let mut handle = BytesMut::with_capacity(12);
                        let job_num = job_count.fetch_add(1, Ordering::Relaxed);
                        debug!("job_num = {}", job_num);
                        handle.extend(format!("H:{:010}", job_num).as_bytes());
                        add = true;
                        handle.freeze()
                    }
                };
                if add {
                    let job = Arc::new(Job::new(fname, unique, data, handle.clone()));
                    info!("Created job {:?}", job);
                    queues.add_job(job.clone(), priority, conn_id);
                }
                future::finished(new_res(JOB_CREATED, BytesMut::from(handle)))
            })
            .boxed()
    }
}

impl Service for GearmanService {
    type Request = GearmanMessage;
    type Response = GearmanMessage;
    type Error = io::Error;
    type Future = BoxFuture<Self::Response, Self::Error>;

    fn call(&self, req: Self::Request) -> Self::Future {
        debug!("Got a req {:?}", req);
        match req {
            Message::WithoutBody(header) => {
                match header.ptype {
                    ADMIN_VERSION | ADMIN_STATUS => {
                        future::ok(self.response_from_header(&header)).boxed()
                    }

                    _ => {
                        future::err(io::Error::new(io::ErrorKind::Other,
                                                   format!("Bodyless packet type = {}",
                                                           header.ptype)))
                            .boxed()
                    }
                }
            }
            Message::WithBody(header, body) => {
                match header.ptype {
                    SUBMIT_JOB => self.handle_submit_job(PRIORITY_NORMAL, false, body),
                    SUBMIT_JOB_HIGH => self.handle_submit_job(PRIORITY_HIGH, false, body),
                    SUBMIT_JOB_LOW => self.handle_submit_job(PRIORITY_LOW, false, body),
                    SUBMIT_JOB_BG => self.handle_submit_job(PRIORITY_NORMAL, true, body),
                    SUBMIT_JOB_HIGH_BG => self.handle_submit_job(PRIORITY_HIGH, true, body),
                    SUBMIT_JOB_LOW_BG => self.handle_submit_job(PRIORITY_LOW, true, body),
                    PRE_SLEEP => self.handle_pre_sleep(),
                    CAN_DO => self.handle_can_do(body),
                    CANT_DO => self.handle_cant_do(body),
                    GRAB_JOB => self.handle_grab_job(body),
                    GRAB_JOB_UNIQ => self.handle_grab_job_uniq(body),
                    GRAB_JOB_ALL => self.handle_grab_job_all(body),/*
                    WORK_COMPLETE => self.handle_work_complete(),
                    WORK_STATUS | WORK_DATA | WORK_WARNING => self.handle_work_update(),
                    ECHO_REQ => self.handle_echo_req(&req),*/
                    _ => {
                        error!("Unimplemented: {:?} processing packet", header);
                        future::err(io::Error::new(io::ErrorKind::Other,
                                                   format!("Invalid packet type {}", header.ptype)))
                            .boxed()
                    }
                }
            }
        }
    }
}
<commit_msg>use put_u8 for micro success<commit_after>use std::io;
use std::sync::{Arc, Mutex};
use std::sync::atomic::{AtomicUsize, Ordering};

use futures::{future, Future, BoxFuture, Stream};
use tokio_proto::streaming::{Message, Body};
use tokio_service::Service;

use bytes::{BufMut, Bytes, BytesMut};

use admin;
use codec::PacketHeader;
use job::Job;
use packet::PacketMagic;
use queues::{HandleJobStorage, JobQueuePriority, SharedJobStorage};
use worker::{SharedWorkers, Worker, Wake};
use constants::*;

pub type GearmanBody = Body<BytesMut, io::Error>;
pub type GearmanMessage = Message<PacketHeader, GearmanBody>;

fn new_res(ptype: u32, data: BytesMut) -> GearmanMessage {
    Message::WithBody(PacketHeader {
                          magic: PacketMagic::RES,
                          ptype: ptype,
                          psize: data.len() as u32,
                      },
                      Body::from(data))
}

pub struct GearmanService {
    pub conn_id: usize,
    pub queues: SharedJobStorage,
    pub workers: SharedWorkers,
    pub worker: Arc<Mutex<Worker>>,
    pub job_count: Arc<AtomicUsize>,
}

fn next_field(buf: &mut BytesMut) -> Result<Bytes, io::Error> {
    match buf[..].iter().position(|b| *b == b'\0') {
        Some(null_pos) => {
            let value = buf.split_to(null_pos);
            buf.split_to(1);
            Ok(value.freeze())
        }
        None => Err(io::Error::new(io::ErrorKind::Other, "Can't find null")),
    }
}

impl GearmanService {
    /// Things that don't require a body should use this
    fn response_from_header(&self,
                            header: &PacketHeader)
                            -> Message<PacketHeader, Body<BytesMut, io::Error>> {
        match header.ptype {
            ADMIN_VERSION => {
                let resp_str = "OK some-rustygear-version\n";
                let mut resp_body = BytesMut::with_capacity(resp_str.len());
                resp_body.put(&resp_str[..]);
                let resp_body = Body::from(resp_body);
                Message::WithBody(PacketHeader {
                                      magic: PacketMagic::TEXT,
                                      ptype: header.ptype,
                                      psize: resp_str.len() as u32,
                                  },
                                  resp_body)
            }
            ADMIN_STATUS => admin::admin_command_status(self.queues.clone(), self.workers.clone()),
            _ => {
                panic!("response_from_header called with invalid ptype: {}",
                       header.ptype)
            }
        }
    }

    pub fn new(conn_id: usize,
               queues: SharedJobStorage,
               workers: SharedWorkers,
               job_count: Arc<AtomicUsize>)
               -> GearmanService {
        GearmanService {
            conn_id: conn_id,
            queues: queues.clone(),
            worker: Arc::new(Mutex::new((Worker::new()))),
            workers: workers.clone(),
            job_count: job_count.clone(),
        }
    }

    fn no_response() -> GearmanMessage {
        Message::WithBody(PacketHeader {
                              magic: PacketMagic::TEXT,
                              ptype: ADMIN_RESPONSE,
                              psize: 0,
                          },
                          Body::from(BytesMut::new()))
    }

    fn handle_can_do(&self, body: GearmanBody) -> BoxFuture<GearmanMessage, io::Error> {
        let worker = self.worker.clone();
        let workers = self.workers.clone();
        let conn_id = self.conn_id;
        trace!("handle_can_do");
        body.concat2()
            .and_then(move |fname| {
                let fname = fname.freeze();
                debug!("CAN_DO fname = {:?}", fname);
                let mut worker = worker.lock().unwrap();
                worker.can_do(fname);
                workers.clone().wakeup(&mut worker, conn_id);
                future::finished(Self::no_response())
            })
            .boxed()
    }

    fn handle_cant_do(&self, body: GearmanBody) -> BoxFuture<GearmanMessage, io::Error> {
        let worker = self.worker.clone();
        body.concat2()
            .and_then(move |fname| {
                let fname = fname.freeze();
                debug!("CANT_DO fname = {:?}", fname);
                let mut worker = worker.lock().unwrap();
                worker.cant_do(&fname);
                future::finished(Self::no_response())
            })
            .boxed()
    }

    fn handle_grab_job_all(&self, body: GearmanBody) -> BoxFuture<GearmanMessage, io::Error> {
        let mut queues = self.queues.clone();
        let worker = self.worker.clone();
        trace!("handle_grab_job_all");
        body.concat2()
            .and_then(move |_| {
                let mut worker = worker.lock().unwrap();
                let ref mut worker = worker;
                if queues.get_job(worker) {
                    match worker.job() {
                        Some(ref j) => {
                            let mut data = BytesMut::with_capacity(4 + j.handle.len() +
                                                                   j.fname.len() +
                                                                   j.unique.len() +
                                                                   j.data.len());
                            data.extend(&j.handle);
                            data.put_u8(b'\0');
                            data.extend(&j.fname);
                            data.put_u8(b'\0');
                            data.extend(&j.unique);
                            data.put_u8(b'\0');
                            // reducer not implemented
                            data.put_u8(b'\0');
                            data.extend(&j.data);
                            return future::finished(new_res(JOB_ASSIGN_ALL, data)).boxed();
                        }
                        None => {}
                    }
                };
                future::finished(new_res(NO_JOB, BytesMut::new())).boxed()
            })
            .boxed()
    }

    fn handle_grab_job_uniq(&self, body: GearmanBody) -> BoxFuture<GearmanMessage, io::Error> {
        let mut queues = self.queues.clone();
        let worker = self.worker.clone();
        trace!("handle_grab_job_uniq");
        body.concat2()
            .and_then(move |_| {
                let mut worker = worker.lock().unwrap();
                let ref mut worker = worker;
                if queues.get_job(worker) {
                    match worker.job() {
                        Some(ref j) => {
                            let mut data = BytesMut::with_capacity(3 + j.handle.len() +
                                                                   j.fname.len() +
                                                                   j.unique.len() +
                                                                   j.data.len());
                            data.extend(&j.handle);
                            data.put_u8(b'\0');
                            data.extend(&j.fname);
                            data.put_u8(b'\0');
                            data.extend(&j.unique);
                            data.put_u8(b'\0');
                            data.extend(&j.data);
                            return future::finished(new_res(JOB_ASSIGN_UNIQ, data)).boxed();
                        }
                        None => {}
                    }
                };
                future::finished(new_res(NO_JOB, BytesMut::new())).boxed()
            })
            .boxed()
    }

    fn handle_grab_job(&self, body: GearmanBody) -> BoxFuture<GearmanMessage, io::Error> {
        let mut queues = self.queues.clone();
        let worker = self.worker.clone();
        trace!("handle_grab_job");
        body.concat2()
            .and_then(move |_| {
                let mut worker = worker.lock().unwrap();
                let ref mut worker = worker;
                if queues.get_job(worker) {
                    match worker.job() {
                        Some(ref j) => {
                            let mut data = BytesMut::with_capacity(2 + j.handle.len() +
                                                                   j.fname.len() +
                                                                   j.data.len());
                            data.extend(&j.handle);
                            data.put_u8(b'\0');
                            data.extend(&j.fname);
                            data.put_u8(b'\0');
                            data.extend(&j.data);
                            return future::finished(new_res(JOB_ASSIGN, data)).boxed();
                        }
                        None => {}
                    }
                };
                future::finished(new_res(NO_JOB, BytesMut::new())).boxed()
            })
            .boxed()
    }

    fn handle_pre_sleep(&self) -> BoxFuture<GearmanMessage, io::Error> {
        let worker = self.worker.clone();
        let ref mut w = worker.lock().unwrap();
        self.workers.clone().sleep(w, self.conn_id);
        future::finished(Self::no_response()).boxed()
    }

    fn handle_submit_job(&self,
                         priority: JobQueuePriority,
                         wait: bool,
                         body: GearmanBody)
                         -> BoxFuture<GearmanMessage, io::Error> {
        let mut queues = self.queues.clone();
        let conn_id = match wait {
            true => Some(self.conn_id),
            false => None,
        };
        let mut workers = self.workers.clone();
        let job_count = self.job_count.clone();

        body.concat2()
            .and_then(move |mut fields| {
                let fname = next_field(&mut fields).unwrap();
                let unique = next_field(&mut fields).unwrap();
                let data = fields.freeze();
                let mut add = false;
                let handle = match queues.coalesce_unique(&unique, conn_id) {
                    Some(handle) => handle,
                    None => {
                        workers.queue_wake(&fname);
                        // H:091234567890
                        let mut handle = BytesMut::with_capacity(12);
                        let job_num = job_count.fetch_add(1, Ordering::Relaxed);
                        debug!("job_num = {}", job_num);
                        handle.extend(format!("H:{:010}", job_num).as_bytes());
                        add = true;
                        handle.freeze()
                    }
                };
                if add {
                    let job = Arc::new(Job::new(fname, unique, data, handle.clone()));
                    info!("Created job {:?}", job);
                    queues.add_job(job.clone(), priority, conn_id);
                }
                future::finished(new_res(JOB_CREATED, BytesMut::from(handle)))
            })
            .boxed()
    }
}

impl Service for GearmanService {
    type Request = GearmanMessage;
    type Response = GearmanMessage;
    type Error = io::Error;
    type Future = BoxFuture<Self::Response, Self::Error>;

    fn call(&self, req: Self::Request) -> Self::Future {
        debug!("Got a req {:?}", req);
        match req {
            Message::WithoutBody(header) => {
                match header.ptype {
                    ADMIN_VERSION | ADMIN_STATUS => {
                        future::ok(self.response_from_header(&header)).boxed()
                    }

                    _ => {
                        future::err(io::Error::new(io::ErrorKind::Other,
                                                   format!("Bodyless packet type = {}",
                                                           header.ptype)))
                            .boxed()
                    }
                }
            }
            Message::WithBody(header, body) => {
                match header.ptype {
                    SUBMIT_JOB => self.handle_submit_job(PRIORITY_NORMAL, false, body),
                    SUBMIT_JOB_HIGH => self.handle_submit_job(PRIORITY_HIGH, false, body),
                    SUBMIT_JOB_LOW => self.handle_submit_job(PRIORITY_LOW, false, body),
                    SUBMIT_JOB_BG => self.handle_submit_job(PRIORITY_NORMAL, true, body),
                    SUBMIT_JOB_HIGH_BG => self.handle_submit_job(PRIORITY_HIGH, true, body),
                    SUBMIT_JOB_LOW_BG => self.handle_submit_job(PRIORITY_LOW, true, body),
                    PRE_SLEEP => self.handle_pre_sleep(),
                    CAN_DO => self.handle_can_do(body),
                    CANT_DO => self.handle_cant_do(body),
                    GRAB_JOB => self.handle_grab_job(body),
                    GRAB_JOB_UNIQ => self.handle_grab_job_uniq(body),
                    GRAB_JOB_ALL => self.handle_grab_job_all(body),/*
                    WORK_COMPLETE => self.handle_work_complete(),
                    WORK_STATUS | WORK_DATA | WORK_WARNING => self.handle_work_update(),
                    ECHO_REQ => self.handle_echo_req(&req),*/
                    _ => {
                        error!("Unimplemented: {:?} processing packet", header);
                        future::err(io::Error::new(io::ErrorKind::Other,
                                                   format!("Invalid packet type {}", header.ptype)))
                            .boxed()
                    }
                }
            }
        }
    }
}
<|endoftext|>