<commit_before>#![feature(libc)]

extern crate rustc_serialize;
extern crate docopt;
extern crate libvterm_sys;
extern crate libc;

use libvterm_sys::*;
use std::io::prelude::*;
use std::slice;

enum Format { Plain, Sgr }

struct Context {
    cols_count: usize,
    rows_count: usize,
    format: Format,
}

fn color_to_index(state: &State, target: &Color) -> isize {
    for i in 0..256 {
        let color = state.get_palette_color(i);
        if color.red == target.red && color.green == target.green && color.blue == target.blue {
            return i as isize
        }
    }
    -1
}

fn dump_cell(state: &State, cell: &ScreenCell, prev_cell: &ScreenCell, context: &Context) {
    match context.format {
        Format::Plain => {},
        Format::Sgr => {
            let mut sgrs: Vec<isize> = vec!();

            if(!prev_cell.attrs.bold && cell.attrs.bold) {
                sgrs.push(1);
            }

            if(prev_cell.attrs.bold && !cell.attrs.bold) {
                sgrs.push(22);
            }

            if(prev_cell.attrs.underline == 0 && cell.attrs.underline != 0) {
                sgrs.push(4);
            }
            if(prev_cell.attrs.underline != 0 && cell.attrs.underline == 0) {
                sgrs.push(24);
            }

            if(!prev_cell.attrs.italic && cell.attrs.italic) {
                sgrs.push(3);
            }
            if(prev_cell.attrs.italic && !cell.attrs.italic) {
                sgrs.push(23);
            }

            if(!prev_cell.attrs.blink && cell.attrs.blink) {
                sgrs.push(5);
            }
            if(prev_cell.attrs.blink && !cell.attrs.blink) {
                sgrs.push(25);
            }

            if(!prev_cell.attrs.reverse && cell.attrs.reverse) {
                sgrs.push(7);
            }
            if(prev_cell.attrs.reverse && !cell.attrs.reverse) {
                sgrs.push(27);
            }

            if(!prev_cell.attrs.strike && cell.attrs.strike) {
                sgrs.push(9);
            }
            if(prev_cell.attrs.strike && !cell.attrs.strike) {
                sgrs.push(29);
            }

            if(prev_cell.attrs.font == 0 && cell.attrs.font != 0) {
                sgrs.push(10 + cell.attrs.font as isize);
            }
            if(prev_cell.attrs.font != 0 && cell.attrs.font == 0) {
                sgrs.push(10);
            }

            if(prev_cell.fg.red   != cell.fg.red   ||
               prev_cell.fg.green != cell.fg.green ||
               prev_cell.fg.blue  != cell.fg.blue) {
                let index = color_to_index(state, &cell.fg);
                if(index == -1) {
                    sgrs.push(39);
                }
                else if(index < 8) {
                    sgrs.push(30 + index);
                }
                else if(index < 16) {
                    sgrs.push(90 + (index - 8));
                }
                else {
                    sgrs.push(38);
                    sgrs.push(5 | (1<<31));
                    sgrs.push(index | (1<<31));
                }
            }

            if(prev_cell.bg.red   != cell.bg.red   ||
               prev_cell.bg.green != cell.bg.green ||
               prev_cell.bg.blue  != cell.bg.blue) {
                let index = color_to_index(state, &cell.bg);
                if(index == -1) {
                    sgrs.push(49);
                }
                else if(index < 8) {
                    sgrs.push(40 + index);
                }
                else if(index < 16) {
                    sgrs.push(100 + (index - 8));
                }
                else {
                    sgrs.push(48);
                    sgrs.push(5 | (1<<31));
                    sgrs.push(index | (1<<31));
                }
            }

            if sgrs.len() != 0 {
                print!("\x1b[");
                for (i, val) in sgrs.iter().enumerate() {
                    // not sure if this is really c7
                    let bare_val = val & !(1<<31);
                    if i == 0 {
                        print!("{}", bare_val);
                    }
                    else if val & (1<<31) != 0 {
                        print!(":{}", bare_val);
                    }
                    else {
                        print!(";{}", bare_val);
                    }
                }
                print!("m");
            }
        }
    }

    std::io::stdout().write_all(&cell.chars_as_utf8_bytes());
}

fn dump_eol(prev_cell: &ScreenCell, context: &Context) {
    match context.format {
        Format::Plain => {},
        Format::Sgr => {
            if(prev_cell.attrs.bold || prev_cell.attrs.underline != 0|| prev_cell.attrs.italic ||
                prev_cell.attrs.blink || prev_cell.attrs.reverse || prev_cell.attrs.strike ||
                prev_cell.attrs.font != 0) {
                print!("\x1b[m");
            }
        }
    }

    print!("\n");
}

fn dump_row(row: usize, vt: &VTerm, context: &Context) {
    let mut prev_cell: ScreenCell = Default::default();
    let (fg, bg) = vt.get_state().get_default_colors();
    prev_cell.fg = fg;
    prev_cell.bg = bg;

    let vts = vt.get_screen();

    let mut pos = Pos { row: row, col: 0 };
    while pos.col < context.cols_count {
        let cell = vts.get_cell(&pos);

        dump_cell(&vt.get_state(), &cell, &prev_cell, context);

        pos.col += cell.width as usize;
        prev_cell = cell;
    }

    dump_eol(&prev_cell, context);
}

const USAGE: &'static str = "
unterm

Usage:
unterm [--cols=<cols>] [--rows=<size>] [--format=<size>] <file>

Options:
--cols=<size>      number of columns to display
--rows=<size>      number of rows to display
--format=<format>  plain or sgr
";

#[derive(Debug, RustcDecodable)]
struct Args {
    flag_cols:    usize,
    flag_rows:    usize,
    flag_format:  String,
    arg_file:     String,
}

fn main() {
    let mut args: Args = docopt::Docopt::new(USAGE)
        .and_then(|d| d.decode())
        .unwrap_or_else(|e| e.exit());

    args.flag_rows   = if args.flag_rows         != 0 { args.flag_rows   } else { 25 };
    args.flag_cols   = if args.flag_cols         != 0 { args.flag_cols   } else { 80 };
    args.flag_format = if args.flag_format.len() != 0 { args.flag_format } else { "sgr".to_string() };

    let mut context = Context {
        rows_count: args.flag_rows,
        cols_count: args.flag_cols,
        format: if args.flag_format == "sgr" { Format::Sgr } else { Format::Plain },
    };

    let mut vt = VTerm::new(context.rows_count, context.cols_count);

    vt.set_utf8(true);

    let rx = vt.receive_screen_events();

    let mut vts: Screen = vt.get_screen();
    vts.reset(true);

    let mut file = std::fs::File::open(args.arg_file).unwrap();
    let mut read_buf = [0 as u8; 1024];
    loop {
        match file.read(&mut read_buf) {
            Ok(0)   => break,
            Ok(num) => { vt.write(&read_buf[0..num]); },
            Err(_)  => panic!("error reading from file")
        }
    }

    while let Ok(event) = rx.try_recv() {
        match event {
            ScreenEvent::Resize{rows: rows, cols: cols} =>  {
                context.rows_count = rows;
                context.cols_count = cols;
            },
            ScreenEvent::SbPushLine{cells: cells} => {
                let (fg, bg) = vt.get_state().get_default_colors();
                let mut prev_cell: ScreenCell = Default::default();
                prev_cell.fg = fg;
                prev_cell.bg = bg;

                for cell in cells {
                    dump_cell(&vt.get_state(), &cell, &prev_cell, &context);
                    prev_cell = cell
                }

                dump_eol(&prev_cell, &context);
            },
            _ => {},
        }
    }

    for row in 0..args.flag_rows {
        dump_row(row, &vt, &context);
    }
}
<commit_msg>Make cli options the same as the c version<commit_after>#![feature(libc)]

extern crate rustc_serialize;
extern crate docopt;
extern crate libvterm_sys;
extern crate libc;

use libvterm_sys::*;
use std::io::prelude::*;
use std::slice;

enum Format { Plain, Sgr }

struct Context {
    cols_count: usize,
    rows_count: usize,
    format: Format,
}

fn color_to_index(state: &State, target: &Color) -> isize {
    for i in 0..256 {
        let color = state.get_palette_color(i);
        if color.red == target.red && color.green == target.green && color.blue == target.blue {
            return i as isize
        }
    }
    -1
}

fn dump_cell(state: &State, cell: &ScreenCell, prev_cell: &ScreenCell, context: &Context) {
    match context.format {
        Format::Plain => {},
        Format::Sgr => {
            let mut sgrs: Vec<isize> = vec!();

            if(!prev_cell.attrs.bold && cell.attrs.bold) {
                sgrs.push(1);
            }

            if(prev_cell.attrs.bold && !cell.attrs.bold) {
                sgrs.push(22);
            }

            if(prev_cell.attrs.underline == 0 && cell.attrs.underline != 0) {
                sgrs.push(4);
            }
            if(prev_cell.attrs.underline != 0 && cell.attrs.underline == 0) {
                sgrs.push(24);
            }

            if(!prev_cell.attrs.italic && cell.attrs.italic) {
                sgrs.push(3);
            }
            if(prev_cell.attrs.italic && !cell.attrs.italic) {
                sgrs.push(23);
            }

            if(!prev_cell.attrs.blink && cell.attrs.blink) {
                sgrs.push(5);
            }
            if(prev_cell.attrs.blink && !cell.attrs.blink) {
                sgrs.push(25);
            }

            if(!prev_cell.attrs.reverse && cell.attrs.reverse) {
                sgrs.push(7);
            }
            if(prev_cell.attrs.reverse && !cell.attrs.reverse) {
                sgrs.push(27);
            }

            if(!prev_cell.attrs.strike && cell.attrs.strike) {
                sgrs.push(9);
            }
            if(prev_cell.attrs.strike && !cell.attrs.strike) {
                sgrs.push(29);
            }

            if(prev_cell.attrs.font == 0 && cell.attrs.font != 0) {
                sgrs.push(10 + cell.attrs.font as isize);
            }
            if(prev_cell.attrs.font != 0 && cell.attrs.font == 0) {
                sgrs.push(10);
            }

            if(prev_cell.fg.red   != cell.fg.red   ||
               prev_cell.fg.green != cell.fg.green ||
               prev_cell.fg.blue  != cell.fg.blue) {
                let index = color_to_index(state, &cell.fg);
                if(index == -1) {
                    sgrs.push(39);
                }
                else if(index < 8) {
                    sgrs.push(30 + index);
                }
                else if(index < 16) {
                    sgrs.push(90 + (index - 8));
                }
                else {
                    sgrs.push(38);
                    sgrs.push(5 | (1<<31));
                    sgrs.push(index | (1<<31));
                }
            }

            if(prev_cell.bg.red   != cell.bg.red   ||
               prev_cell.bg.green != cell.bg.green ||
               prev_cell.bg.blue  != cell.bg.blue) {
                let index = color_to_index(state, &cell.bg);
                if(index == -1) {
                    sgrs.push(49);
                }
                else if(index < 8) {
                    sgrs.push(40 + index);
                }
                else if(index < 16) {
                    sgrs.push(100 + (index - 8));
                }
                else {
                    sgrs.push(48);
                    sgrs.push(5 | (1<<31));
                    sgrs.push(index | (1<<31));
                }
            }

            if sgrs.len() != 0 {
                print!("\x1b[");
                for (i, val) in sgrs.iter().enumerate() {
                    // not sure if this is really c7
                    let bare_val = val & !(1<<31);
                    if i == 0 {
                        print!("{}", bare_val);
                    }
                    else if val & (1<<31) != 0 {
                        print!(":{}", bare_val);
                    }
                    else {
                        print!(";{}", bare_val);
                    }
                }
                print!("m");
            }
        }
    }

    std::io::stdout().write_all(&cell.chars_as_utf8_bytes());
}

fn dump_eol(prev_cell: &ScreenCell, context: &Context) {
    match context.format {
        Format::Plain => {},
        Format::Sgr => {
            if(prev_cell.attrs.bold || prev_cell.attrs.underline != 0|| prev_cell.attrs.italic ||
                prev_cell.attrs.blink || prev_cell.attrs.reverse || prev_cell.attrs.strike ||
                prev_cell.attrs.font != 0) {
                print!("\x1b[m");
            }
        }
    }

    print!("\n");
}

fn dump_row(row: usize, vt: &VTerm, context: &Context) {
    let mut prev_cell: ScreenCell = Default::default();
    let (fg, bg) = vt.get_state().get_default_colors();
    prev_cell.fg = fg;
    prev_cell.bg = bg;

    let vts = vt.get_screen();

    let mut pos = Pos { row: row, col: 0 };
    while pos.col < context.cols_count {
        let cell = vts.get_cell(&pos);

        dump_cell(&vt.get_state(), &cell, &prev_cell, context);

        pos.col += cell.width as usize;
        prev_cell = cell;
    }

    dump_eol(&prev_cell, context);
}

const USAGE: &'static str = "
unterm

Usage:
unterm [-c <cols>] [-l <lines>] [-f <format>] <file>

Options:
-c <cols>      number of columns to display
-l <lines>     number of lines in vterm before scrolling
-f <format>    plain or sgr
";

#[derive(Debug, RustcDecodable)]
struct Args {
    flag_c:    usize,
    flag_l:    usize,
    flag_f:    String,
    arg_file:  String,
}

fn main() {
    let mut args: Args = docopt::Docopt::new(USAGE)
        .and_then(|d| d.decode())
        .unwrap_or_else(|e| e.exit());

    args.flag_l = if args.flag_l       != 0 { args.flag_l } else { 25 };
    args.flag_c = if args.flag_c       != 0 { args.flag_c } else { 80 };
    args.flag_f = if args.flag_f.len() != 0 { args.flag_f } else { "sgr".to_string() };

    let mut context = Context {
        rows_count:  args.flag_l,
        cols_count:  args.flag_c,
        format:      if args.flag_f == "sgr" { Format::Sgr } else { Format::Plain },
    };

    let mut vt = VTerm::new(context.rows_count, context.cols_count);

    vt.set_utf8(true);

    let rx = vt.receive_screen_events();

    let mut vts: Screen = vt.get_screen();
    vts.reset(true);

    let mut file = std::fs::File::open(args.arg_file).unwrap();
    let mut read_buf = [0 as u8; 1024];
    loop {
        match file.read(&mut read_buf) {
            Ok(0)   => break,
            Ok(num) => { vt.write(&read_buf[0..num]); },
            Err(_)  => panic!("error reading from file")
        }
    }

    while let Ok(event) = rx.try_recv() {
        match event {
            ScreenEvent::Resize{rows: rows, cols: cols} =>  {
                context.rows_count = rows;
                context.cols_count = cols;
            },
            ScreenEvent::SbPushLine{cells: cells} => {
                let (fg, bg) = vt.get_state().get_default_colors();
                let mut prev_cell: ScreenCell = Default::default();
                prev_cell.fg = fg;
                prev_cell.bg = bg;

                for cell in cells {
                    dump_cell(&vt.get_state(), &cell, &prev_cell, &context);
                    prev_cell = cell
                }

                dump_eol(&prev_cell, &context);
            },
            _ => {},
        }
    }

    for row in 0..context.rows_count {
        dump_row(row, &vt, &context);
    }
}
<|endoftext|>


<commit_before>use std::sync::Arc;
use mio::*;
use mio::tcp::{TcpStream, TcpSocket};
use mio::buf::{ByteBuf, MutByteBuf};
use std::net::SocketAddr;
use std::net::lookup_host;
use std::collections::VecMap;
use url::Url;
use std::str;
use eventual;

#[derive(Debug, Clone)]
pub enum HttpAction {
    Get(Arc<Url>),
}

pub struct ClientInfo {
    tcp_stream: TcpStream,
    action: HttpAction,
    complete: eventual::Complete<Box<Vec<u8>>, &'static str>,
    mut_buf: Vec<u8>
}

impl ClientInfo {

    pub fn complete(self) {
        self.complete.complete(Box::new(self.mut_buf));
    }
}

pub struct Echo {
    client_info: VecMap<ClientInfo>,
}

impl Echo {
    pub fn new() -> Echo {
        Echo {
            client_info: VecMap::new(),
        }
    }
}

impl Handler for Echo {
    type Timeout = usize;
    type Message = (String, eventual::Complete<Box<Vec<u8>>, &'static str>);

    fn readable(&mut self, event_loop: &mut EventLoop<Echo>, token: Token, hint: ReadHint) {
        println!("foo {:?}", hint);
            let mut closed = false;

        if !hint.is_hup() {
            println!("READ!");
            let mut buf = ByteBuf::mut_with_capacity(4096 * 16);
            let mut client_info = self.client_info.get_mut(&token.as_usize()).unwrap();
            match client_info.tcp_stream.try_read_buf(&mut buf).unwrap() {
                Some(r) => {
                    println!("r:{}", r);
                    if r > 0 {
                        client_info.mut_buf.push_all(buf.flip().bytes());

                        event_loop.reregister(&client_info.tcp_stream, token,
                                              Interest::readable(),
                                              PollOpt::edge() | PollOpt::oneshot()).unwrap();
                    } else {
                        event_loop.deregister(&client_info.tcp_stream).unwrap();
                        closed = true;
                    }
                }
                _ => {
                    panic!("err!");
                }
            }

        } else {
            println!("Done!");
        }
        if closed {
                   self.client_info.remove(&token.as_usize()).unwrap().complete();
                   }

    }

    fn writable(&mut self, event_loop: &mut EventLoop<Echo>, token: Token) {
        let client_info = self.client_info.get_mut(&token.as_usize()).unwrap();
        let get_command: String = body(client_info.action.clone());
        match client_info.action {
            HttpAction::Get(_) => {
                let mut buf = ByteBuf::from_slice(get_command.as_bytes());
                match client_info.tcp_stream.try_write_buf(&mut buf) {
                    Ok(None) => {
                        panic!("client flushing buf; WOULDBLOCK");
                        //   self.buf = Some(buf);
                    }
                    Ok(Some(a)) => {
                        println!("Writable {}", a);
                    }
                    Err(e) => panic!("not implemented; client err={:?}", e),
                }

                event_loop.reregister(&client_info.tcp_stream, token, Interest::readable(),
                                      PollOpt::edge() | PollOpt::oneshot()).unwrap();
            }
        }
    }
    fn notify(&mut self,
              event_loop: &mut EventLoop<Echo>,
              tuple: (String, eventual::Complete<Box<Vec<u8>>, &'static str>)) {
        let token = Token(self.client_info.len() + 1);

        let action = get_action(tuple.0);
        match action.clone() {
            HttpAction::Get(url_p) => {
                let url: Url = (*url_p).clone();
                let ip = lookup_host(url.domain().unwrap()).unwrap().next().unwrap().unwrap();
                let port = url.port_or_default().unwrap();
                let address = SocketAddr::new(ip.ip(), port);
                let (sock, _) = TcpSocket::v4().unwrap().connect(&address).unwrap();
                let client_info = ClientInfo {
                    tcp_stream: sock,
                    action: action,
                    complete: tuple.1,
                    mut_buf: Vec::new()
                };

                event_loop.register_opt(&client_info.tcp_stream, token, Interest::writable(),
                                        PollOpt::edge() | PollOpt::oneshot()).unwrap();
                self.client_info.insert(token.as_usize(), client_info);
            }
        }
    }
}

fn body(action: HttpAction) -> String {
    match action {
        HttpAction::Get(ref resource) => {
            format!(
                "GET {}  HTTP/1.1\r\nHost: {}\r\nUser-Agent: curl/7.37.1\r\nAccept */*\r\nConnection: close \r\n\r\n",
                resource.serialize_path().unwrap(), resource.domain().unwrap())
        }
    }
}
fn get_action(url_s: String) -> HttpAction {
    let url = Url::parse(url_s.as_str()).unwrap();
    HttpAction::Get(Arc::new(url))
}<commit_msg>reduce output<commit_after>use std::sync::Arc;
use mio::*;
use mio::tcp::{TcpStream, TcpSocket};
use mio::buf::ByteBuf;
use std::net::SocketAddr;
use std::net::lookup_host;
use std::collections::VecMap;
use url::Url;

use eventual;

#[derive(Debug, Clone)]
pub enum HttpAction {
    Get(Arc<Url>),
}

pub struct ClientInfo {
    tcp_stream: TcpStream,
    action: HttpAction,
    complete: eventual::Complete<Box<Vec<u8>>, &'static str>,
    mut_buf: Vec<u8>
}

impl ClientInfo {

    pub fn complete(self) {
        self.complete.complete(Box::new(self.mut_buf));
    }
}

pub struct Echo {
    client_info: VecMap<ClientInfo>,
}

impl Echo {
    pub fn new() -> Echo {
        Echo {
            client_info: VecMap::new(),
        }
    }
}

impl Handler for Echo {
    type Timeout = usize;
    type Message = (String, eventual::Complete<Box<Vec<u8>>, &'static str>);

    fn readable(&mut self, event_loop: &mut EventLoop<Echo>, token: Token, hint: ReadHint) {
            let mut closed = false;

        if !hint.is_hup() {
            let mut buf = ByteBuf::mut_with_capacity(4096 * 16);
            let mut client_info = self.client_info.get_mut(&token.as_usize()).unwrap();
            match client_info.tcp_stream.try_read_buf(&mut buf).unwrap() {
                Some(r) => {
                    if r > 0 {
                        client_info.mut_buf.push_all(buf.flip().bytes());

                        event_loop.reregister(&client_info.tcp_stream, token,
                                              Interest::readable(),
                                              PollOpt::edge() | PollOpt::oneshot()).unwrap();
                    } else {
                        event_loop.deregister(&client_info.tcp_stream).unwrap();
                        closed = true;
                    }
                }
                _ => {
                    panic!("err!");
                }
            }

        } else {
        	            let client_info = self.client_info.remove(&token.as_usize()).unwrap();

 event_loop.deregister(&client_info.tcp_stream).unwrap();
                        closed = true;
                                }
        if closed {
                   self.client_info.remove(&token.as_usize()).unwrap().complete();
                   }

    }

    fn writable(&mut self, event_loop: &mut EventLoop<Echo>, token: Token) {
        let client_info = self.client_info.get_mut(&token.as_usize()).unwrap();
        let get_command: String = body(client_info.action.clone());
        match client_info.action {
            HttpAction::Get(_) => {
                let mut buf = ByteBuf::from_slice(get_command.as_bytes());
                match client_info.tcp_stream.try_write_buf(&mut buf) {
                    Ok(None) => {
                        panic!("client flushing buf; WOULDBLOCK");
                        //   self.buf = Some(buf);
                    }
                    Ok(Some(_)) => {}
                    Err(e) => panic!("not implemented; client err={:?}", e),
                }

                event_loop.reregister(&client_info.tcp_stream, token, Interest::readable(),
                                      PollOpt::edge() | PollOpt::oneshot()).unwrap();
            }
        }
    }
    fn notify(&mut self,
              event_loop: &mut EventLoop<Echo>,
              tuple: (String, eventual::Complete<Box<Vec<u8>>, &'static str>)) {
        let token = Token(self.client_info.len() + 1);

        let action = get_action(tuple.0);
        match action.clone() {
            HttpAction::Get(url_p) => {
                let url: Url = (*url_p).clone();
                let ip = lookup_host(url.domain().unwrap()).unwrap().next().unwrap().unwrap();
                let port = url.port_or_default().unwrap();
                let address = SocketAddr::new(ip.ip(), port);
                let (sock, _) = TcpSocket::v4().unwrap().connect(&address).unwrap();
                let client_info = ClientInfo {
                    tcp_stream: sock,
                    action: action,
                    complete: tuple.1,
                    mut_buf: Vec::new()
                };

                event_loop.register_opt(&client_info.tcp_stream, token, Interest::writable(),
                                        PollOpt::edge() | PollOpt::oneshot()).unwrap();
                self.client_info.insert(token.as_usize(), client_info);
            }
        }
    }
}

fn body(action: HttpAction) -> String {
    match action {
        HttpAction::Get(ref resource) => {
            format!(
                "GET {}  HTTP/1.1\r\nHost: {}\r\nUser-Agent: curl/7.37.1\r\nAccept */*\r\nConnection: close \r\n\r\n",
                resource.serialize_path().unwrap(), resource.domain().unwrap())
        }
    }
}
fn get_action(url_s: String) -> HttpAction {
    let url = Url::parse(url_s.as_str()).unwrap();
    HttpAction::Get(Arc::new(url))
}<|endoftext|>


<commit_before>use crate::syntax::namespace::Namespace;
use crate::syntax::Api;
use proc_macro2::Ident;
use std::collections::BTreeMap;
use std::iter::FromIterator;

pub struct NamespaceEntries<'a> {
    pub namespace: Namespace,
    direct: Vec<&'a Api>,
    nested: BTreeMap<&'a Ident, NamespaceEntries<'a>>,
}

impl<'a> NamespaceEntries<'a> {
    pub fn new(apis: &'a [Api]) -> Self {
        let api_refs = Vec::from_iter(apis);
        sort_by_inner_namespace(api_refs, 0)
    }

    pub fn direct_content(&self) -> &[&'a Api] {
        &self.direct
    }

    pub fn nested_content(&self) -> impl Iterator<Item = (&'a Ident, &NamespaceEntries<'a>)> {
        self.nested.iter().map(|(k, entries)| (*k, entries))
    }
}

fn sort_by_inner_namespace(apis: Vec<&Api>, depth: usize) -> NamespaceEntries {
    let mut direct = Vec::new();
    let mut nested_namespaces = BTreeMap::new();
    for api in &apis {
        if let Some(namespace) = api.namespace() {
            let first_ns_elem = namespace.iter().nth(depth);
            if let Some(first_ns_elem) = first_ns_elem {
                nested_namespaces
                    .entry(first_ns_elem)
                    .or_insert_with(Vec::new)
                    .push(*api);
                continue;
            }
        }
        direct.push(*api);
    }

    let nested = nested_namespaces
        .into_iter()
        .map(|(k, apis)| (k, sort_by_inner_namespace(apis, depth + 1)))
        .collect();

    let namespace = apis
        .first()
        .copied()
        .and_then(Api::namespace)
        .map_or(Namespace::ROOT, |ns| ns.iter().take(depth).collect());

    NamespaceEntries {
        namespace,
        direct,
        nested,
    }
}

#[cfg(test)]
mod tests {
    use super::NamespaceEntries;
    use crate::syntax::namespace::Namespace;
    use crate::syntax::{Api, Doc, ExternType, Pair};
    use proc_macro2::{Ident, Span};
    use syn::Token;

    #[test]
    fn test_ns_entries_sort() {
        let apis = &[
            make_api(None, "C"),
            make_api(None, "A"),
            make_api(Some("G"), "E"),
            make_api(Some("D"), "F"),
            make_api(Some("G"), "H"),
            make_api(Some("D::K"), "L"),
            make_api(Some("D::K"), "M"),
            make_api(None, "B"),
            make_api(Some("D"), "I"),
            make_api(Some("D"), "J"),
        ];

        let root = NamespaceEntries::new(apis);

        // ::
        let root_direct = root.direct_content();
        assert_eq!(root_direct.len(), 3);
        assert_ident(root_direct[0], "C");
        assert_ident(root_direct[1], "A");
        assert_ident(root_direct[2], "B");

        let mut root_nested = root.nested_content();
        let (id, d) = root_nested.next().unwrap();
        assert_eq!(id, "D");
        let (id, g) = root_nested.next().unwrap();
        assert_eq!(id, "G");
        assert!(root_nested.next().is_none());

        // ::D
        let d_direct = d.direct_content();
        assert_eq!(d_direct.len(), 3);
        assert_ident(d_direct[0], "F");
        assert_ident(d_direct[1], "I");
        assert_ident(d_direct[2], "J");

        let mut d_nested = d.nested_content();
        let (id, k) = d_nested.next().unwrap();
        assert_eq!(id, "K");

        // ::D::K
        let k_direct = k.direct_content();
        assert_eq!(k_direct.len(), 2);
        assert_ident(k_direct[0], "L");
        assert_ident(k_direct[1], "M");

        // ::G
        let g_direct = g.direct_content();
        assert_eq!(g_direct.len(), 2);
        assert_ident(g_direct[0], "E");
        assert_ident(g_direct[1], "H");

        let mut g_nested = g.nested_content();
        assert!(g_nested.next().is_none());
    }

    fn assert_ident(api: &Api, expected: &str) {
        if let Api::CxxType(cxx_type) = api {
            assert_eq!(cxx_type.ident.cxx.ident, expected);
        } else {
            unreachable!()
        }
    }

    fn make_api(ns: Option<&str>, ident: &str) -> Api {
        let ns = ns.map_or(Namespace::ROOT, |ns| syn::parse_str(ns).unwrap());
        Api::CxxType(ExternType {
            doc: Doc::new(),
            type_token: Token![type](Span::call_site()),
            ident: Pair::new(ns, Ident::new(ident, Span::call_site())),
            semi_token: Token![;](Span::call_site()),
            trusted: false,
        })
    }
}
<commit_msg>Remove namespace from NamespaceEntries<commit_after>use crate::syntax::Api;
use proc_macro2::Ident;
use std::collections::BTreeMap;
use std::iter::FromIterator;

pub struct NamespaceEntries<'a> {
    direct: Vec<&'a Api>,
    nested: BTreeMap<&'a Ident, NamespaceEntries<'a>>,
}

impl<'a> NamespaceEntries<'a> {
    pub fn new(apis: &'a [Api]) -> Self {
        let api_refs = Vec::from_iter(apis);
        sort_by_inner_namespace(api_refs, 0)
    }

    pub fn direct_content(&self) -> &[&'a Api] {
        &self.direct
    }

    pub fn nested_content(&self) -> impl Iterator<Item = (&'a Ident, &NamespaceEntries<'a>)> {
        self.nested.iter().map(|(k, entries)| (*k, entries))
    }
}

fn sort_by_inner_namespace(apis: Vec<&Api>, depth: usize) -> NamespaceEntries {
    let mut direct = Vec::new();
    let mut nested_namespaces = BTreeMap::new();
    for api in &apis {
        if let Some(namespace) = api.namespace() {
            let first_ns_elem = namespace.iter().nth(depth);
            if let Some(first_ns_elem) = first_ns_elem {
                nested_namespaces
                    .entry(first_ns_elem)
                    .or_insert_with(Vec::new)
                    .push(*api);
                continue;
            }
        }
        direct.push(*api);
    }

    let nested = nested_namespaces
        .into_iter()
        .map(|(k, apis)| (k, sort_by_inner_namespace(apis, depth + 1)))
        .collect();

    NamespaceEntries { direct, nested }
}

#[cfg(test)]
mod tests {
    use super::NamespaceEntries;
    use crate::syntax::namespace::Namespace;
    use crate::syntax::{Api, Doc, ExternType, Pair};
    use proc_macro2::{Ident, Span};
    use syn::Token;

    #[test]
    fn test_ns_entries_sort() {
        let apis = &[
            make_api(None, "C"),
            make_api(None, "A"),
            make_api(Some("G"), "E"),
            make_api(Some("D"), "F"),
            make_api(Some("G"), "H"),
            make_api(Some("D::K"), "L"),
            make_api(Some("D::K"), "M"),
            make_api(None, "B"),
            make_api(Some("D"), "I"),
            make_api(Some("D"), "J"),
        ];

        let root = NamespaceEntries::new(apis);

        // ::
        let root_direct = root.direct_content();
        assert_eq!(root_direct.len(), 3);
        assert_ident(root_direct[0], "C");
        assert_ident(root_direct[1], "A");
        assert_ident(root_direct[2], "B");

        let mut root_nested = root.nested_content();
        let (id, d) = root_nested.next().unwrap();
        assert_eq!(id, "D");
        let (id, g) = root_nested.next().unwrap();
        assert_eq!(id, "G");
        assert!(root_nested.next().is_none());

        // ::D
        let d_direct = d.direct_content();
        assert_eq!(d_direct.len(), 3);
        assert_ident(d_direct[0], "F");
        assert_ident(d_direct[1], "I");
        assert_ident(d_direct[2], "J");

        let mut d_nested = d.nested_content();
        let (id, k) = d_nested.next().unwrap();
        assert_eq!(id, "K");

        // ::D::K
        let k_direct = k.direct_content();
        assert_eq!(k_direct.len(), 2);
        assert_ident(k_direct[0], "L");
        assert_ident(k_direct[1], "M");

        // ::G
        let g_direct = g.direct_content();
        assert_eq!(g_direct.len(), 2);
        assert_ident(g_direct[0], "E");
        assert_ident(g_direct[1], "H");

        let mut g_nested = g.nested_content();
        assert!(g_nested.next().is_none());
    }

    fn assert_ident(api: &Api, expected: &str) {
        if let Api::CxxType(cxx_type) = api {
            assert_eq!(cxx_type.ident.cxx.ident, expected);
        } else {
            unreachable!()
        }
    }

    fn make_api(ns: Option<&str>, ident: &str) -> Api {
        let ns = ns.map_or(Namespace::ROOT, |ns| syn::parse_str(ns).unwrap());
        Api::CxxType(ExternType {
            doc: Doc::new(),
            type_token: Token![type](Span::call_site()),
            ident: Pair::new(ns, Ident::new(ident, Span::call_site())),
            semi_token: Token![;](Span::call_site()),
            trusted: false,
        })
    }
}
<|endoftext|>


<commit_before>pub use std::libc::*;
pub use std::libc::types::os::arch::extra::*;

pub type ATOM = WORD;
pub type UINT = c_uint;

// 32-bit specific
pub type UINT_PTR = c_uint;
pub type LONG_PTR = c_long;

pub type HANDLE = PVOID;

pub type HBRUSH = HANDLE;
pub type HCURSOR = HICON;
pub type HMENU = HANDLE;
pub type HICON = HANDLE;
pub type HINSTANCE = HANDLE;
pub type HWND = HANDLE;

pub type WPARAM = UINT_PTR;
pub type LPARAM = LONG_PTR;

pub type PVOID = *c_void;

// extern fn(HWND, UINT, WPARAM, LPARAM) -> LRESULT
pub type WNDPROC = *u8;

pub struct WNDCLASSEX {
    cbSize: UINT,
    style: UINT,
    lpfnWndProc: WNDPROC,
    cbClsExtra: c_int,
    cbWndExtra: c_int,
    hInstance: HINSTANCE,
    hIcon: HICON,
    hCursor: HCURSOR,
    hbrBackground: HBRUSH,
    lpszMenuName: LPCWSTR,
    lpszClassName: LPCWSTR,
    hIconSm: HICON,
}

pub mod user32 {
    use ll::*;
    extern "stdcall" {
        unsafe fn CreateWindowExW(extrastyle: DWORD, classname: LPCWSTR,
                windowname: LPCWSTR, style: DWORD,
                x: c_int, y: c_int, width: c_int, height: c_int,
                parent: HWND, menu: HMENU, instance: HINSTANCE, param: LPVOID
        ) -> HWND;

        unsafe fn MessageBoxW(
                hWnd: HWND, lpText: LPCWSTR, lpCaption: LPCWSTR, uType: UINT
        ) -> c_int;

        unsafe fn RegisterClassExW(lpwcx: *WNDCLASSEX) -> ATOM;

        unsafe fn DefWindowProcW(
                hwnd: HWND, msg: UINT, wparam: WPARAM, lparam: LPARAM
        ) -> LRESULT;
    }
}
<commit_msg>ll: add msg loop apis<commit_after>pub use std::libc::*;
pub use std::libc::types::os::arch::extra::*;

pub type ATOM = WORD;
pub type UINT = c_uint;
pub type LONG = c_long;

// 32-bit specific
pub type UINT_PTR = c_uint;
pub type LONG_PTR = c_long;

pub type HANDLE = PVOID;

pub type HBRUSH = HANDLE;
pub type HCURSOR = HICON;
pub type HMENU = HANDLE;
pub type HICON = HANDLE;
pub type HINSTANCE = HANDLE;
pub type HWND = HANDLE;

pub type WPARAM = UINT_PTR;
pub type LPARAM = LONG_PTR;

pub type PVOID = *c_void;

// extern fn(HWND, UINT, WPARAM, LPARAM) -> LRESULT
pub type WNDPROC = *u8;

pub struct WNDCLASSEX {
    cbSize: UINT,
    style: UINT,
    lpfnWndProc: WNDPROC,
    cbClsExtra: c_int,
    cbWndExtra: c_int,
    hInstance: HINSTANCE,
    hIcon: HICON,
    hCursor: HCURSOR,
    hbrBackground: HBRUSH,
    lpszMenuName: LPCWSTR,
    lpszClassName: LPCWSTR,
    hIconSm: HICON,
}

pub struct POINT {
    x: LONG,
    y: LONG,
}

pub struct MSG {
    hwnd: HWND,
    message: UINT,
    wParam: WPARAM,
    lParam: LPARAM,
    time: DWORD,
    pt: POINT,
}

pub mod user32 {
    use ll::*;
    extern "stdcall" {
        unsafe fn CreateWindowExW(extrastyle: DWORD, classname: LPCWSTR,
                windowname: LPCWSTR, style: DWORD,
                x: c_int, y: c_int, width: c_int, height: c_int,
                parent: HWND, menu: HMENU, instance: HINSTANCE, param: LPVOID
        ) -> HWND;

        unsafe fn MessageBoxW(
                hWnd: HWND, lpText: LPCWSTR, lpCaption: LPCWSTR, uType: UINT
        ) -> c_int;

        unsafe fn RegisterClassExW(lpwcx: *WNDCLASSEX) -> ATOM;

        unsafe fn DefWindowProcW(
                hwnd: HWND, msg: UINT, wparam: WPARAM, lparam: LPARAM
        ) -> LRESULT;

        unsafe fn GetMessageW(
                lpMsg: *MSG, hWnd: HWND,
                wMsgFilterMin: UINT, wMsgFilterMAx: UINT
        ) -> BOOL;

        unsafe fn PeekMessageW(
                lpMsg: *MSG, hWnd: HWND,
                wMsgFilterMin: UINT, wMsgFilterMAx: UINT, wRemoveMsg: UINT
        ) -> BOOL;

        unsafe fn TranslateMessage(lpMsg: *MSG) -> BOOL;

        unsafe fn DispatchMessageW(lpMsg: *MSG) -> LRESULT;
    }
}
<|endoftext|>


<commit_before>use super::{GethRPCClient, RPCObjectRequest, RPCObjectResponse};

use serde;
use serde_json;
use reqwest::Client;

#[derive(Serialize, Deserialize)]
struct Record {
    pub method: String,
    pub request: serde_json::Value,
    pub response: serde_json::Value,
}

pub struct RecordGethRPCClient {
    endpoint: String,
    free_id: usize,
    http: Client,
    records: Vec<Record>,
}

impl RecordGethRPCClient {
    pub fn new(endpoint: &str) -> Self {
        RecordGethRPCClient {
            endpoint: endpoint.to_string(),
            free_id: 1,
            http: Client::new(),
            records: Vec::new(),
        }
    }

    pub fn to_value(&self) -> serde_json::Value {
        serde_json::to_value(&self.records).unwrap()
    }
}

impl GethRPCClient for RecordGethRPCClient {
    fn rpc_object_request<Req: serde::Serialize, Res: serde::de::DeserializeOwned>(
        &mut self,
        method: &str,
        params: Req,
    ) -> Res {
        let request_value = serde_json::to_value(params).unwrap();
        let request = RPCObjectRequest {
            jsonrpc: "2.0".to_string(),
            method: method.to_string(),
            params: request_value.clone(),
            id: self.free_id,
        };
        self.free_id = self.free_id + 1;

        let mut response = self.http.post(&self.endpoint)
            .json(&request)
            .send()
            .unwrap();

        let response_value: serde_json::Value = response.json().unwrap();
        let response: RPCObjectResponse<Res> = serde_json::from_value(response_value.clone())
            .unwrap();

        self.records.push(Record {
            method: method.to_string(),
            request: request_value,
            response: response_value,
        });

        response.result
    }
}

pub struct CachedGethRPCClient {
    records: Vec<Record>,
}

impl CachedGethRPCClient {
    pub fn from_value(value: serde_json::Value) -> Self {
        CachedGethRPCClient { records: serde_json::from_value(value).unwrap() }
    }
}

impl GethRPCClient for CachedGethRPCClient {
    fn rpc_object_request<Req: serde::Serialize, Res: serde::de::DeserializeOwned>(
        &mut self,
        method: &str,
        params: Req,
    ) -> Res {
        let request_value = serde_json::to_value(params).unwrap();

        for record in &self.records {
            if &record.method == method && record.request == request_value {
                println!("response: {:#?}", record.response);
                let response: RPCObjectResponse<Res> =
                    serde_json::from_value(record.response.clone()).unwrap();
                return response.result;
            }
        }

        panic!()
    }
}
<commit_msg>remove debug log line<commit_after>use super::{GethRPCClient, RPCObjectRequest, RPCObjectResponse};

use serde;
use serde_json;
use reqwest::Client;

#[derive(Serialize, Deserialize)]
struct Record {
    pub method: String,
    pub request: serde_json::Value,
    pub response: serde_json::Value,
}

pub struct RecordGethRPCClient {
    endpoint: String,
    free_id: usize,
    http: Client,
    records: Vec<Record>,
}

impl RecordGethRPCClient {
    pub fn new(endpoint: &str) -> Self {
        RecordGethRPCClient {
            endpoint: endpoint.to_string(),
            free_id: 1,
            http: Client::new(),
            records: Vec::new(),
        }
    }

    pub fn to_value(&self) -> serde_json::Value {
        serde_json::to_value(&self.records).unwrap()
    }
}

impl GethRPCClient for RecordGethRPCClient {
    fn rpc_object_request<Req: serde::Serialize, Res: serde::de::DeserializeOwned>(
        &mut self,
        method: &str,
        params: Req,
    ) -> Res {
        let request_value = serde_json::to_value(params).unwrap();
        let request = RPCObjectRequest {
            jsonrpc: "2.0".to_string(),
            method: method.to_string(),
            params: request_value.clone(),
            id: self.free_id,
        };
        self.free_id = self.free_id + 1;

        let mut response = self.http.post(&self.endpoint)
            .json(&request)
            .send()
            .unwrap();

        let response_value: serde_json::Value = response.json().unwrap();
        let response: RPCObjectResponse<Res> = serde_json::from_value(response_value.clone())
            .unwrap();

        self.records.push(Record {
            method: method.to_string(),
            request: request_value,
            response: response_value,
        });

        response.result
    }
}

pub struct CachedGethRPCClient {
    records: Vec<Record>,
}

impl CachedGethRPCClient {
    pub fn from_value(value: serde_json::Value) -> Self {
        CachedGethRPCClient { records: serde_json::from_value(value).unwrap() }
    }
}

impl GethRPCClient for CachedGethRPCClient {
    fn rpc_object_request<Req: serde::Serialize, Res: serde::de::DeserializeOwned>(
        &mut self,
        method: &str,
        params: Req,
    ) -> Res {
        let request_value = serde_json::to_value(params).unwrap();

        for record in &self.records {
            if &record.method == method && record.request == request_value {
                let response: RPCObjectResponse<Res> =
                    serde_json::from_value(record.response.clone()).unwrap();
                return response.result;
            }
        }

        panic!()
    }
}
<|endoftext|>


<commit_before>// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Interfaces to the operating system provided random number
//! generators.

pub use self::imp::OsRng;

#[cfg(unix)]
mod imp {
    use io::{IoResult, File};
    use path::Path;
    use rand::Rng;
    use rand::reader::ReaderRng;
    use result::{Ok, Err};

    /// A random number generator that retrieves randomness straight from
    /// the operating system. Platform sources:
    ///
    /// - Unix-like systems (Linux, Android, Mac OSX): read directly from
    ///   `/dev/urandom`.
    /// - Windows: calls `CryptGenRandom`, using the default cryptographic
    ///   service provider with the `PROV_RSA_FULL` type.
    ///
    /// This does not block.
    #[cfg(unix)]
    pub struct OsRng {
        inner: ReaderRng<File>
    }

    impl OsRng {
        /// Create a new `OsRng`.
        pub fn new() -> IoResult<OsRng> {
            let reader = try!(File::open(&Path::new("/dev/urandom")));
            let reader_rng = ReaderRng::new(reader);

            Ok(OsRng { inner: reader_rng })
        }
    }

    impl Rng for OsRng {
        fn next_u32(&mut self) -> u32 {
            self.inner.next_u32()
        }
        fn next_u64(&mut self) -> u64 {
            self.inner.next_u64()
        }
        fn fill_bytes(&mut self, v: &mut [u8]) {
            self.inner.fill_bytes(v)
        }
    }
}

#[cfg(windows)]
mod imp {
    extern crate libc;

    use container::Container;
    use io::{IoResult, IoError};
    use mem;
    use ops::Drop;
    use os;
    use rand::Rng;
    use result::{Ok, Err};
    use rt::stack;
    use self::libc::{c_ulong, DWORD, BYTE, LPCSTR, BOOL};
    use slice::MutableVector;

    type HCRYPTPROV = c_ulong;

    /// A random number generator that retrieves randomness straight from
    /// the operating system. Platform sources:
    ///
    /// - Unix-like systems (Linux, Android, Mac OSX): read directly from
    ///   `/dev/urandom`.
    /// - Windows: calls `CryptGenRandom`, using the default cryptographic
    ///   service provider with the `PROV_RSA_FULL` type.
    ///
    /// This does not block.
    pub struct OsRng {
        hcryptprov: HCRYPTPROV
    }

    static PROV_RSA_FULL: DWORD = 1;
    static CRYPT_SILENT: DWORD = 64;
    static CRYPT_VERIFYCONTEXT: DWORD = 0xF0000000;
    static NTE_BAD_SIGNATURE: DWORD = 0x80090006;

    extern "system" {
        fn CryptAcquireContextA(phProv: *mut HCRYPTPROV,
                                pszContainer: LPCSTR,
                                pszProvider: LPCSTR,
                                dwProvType: DWORD,
                                dwFlags: DWORD) -> BOOL;
        fn CryptGenRandom(hProv: HCRYPTPROV,
                          dwLen: DWORD,
                          pbBuffer: *mut BYTE) -> BOOL;
        fn CryptReleaseContext(hProv: HCRYPTPROV, dwFlags: DWORD) -> BOOL;
    }

    impl OsRng {
        /// Create a new `OsRng`.
        pub fn new() -> IoResult<OsRng> {
            let mut hcp = 0;
            let mut ret = unsafe {
                CryptAcquireContextA(&mut hcp, 0 as LPCSTR, 0 as LPCSTR,
                                     PROV_RSA_FULL,
                                     CRYPT_VERIFYCONTEXT | CRYPT_SILENT)
            };

            // FIXME #13259:
            // It turns out that if we can't acquire a context with the
            // NTE_BAD_SIGNATURE error code, the documentation states:
            //
            //     The provider DLL signature could not be verified. Either the
            //     DLL or the digital signature has been tampered with.
            //
            // Sounds fishy, no? As it turns out, our signature can be bad
            // because our Thread Information Block (TIB) isn't exactly what it
            // expects. As to why, I have no idea. The only data we store in the
            // TIB is the stack limit for each thread, but apparently that's
            // enough to make the signature valid.
            //
            // Furthermore, this error only happens the *first* time we call
            // CryptAcquireContext, so we don't have to worry about future
            // calls.
            //
            // Anyway, the fix employed here is that if we see this error, we
            // pray that we're not close to the end of the stack, temporarily
            // set the stack limit to 0 (what the TIB originally was), acquire a
            // context, and then reset the stack limit.
            //
            // Again, I'm not sure why this is the fix, nor why we're getting
            // this error. All I can say is that this seems to allow libnative
            // to progress where it otherwise would be hindered. Who knew?
            if ret == 0 && os::errno() as DWORD == NTE_BAD_SIGNATURE {
                unsafe {
                    let limit = stack::get_sp_limit();
                    stack::record_sp_limit(0);
                    ret = CryptAcquireContextA(&mut hcp, 0 as LPCSTR, 0 as LPCSTR,
                                               PROV_RSA_FULL,
                                               CRYPT_VERIFYCONTEXT | CRYPT_SILENT);
                    stack::record_sp_limit(limit);
                }
            }

            if ret == 0 {
                Err(IoError::last_error())
            } else {
                Ok(OsRng { hcryptprov: hcp })
            }
        }
    }

    impl Rng for OsRng {
        fn next_u32(&mut self) -> u32 {
            let mut v = [0u8, .. 4];
            self.fill_bytes(v);
            unsafe { mem::transmute(v) }
        }
        fn next_u64(&mut self) -> u64 {
            let mut v = [0u8, .. 8];
            self.fill_bytes(v);
            unsafe { mem::transmute(v) }
        }
        fn fill_bytes(&mut self, v: &mut [u8]) {
            let ret = unsafe {
                CryptGenRandom(self.hcryptprov, v.len() as DWORD,
                               v.as_mut_ptr())
            };
            if ret == 0 {
                fail!("couldn't generate random bytes: {}", os::last_os_error());
            }
        }
    }

    impl Drop for OsRng {
        fn drop(&mut self) {
            let ret = unsafe {
                CryptReleaseContext(self.hcryptprov, 0)
            };
            if ret == 0 {
                fail!("couldn't release context: {}", os::last_os_error());
            }
        }
    }
}

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

    use super::OsRng;
    use rand::Rng;
    use task;

    #[test]
    fn test_os_rng() {
        let mut r = OsRng::new().unwrap();

        r.next_u32();
        r.next_u64();

        let mut v = [0u8, .. 1000];
        r.fill_bytes(v);
    }

    #[test]
    fn test_os_rng_tasks() {

        let mut txs = vec!();
        for _ in range(0, 20) {
            let (tx, rx) = channel();
            txs.push(tx);
            task::spawn(proc() {
                // wait until all the tasks are ready to go.
                rx.recv();

                // deschedule to attempt to interleave things as much
                // as possible (XXX: is this a good test?)
                let mut r = OsRng::new().unwrap();
                task::deschedule();
                let mut v = [0u8, .. 1000];

                for _ in range(0, 100) {
                    r.next_u32();
                    task::deschedule();
                    r.next_u64();
                    task::deschedule();
                    r.fill_bytes(v);
                    task::deschedule();
                }
            })
        }

        // start all the tasks
        for tx in txs.iter() {
            tx.send(())
        }
    }
}
<commit_msg>windows: Allow snake_case errors for now.<commit_after>// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Interfaces to the operating system provided random number
//! generators.

pub use self::imp::OsRng;

#[cfg(unix)]
mod imp {
    use io::{IoResult, File};
    use path::Path;
    use rand::Rng;
    use rand::reader::ReaderRng;
    use result::{Ok, Err};

    /// A random number generator that retrieves randomness straight from
    /// the operating system. Platform sources:
    ///
    /// - Unix-like systems (Linux, Android, Mac OSX): read directly from
    ///   `/dev/urandom`.
    /// - Windows: calls `CryptGenRandom`, using the default cryptographic
    ///   service provider with the `PROV_RSA_FULL` type.
    ///
    /// This does not block.
    #[cfg(unix)]
    pub struct OsRng {
        inner: ReaderRng<File>
    }

    impl OsRng {
        /// Create a new `OsRng`.
        pub fn new() -> IoResult<OsRng> {
            let reader = try!(File::open(&Path::new("/dev/urandom")));
            let reader_rng = ReaderRng::new(reader);

            Ok(OsRng { inner: reader_rng })
        }
    }

    impl Rng for OsRng {
        fn next_u32(&mut self) -> u32 {
            self.inner.next_u32()
        }
        fn next_u64(&mut self) -> u64 {
            self.inner.next_u64()
        }
        fn fill_bytes(&mut self, v: &mut [u8]) {
            self.inner.fill_bytes(v)
        }
    }
}

#[cfg(windows)]
mod imp {
    extern crate libc;

    use container::Container;
    use io::{IoResult, IoError};
    use mem;
    use ops::Drop;
    use os;
    use rand::Rng;
    use result::{Ok, Err};
    use rt::stack;
    use self::libc::{c_ulong, DWORD, BYTE, LPCSTR, BOOL};
    use slice::MutableVector;

    type HCRYPTPROV = c_ulong;

    /// A random number generator that retrieves randomness straight from
    /// the operating system. Platform sources:
    ///
    /// - Unix-like systems (Linux, Android, Mac OSX): read directly from
    ///   `/dev/urandom`.
    /// - Windows: calls `CryptGenRandom`, using the default cryptographic
    ///   service provider with the `PROV_RSA_FULL` type.
    ///
    /// This does not block.
    pub struct OsRng {
        hcryptprov: HCRYPTPROV
    }

    static PROV_RSA_FULL: DWORD = 1;
    static CRYPT_SILENT: DWORD = 64;
    static CRYPT_VERIFYCONTEXT: DWORD = 0xF0000000;
    static NTE_BAD_SIGNATURE: DWORD = 0x80090006;

    #[allow(non_snake_case_functions)]
    extern "system" {
        fn CryptAcquireContextA(phProv: *mut HCRYPTPROV,
                                pszContainer: LPCSTR,
                                pszProvider: LPCSTR,
                                dwProvType: DWORD,
                                dwFlags: DWORD) -> BOOL;
        fn CryptGenRandom(hProv: HCRYPTPROV,
                          dwLen: DWORD,
                          pbBuffer: *mut BYTE) -> BOOL;
        fn CryptReleaseContext(hProv: HCRYPTPROV, dwFlags: DWORD) -> BOOL;
    }

    impl OsRng {
        /// Create a new `OsRng`.
        pub fn new() -> IoResult<OsRng> {
            let mut hcp = 0;
            let mut ret = unsafe {
                CryptAcquireContextA(&mut hcp, 0 as LPCSTR, 0 as LPCSTR,
                                     PROV_RSA_FULL,
                                     CRYPT_VERIFYCONTEXT | CRYPT_SILENT)
            };

            // FIXME #13259:
            // It turns out that if we can't acquire a context with the
            // NTE_BAD_SIGNATURE error code, the documentation states:
            //
            //     The provider DLL signature could not be verified. Either the
            //     DLL or the digital signature has been tampered with.
            //
            // Sounds fishy, no? As it turns out, our signature can be bad
            // because our Thread Information Block (TIB) isn't exactly what it
            // expects. As to why, I have no idea. The only data we store in the
            // TIB is the stack limit for each thread, but apparently that's
            // enough to make the signature valid.
            //
            // Furthermore, this error only happens the *first* time we call
            // CryptAcquireContext, so we don't have to worry about future
            // calls.
            //
            // Anyway, the fix employed here is that if we see this error, we
            // pray that we're not close to the end of the stack, temporarily
            // set the stack limit to 0 (what the TIB originally was), acquire a
            // context, and then reset the stack limit.
            //
            // Again, I'm not sure why this is the fix, nor why we're getting
            // this error. All I can say is that this seems to allow libnative
            // to progress where it otherwise would be hindered. Who knew?
            if ret == 0 && os::errno() as DWORD == NTE_BAD_SIGNATURE {
                unsafe {
                    let limit = stack::get_sp_limit();
                    stack::record_sp_limit(0);
                    ret = CryptAcquireContextA(&mut hcp, 0 as LPCSTR, 0 as LPCSTR,
                                               PROV_RSA_FULL,
                                               CRYPT_VERIFYCONTEXT | CRYPT_SILENT);
                    stack::record_sp_limit(limit);
                }
            }

            if ret == 0 {
                Err(IoError::last_error())
            } else {
                Ok(OsRng { hcryptprov: hcp })
            }
        }
    }

    impl Rng for OsRng {
        fn next_u32(&mut self) -> u32 {
            let mut v = [0u8, .. 4];
            self.fill_bytes(v);
            unsafe { mem::transmute(v) }
        }
        fn next_u64(&mut self) -> u64 {
            let mut v = [0u8, .. 8];
            self.fill_bytes(v);
            unsafe { mem::transmute(v) }
        }
        fn fill_bytes(&mut self, v: &mut [u8]) {
            let ret = unsafe {
                CryptGenRandom(self.hcryptprov, v.len() as DWORD,
                               v.as_mut_ptr())
            };
            if ret == 0 {
                fail!("couldn't generate random bytes: {}", os::last_os_error());
            }
        }
    }

    impl Drop for OsRng {
        fn drop(&mut self) {
            let ret = unsafe {
                CryptReleaseContext(self.hcryptprov, 0)
            };
            if ret == 0 {
                fail!("couldn't release context: {}", os::last_os_error());
            }
        }
    }
}

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

    use super::OsRng;
    use rand::Rng;
    use task;

    #[test]
    fn test_os_rng() {
        let mut r = OsRng::new().unwrap();

        r.next_u32();
        r.next_u64();

        let mut v = [0u8, .. 1000];
        r.fill_bytes(v);
    }

    #[test]
    fn test_os_rng_tasks() {

        let mut txs = vec!();
        for _ in range(0, 20) {
            let (tx, rx) = channel();
            txs.push(tx);
            task::spawn(proc() {
                // wait until all the tasks are ready to go.
                rx.recv();

                // deschedule to attempt to interleave things as much
                // as possible (XXX: is this a good test?)
                let mut r = OsRng::new().unwrap();
                task::deschedule();
                let mut v = [0u8, .. 1000];

                for _ in range(0, 100) {
                    r.next_u32();
                    task::deschedule();
                    r.next_u64();
                    task::deschedule();
                    r.fill_bytes(v);
                    task::deschedule();
                }
            })
        }

        // start all the tasks
        for tx in txs.iter() {
            tx.send(())
        }
    }
}
<|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/. */

use dom::bindings::codegen::Bindings::RequestBinding::RequestInfo;
use dom::bindings::codegen::Bindings::RequestBinding::RequestInit;
use dom::bindings::codegen::Bindings::ResponseBinding::ResponseBinding::ResponseMethods;
use dom::bindings::codegen::Bindings::ResponseBinding::ResponseType as DOMResponseType;
use dom::bindings::error::Error;
use dom::bindings::inheritance::Castable;
use dom::bindings::refcounted::{Trusted, TrustedPromise};
use dom::bindings::reflector::DomObject;
use dom::bindings::root::DomRoot;
use dom::bindings::trace::RootedTraceableBox;
use dom::globalscope::GlobalScope;
use dom::headers::Guard;
use dom::promise::Promise;
use dom::request::Request;
use dom::response::Response;
use dom::serviceworkerglobalscope::ServiceWorkerGlobalScope;
use ipc_channel::ipc;
use ipc_channel::router::ROUTER;
use js::jsapi::JSAutoCompartment;
use net_traits::{FetchChannels, FetchResponseListener, NetworkError};
use net_traits::{FilteredMetadata, FetchMetadata, Metadata};
use net_traits::CoreResourceMsg::Fetch as NetTraitsFetch;
use net_traits::request::{Request as NetTraitsRequest, ServiceWorkersMode};
use net_traits::request::RequestInit as NetTraitsRequestInit;
use network_listener::{NetworkListener, PreInvoke};
use servo_url::ServoUrl;
use std::mem;
use std::rc::Rc;
use std::sync::{Arc, Mutex};

struct FetchContext {
    fetch_promise: Option<TrustedPromise>,
    response_object: Trusted<Response>,
    body: Vec<u8>,
}

fn from_referrer_to_referrer_url(request: &NetTraitsRequest) -> Option<ServoUrl> {
    request.referrer.to_url().map(|url| url.clone())
}

fn request_init_from_request(request: NetTraitsRequest) -> NetTraitsRequestInit {
    NetTraitsRequestInit {
        method: request.method.clone(),
        url: request.url(),
        headers: request.headers.clone(),
        unsafe_request: request.unsafe_request,
        body: request.body.clone(),
        destination: request.destination,
        synchronous: request.synchronous,
        mode: request.mode.clone(),
        use_cors_preflight: request.use_cors_preflight,
        credentials_mode: request.credentials_mode,
        use_url_credentials: request.use_url_credentials,
        origin: GlobalScope::current().expect("No current global object").origin().immutable().clone(),
        referrer_url: from_referrer_to_referrer_url(&request),
        referrer_policy: request.referrer_policy,
        pipeline_id: request.pipeline_id,
        redirect_mode: request.redirect_mode,
        ..NetTraitsRequestInit::default()
    }
}

// https://fetch.spec.whatwg.org/#fetch-method
#[allow(unrooted_must_root)]
pub fn Fetch(global: &GlobalScope, input: RequestInfo, init: RootedTraceableBox<RequestInit>) -> Rc<Promise> {
    let core_resource_thread = global.core_resource_thread();

    // Step 1
    let promise = Promise::new(global);
    let response = Response::new(global);

    // Step 2
    let request = match Request::Constructor(global, input, init) {
        Err(e) => {
            promise.reject_error(e);
            return promise;
        },
        Ok(r) => r.get_request(),
    };
    let mut request_init = request_init_from_request(request);

    // Step 3
    if global.downcast::<ServiceWorkerGlobalScope>().is_some() {
        request_init.service_workers_mode = ServiceWorkersMode::Foreign;
    }

    // Step 4
    response.Headers().set_guard(Guard::Immutable);

    // Step 5
    let (action_sender, action_receiver) = ipc::channel().unwrap();
    let fetch_context = Arc::new(Mutex::new(FetchContext {
        fetch_promise: Some(TrustedPromise::new(promise.clone())),
        response_object: Trusted::new(&*response),
        body: vec![],
    }));
    let listener = NetworkListener {
        context: fetch_context,
        task_source: global.networking_task_source(),
        canceller: Some(global.task_canceller())
    };

    ROUTER.add_route(action_receiver.to_opaque(), Box::new(move |message| {
        listener.notify_fetch(message.to().unwrap());
    }));
    core_resource_thread.send(
        NetTraitsFetch(request_init, FetchChannels::ResponseMsg(action_sender))).unwrap();

    promise
}

impl PreInvoke for FetchContext {}

impl FetchResponseListener for FetchContext {
    fn process_request_body(&mut self) {
        // TODO
    }

    fn process_request_eof(&mut self) {
        // TODO
    }

    #[allow(unrooted_must_root)]
    fn process_response(&mut self, fetch_metadata: Result<FetchMetadata, NetworkError>) {
        let promise = self.fetch_promise.take().expect("fetch promise is missing").root();

        // JSAutoCompartment needs to be manually made.
        // Otherwise, Servo will crash.
        let promise_cx = promise.global().get_cx();
        let _ac = JSAutoCompartment::new(promise_cx, promise.reflector().get_jsobject().get());
        match fetch_metadata {
            // Step 4.1
            Err(_) => {
                promise.reject_error(Error::Type("Network error occurred".to_string()));
                self.fetch_promise = Some(TrustedPromise::new(promise));
                self.response_object.root().set_type(DOMResponseType::Error);
                return;
            },
            // Step 4.2
            Ok(metadata) => {
                match metadata {
                    FetchMetadata::Unfiltered(m) => {
                        fill_headers_with_metadata(self.response_object.root(), m);
                        self.response_object.root().set_type(DOMResponseType::Default);
                    },
                    FetchMetadata::Filtered { filtered, .. } => match filtered {
                        FilteredMetadata::Basic(m) => {
                            fill_headers_with_metadata(self.response_object.root(), m);
                            self.response_object.root().set_type(DOMResponseType::Basic);
                        },
                        FilteredMetadata::Cors(m) => {
                            fill_headers_with_metadata(self.response_object.root(), m);
                            self.response_object.root().set_type(DOMResponseType::Cors);
                        },
                        FilteredMetadata::Opaque =>
                            self.response_object.root().set_type(DOMResponseType::Opaque),
                        FilteredMetadata::OpaqueRedirect =>
                            self.response_object.root().set_type(DOMResponseType::Opaqueredirect)
                    }
                }
            }
        }
        // Step 4.3
        promise.resolve_native(&self.response_object.root());
        self.fetch_promise = Some(TrustedPromise::new(promise));
    }

    fn process_response_chunk(&mut self, mut chunk: Vec<u8>) {
        self.body.append(&mut chunk);
    }

    fn process_response_eof(&mut self, _response: Result<(), NetworkError>) {
        let response = self.response_object.root();
        let global = response.global();
        let cx = global.get_cx();
        let _ac = JSAutoCompartment::new(cx, global.reflector().get_jsobject().get());
        response.finish(mem::replace(&mut self.body, vec![]));
        // TODO
        // ... trailerObject is not supported in Servo yet.
    }
}

fn fill_headers_with_metadata(r: DomRoot<Response>, m: Metadata) {
    r.set_headers(m.headers);
    r.set_raw_status(m.status);
    r.set_final_url(m.final_url);
}
<commit_msg>pass cache_mode from request to request init<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/. */

use dom::bindings::codegen::Bindings::RequestBinding::RequestInfo;
use dom::bindings::codegen::Bindings::RequestBinding::RequestInit;
use dom::bindings::codegen::Bindings::ResponseBinding::ResponseBinding::ResponseMethods;
use dom::bindings::codegen::Bindings::ResponseBinding::ResponseType as DOMResponseType;
use dom::bindings::error::Error;
use dom::bindings::inheritance::Castable;
use dom::bindings::refcounted::{Trusted, TrustedPromise};
use dom::bindings::reflector::DomObject;
use dom::bindings::root::DomRoot;
use dom::bindings::trace::RootedTraceableBox;
use dom::globalscope::GlobalScope;
use dom::headers::Guard;
use dom::promise::Promise;
use dom::request::Request;
use dom::response::Response;
use dom::serviceworkerglobalscope::ServiceWorkerGlobalScope;
use ipc_channel::ipc;
use ipc_channel::router::ROUTER;
use js::jsapi::JSAutoCompartment;
use net_traits::{FetchChannels, FetchResponseListener, NetworkError};
use net_traits::{FilteredMetadata, FetchMetadata, Metadata};
use net_traits::CoreResourceMsg::Fetch as NetTraitsFetch;
use net_traits::request::{Request as NetTraitsRequest, ServiceWorkersMode};
use net_traits::request::RequestInit as NetTraitsRequestInit;
use network_listener::{NetworkListener, PreInvoke};
use servo_url::ServoUrl;
use std::mem;
use std::rc::Rc;
use std::sync::{Arc, Mutex};

struct FetchContext {
    fetch_promise: Option<TrustedPromise>,
    response_object: Trusted<Response>,
    body: Vec<u8>,
}

fn from_referrer_to_referrer_url(request: &NetTraitsRequest) -> Option<ServoUrl> {
    request.referrer.to_url().map(|url| url.clone())
}

fn request_init_from_request(request: NetTraitsRequest) -> NetTraitsRequestInit {
    NetTraitsRequestInit {
        method: request.method.clone(),
        url: request.url(),
        headers: request.headers.clone(),
        unsafe_request: request.unsafe_request,
        body: request.body.clone(),
        destination: request.destination,
        synchronous: request.synchronous,
        mode: request.mode.clone(),
        use_cors_preflight: request.use_cors_preflight,
        credentials_mode: request.credentials_mode,
        use_url_credentials: request.use_url_credentials,
        origin: GlobalScope::current().expect("No current global object").origin().immutable().clone(),
        referrer_url: from_referrer_to_referrer_url(&request),
        referrer_policy: request.referrer_policy,
        pipeline_id: request.pipeline_id,
        redirect_mode: request.redirect_mode,
        cache_mode: request.cache_mode,
        ..NetTraitsRequestInit::default()
    }
}

// https://fetch.spec.whatwg.org/#fetch-method
#[allow(unrooted_must_root)]
pub fn Fetch(global: &GlobalScope, input: RequestInfo, init: RootedTraceableBox<RequestInit>) -> Rc<Promise> {
    let core_resource_thread = global.core_resource_thread();

    // Step 1
    let promise = Promise::new(global);
    let response = Response::new(global);

    // Step 2
    let request = match Request::Constructor(global, input, init) {
        Err(e) => {
            promise.reject_error(e);
            return promise;
        },
        Ok(r) => r.get_request(),
    };
    let mut request_init = request_init_from_request(request);

    // Step 3
    if global.downcast::<ServiceWorkerGlobalScope>().is_some() {
        request_init.service_workers_mode = ServiceWorkersMode::Foreign;
    }

    // Step 4
    response.Headers().set_guard(Guard::Immutable);

    // Step 5
    let (action_sender, action_receiver) = ipc::channel().unwrap();
    let fetch_context = Arc::new(Mutex::new(FetchContext {
        fetch_promise: Some(TrustedPromise::new(promise.clone())),
        response_object: Trusted::new(&*response),
        body: vec![],
    }));
    let listener = NetworkListener {
        context: fetch_context,
        task_source: global.networking_task_source(),
        canceller: Some(global.task_canceller())
    };

    ROUTER.add_route(action_receiver.to_opaque(), Box::new(move |message| {
        listener.notify_fetch(message.to().unwrap());
    }));
    core_resource_thread.send(
        NetTraitsFetch(request_init, FetchChannels::ResponseMsg(action_sender))).unwrap();

    promise
}

impl PreInvoke for FetchContext {}

impl FetchResponseListener for FetchContext {
    fn process_request_body(&mut self) {
        // TODO
    }

    fn process_request_eof(&mut self) {
        // TODO
    }

    #[allow(unrooted_must_root)]
    fn process_response(&mut self, fetch_metadata: Result<FetchMetadata, NetworkError>) {
        let promise = self.fetch_promise.take().expect("fetch promise is missing").root();

        // JSAutoCompartment needs to be manually made.
        // Otherwise, Servo will crash.
        let promise_cx = promise.global().get_cx();
        let _ac = JSAutoCompartment::new(promise_cx, promise.reflector().get_jsobject().get());
        match fetch_metadata {
            // Step 4.1
            Err(_) => {
                promise.reject_error(Error::Type("Network error occurred".to_string()));
                self.fetch_promise = Some(TrustedPromise::new(promise));
                self.response_object.root().set_type(DOMResponseType::Error);
                return;
            },
            // Step 4.2
            Ok(metadata) => {
                match metadata {
                    FetchMetadata::Unfiltered(m) => {
                        fill_headers_with_metadata(self.response_object.root(), m);
                        self.response_object.root().set_type(DOMResponseType::Default);
                    },
                    FetchMetadata::Filtered { filtered, .. } => match filtered {
                        FilteredMetadata::Basic(m) => {
                            fill_headers_with_metadata(self.response_object.root(), m);
                            self.response_object.root().set_type(DOMResponseType::Basic);
                        },
                        FilteredMetadata::Cors(m) => {
                            fill_headers_with_metadata(self.response_object.root(), m);
                            self.response_object.root().set_type(DOMResponseType::Cors);
                        },
                        FilteredMetadata::Opaque =>
                            self.response_object.root().set_type(DOMResponseType::Opaque),
                        FilteredMetadata::OpaqueRedirect =>
                            self.response_object.root().set_type(DOMResponseType::Opaqueredirect)
                    }
                }
            }
        }
        // Step 4.3
        promise.resolve_native(&self.response_object.root());
        self.fetch_promise = Some(TrustedPromise::new(promise));
    }

    fn process_response_chunk(&mut self, mut chunk: Vec<u8>) {
        self.body.append(&mut chunk);
    }

    fn process_response_eof(&mut self, _response: Result<(), NetworkError>) {
        let response = self.response_object.root();
        let global = response.global();
        let cx = global.get_cx();
        let _ac = JSAutoCompartment::new(cx, global.reflector().get_jsobject().get());
        response.finish(mem::replace(&mut self.body, vec![]));
        // TODO
        // ... trailerObject is not supported in Servo yet.
    }
}

fn fill_headers_with_metadata(r: DomRoot<Response>, m: Metadata) {
    r.set_headers(m.headers);
    r.set_raw_status(m.status);
    r.set_final_url(m.final_url);
}
<|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/. */

//! The context within which CSS code is parsed.

use cssparser::{Parser, SourcePosition};
use error_reporting::ParseErrorReporter;
#[cfg(feature = "gecko")]
use gecko_bindings::sugar::refptr::{GeckoArcPrincipal, GeckoArcURI};
use servo_url::ServoUrl;
use stylesheets::Origin;

#[cfg(not(feature = "gecko"))]
pub struct ParserContextExtraData;

#[cfg(feature = "gecko")]
pub struct ParserContextExtraData {
    pub base: Option<GeckoArcURI>,
    pub referrer: Option<GeckoArcURI>,
    pub principal: Option<GeckoArcPrincipal>,
}

impl ParserContextExtraData {
    #[cfg(not(feature = "gecko"))]
    pub fn default() -> ParserContextExtraData {
        ParserContextExtraData
    }

    #[cfg(feature = "gecko")]
    pub fn default() -> ParserContextExtraData {
        ParserContextExtraData { base: None, referrer: None, principal: None }
    }
}

pub struct ParserContext<'a> {
    pub stylesheet_origin: Origin,
    pub base_url: &'a ServoUrl,
    pub error_reporter: Box<ParseErrorReporter + Send>,
    pub extra_data: ParserContextExtraData,
}

impl<'a> ParserContext<'a> {
    pub fn new_with_extra_data(stylesheet_origin: Origin, base_url: &'a ServoUrl,
                               error_reporter: Box<ParseErrorReporter + Send>,
                               extra_data: ParserContextExtraData)
                               -> ParserContext<'a> {
        ParserContext {
            stylesheet_origin: stylesheet_origin,
            base_url: base_url,
            error_reporter: error_reporter,
            extra_data: extra_data,
        }
    }

    pub fn new(stylesheet_origin: Origin, base_url: &'a ServoUrl, error_reporter: Box<ParseErrorReporter + Send>)
               -> ParserContext<'a> {
        let extra_data = ParserContextExtraData::default();
        ParserContext::new_with_extra_data(stylesheet_origin, base_url, error_reporter, extra_data)
    }
}

/// Defaults to a no-op.
/// Set a `RUST_LOG=style::errors` environment variable
/// to log CSS parse errors to stderr.
pub fn log_css_error(input: &mut Parser, position: SourcePosition, message: &str, parsercontext: &ParserContext) {
    parsercontext.error_reporter.report_error(input, position, message);
}

// XXXManishearth Replace all specified value parse impls with impls of this
// trait. This will make it easy to write more generic values in the future.
pub trait Parse {
    fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> where Self: Sized;
}
<commit_msg>style: Document and clean up the parser module.<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/. */

//! The context within which CSS code is parsed.

#![deny(missing_docs)]

use cssparser::{Parser, SourcePosition};
use error_reporting::ParseErrorReporter;
#[cfg(feature = "gecko")]
use gecko_bindings::sugar::refptr::{GeckoArcPrincipal, GeckoArcURI};
use servo_url::ServoUrl;
use stylesheets::Origin;

/// Extra data that the style backend may need to parse stylesheets.
#[cfg(not(feature = "gecko"))]
pub struct ParserContextExtraData;

/// Extra data that the style backend may need to parse stylesheets.
#[cfg(feature = "gecko")]
pub struct ParserContextExtraData {
    /// The base URI.
    pub base: Option<GeckoArcURI>,
    /// The referrer URI.
    pub referrer: Option<GeckoArcURI>,
    /// The principal that loaded this stylesheet.
    pub principal: Option<GeckoArcPrincipal>,
}

#[cfg(not(feature = "gecko"))]
impl Default for ParserContextExtraData {
    fn default() -> Self {
        ParserContextExtraData
    }
}

#[cfg(feature = "gecko")]
impl Default for ParserContextExtraData {
    fn default() -> Self {
        ParserContextExtraData { base: None, referrer: None, principal: None }
    }
}

/// The data that the parser needs from outside in order to parse a stylesheet.
pub struct ParserContext<'a> {
    /// The `Origin` of the stylesheet, whether it's a user, author or
    /// user-agent stylesheet.
    pub stylesheet_origin: Origin,
    /// The base url we're parsing this stylesheet as.
    pub base_url: &'a ServoUrl,
    /// An error reporter to report syntax errors.
    pub error_reporter: Box<ParseErrorReporter + Send>,
    /// Implementation-dependent extra data.
    pub extra_data: ParserContextExtraData,
}

impl<'a> ParserContext<'a> {
    /// Create a `ParserContext` with extra data.
    pub fn new_with_extra_data(stylesheet_origin: Origin,
                               base_url: &'a ServoUrl,
                               error_reporter: Box<ParseErrorReporter + Send>,
                               extra_data: ParserContextExtraData)
                               -> ParserContext<'a> {
        ParserContext {
            stylesheet_origin: stylesheet_origin,
            base_url: base_url,
            error_reporter: error_reporter,
            extra_data: extra_data,
        }
    }

    /// Create a parser context with the default extra data.
    pub fn new(stylesheet_origin: Origin,
               base_url: &'a ServoUrl,
               error_reporter: Box<ParseErrorReporter + Send>)
               -> ParserContext<'a> {
        let extra_data = ParserContextExtraData::default();
        Self::new_with_extra_data(stylesheet_origin, base_url, error_reporter, extra_data)
    }
}

/// Defaults to a no-op.
/// Set a `RUST_LOG=style::errors` environment variable
/// to log CSS parse errors to stderr.
pub fn log_css_error(input: &mut Parser, position: SourcePosition, message: &str, parsercontext: &ParserContext) {
    parsercontext.error_reporter.report_error(input, position, message);
}

// XXXManishearth Replace all specified value parse impls with impls of this
// trait. This will make it easy to write more generic values in the future.
/// A trait to abstract parsing of a specified value given a `ParserContext` and
/// CSS input.
pub trait Parse : Sized {
    /// Parse a value of this type.
    ///
    /// Returns an error on failure.
    fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()>;
}
<|endoftext|>


<commit_before>use crate::sys::config;
use crate::sys::taskserver::Control;
use super::SystemModule;
use anyhow::{Result, anyhow, ensure};
use chrono::NaiveTime;
use log::info;
use serde::{Serialize, Deserialize};
use tokio::process::Command;

#[derive(Clone, Serialize, Deserialize)]
struct HealthConfig {
    enabled: bool,
    debug_exec_once: bool,
}

pub struct Health {
    config: HealthConfig,
    wakeup_list: Vec<NaiveTime>,
}

impl Health {
    pub fn new(wakeup_list: Vec<NaiveTime>) -> Result<Self> {
        info!("[health] initialize");

        let jsobj = config::get_object(&["health"])
            .map_or(Err(anyhow!("Config not found: health")), Ok)?;
        let config: HealthConfig = serde_json::from_value(jsobj)?;

        Ok(Health {
            config,
            wakeup_list,
        })
    }

    async fn health_task(&mut self, ctrl: &Control) -> Result<()> {
        let cpu_info = get_cpu_info().await;
        info!("{:?}", cpu_info);
        let mem_info = get_mem_info().await;
        info!("{:?}", mem_info?);
        let disk_info = get_disk_info().await;
        info!("{:?}", disk_info?);
        let cpu_temp = get_cpu_temp().await;
        info!("{:?}", cpu_temp?);

        Ok(())
    }

    async fn health_task_entry(ctrl: Control) -> Result<()> {
        let mut health = ctrl.sysmods().health.write().await;
        health.health_task(&ctrl).await
    }
}

impl SystemModule for Health {
    fn on_start(&self, ctrl: &Control) {
        info!("[health] on_start");
        if self.config.enabled {
            if self.config.debug_exec_once {
                ctrl.spawn_oneshot_task(
                    "health_check",
                    Health::health_task_entry);
            }
            else {
                ctrl.spawn_periodic_task(
                    "health_check",
                    &self.wakeup_list,
                    Health::health_task_entry);
            }
        }
    }
}

#[derive(Debug, Clone)]
struct CpuInfo {
    usage_percent_total: f64,
    usage_percent_list: Vec<f64>,
}

async fn get_cpu_info() -> Result<CpuInfo> {
    let buf = tokio::fs::read("/proc/stat").await?;
    let text = String::from_utf8_lossy(&buf);

    // See `man proc`
    // user   (1) Time spent in user mode.
    // nice   (2) Time spent in user mode with low priority (nice).
    // system (3) Time spent in system mode.
    // idle   (4) Time spent in the idle task.  This value should be USER_HZ times the second entry in the /proc/uptime pseudo-file.
    // iowait (since Linux 2.5.41)
    //        (5) Time waiting for I/O to complete.  This value is not reliable, for the following reasons:
    // irq (since Linux 2.6.0-test4)
    //        (6) Time servicing interrupts.
    // softirq (since Linux 2.6.0-test4)
    //        (7) Time servicing softirqs.
    // steal (since Linux 2.6.11)
    //        (8)  Stolen  time,  which  is the time spent in other operating systems when running in a virtualized environment
    // guest (since Linux 2.6.24)
    //        (9) Time spent running a virtual CPU for guest operating systems under the control of the Linux kernel.
    // guest_nice (since Linux 2.6.33)
    //        (10)  Time spent running a niced guest (virtual CPU for guest operating systems under the
    //        control of the Linux kernel).
    let mut usage_percent_total = None;
    let mut usage_percent_list = vec![];
    for line in text.lines() {
        let mut name = None;
        let mut user = None;
        let mut nice = None;
        let mut system = None;
        let mut idle = None;
        for (col_no, elem) in line.split_ascii_whitespace().enumerate() {
            match col_no {
                0 => name = Some(elem),
                1 => user = Some(elem),
                2 => nice = Some(elem),
                3 => system = Some(elem),
                4 => idle = Some(elem),
                _ => (),
            }
        }
        // cpu or cpu%d の行を取り出す
        if name.is_none() || !name.unwrap().starts_with("cpu") {
            continue;
        }

        let user: u64 = user.ok_or(anyhow!("parse error"))?.parse()?;
        let nice: u64 = nice.ok_or(anyhow!("parse error"))?.parse()?;
        let system: u64 = system.ok_or(anyhow!("parse error"))?.parse()?;
        let idle: u64 = idle.ok_or(anyhow!("parse error"))?.parse()?;
        let total = user + nice + system + idle;
        let value = (total - idle) as f64 / total as f64;
        if name == Some("cpu") {
            usage_percent_total = Some(value);
        }
        else {
            usage_percent_list.push(value);
        }
    }

    ensure!(usage_percent_total.is_some());
    ensure!(!usage_percent_list.is_empty());
    Ok(CpuInfo {
        usage_percent_total: usage_percent_total.unwrap(),
        usage_percent_list,
    })
}

#[derive(Debug, Clone, Copy)]
struct MemInfo {
    total_mib: f64,
    avail_mib: f64,
    percent: f64,
}

async fn get_mem_info() -> Result<MemInfo> {
    let mut cmd = Command::new("free");
	let output = cmd.output().await?;
    ensure!(output.status.success(), "free command failed");

    // sample
    //                total        used        free      shared  buff/cache   available
    // Mem:        13034888     4119272     5561960          68     3353656     8609008
    // Swap:        4194304           0     4194304
    let stdout = String::from_utf8_lossy(&output.stdout);
    let mut total = None;
    let mut avail = None;
    for (line_no, line) in stdout.lines().enumerate() {
        if line_no != 1 {
            continue;
        }
        for (col_no, elem) in line.split_ascii_whitespace().enumerate() {
            match col_no {
                1 => total = Some(elem),
                6 => avail = Some(elem),
                _ => (),
            }
        }
        break;
    }
    let total = total.ok_or(anyhow!("parse error"))?;
    let avail = avail.ok_or(anyhow!("parse error"))?;
    let total_mib = total.parse::<u64>()? as f64 / 1024.0;
    let avail_mib = avail.parse::<u64>()? as f64 / 1024.0;
    let percent = 100.0 * avail_mib / total_mib;

    Ok(MemInfo { total_mib, avail_mib, percent })
}

#[derive(Debug, Clone, Copy)]
struct DiskInfo {
    total_gib: f64,
    avail_gib: f64,
    percent: f64,
}

async fn get_disk_info() -> Result<DiskInfo> {
    let mut cmd = Command::new("df");
	let output = cmd.output().await?;
    ensure!(output.status.success(), "df command failed");

    // sample
    // ファイルシス   1K-ブロック     使用    使用可 使用% マウント位置
    // /dev/root        122621412 12964620 104641120   12% /
    // devtmpfs           1800568        0   1800568    0% /dev
    // tmpfs              1965432        0   1965432    0% /dev/shm
    // tmpfs              1965432    17116   1948316    1% /run
    // tmpfs                 5120        4      5116    1% /run/lock
    // tmpfs              1965432        0   1965432    0% /sys/fs/cgroup
    // /dev/mmcblk0p1      258095    49324    208772   20% /boot
    // /dev/sda1         59280316 57109344         0  100% /media/usbbkup
    let stdout = String::from_utf8_lossy(&output.stdout);
    let mut total = None;
    let mut avail = None;
    for line in stdout.lines().skip(1) {
        let mut total_tmp = None;
        let mut avail_tmp = None;
        let mut mp_tmp = None;
        for (col_no, elem) in line.split_ascii_whitespace().enumerate() {
            match col_no {
                1 => total_tmp = Some(elem),
                3 => avail_tmp = Some(elem),
                5 => mp_tmp = Some(elem),
                _ => (),
            }
        }
        if let Some(mp) = mp_tmp {
            if mp == "/" {
                total = total_tmp;
                avail = avail_tmp;
            }
        }
    }
    let total = total.ok_or(anyhow!("parse error"))?;
    let avail = avail.ok_or(anyhow!("parse error"))?;
    let total_gib = total.parse::<u64>()? as f64 / 1024.0 / 1024.0;
    let avail_gib = avail.parse::<u64>()? as f64 / 1024.0 / 1024.0;
    let percent = 100.0 * avail_gib / total_gib;

    Ok(DiskInfo { total_gib, avail_gib, percent })
}

#[derive(Debug, Clone, Copy)]
struct CpuTemp {
    temp: f64,
}

/// CPU 温度 (正確には違うかもしれない。ボード上の何らかの温度センサの値。) を取得する。
///
/// "/sys/class/thermal/thermal_zone0/temp" による。
/// デバイスファイルが存在しないと [std::io::Error] (NotFound) になる。
/// Linux 汎用のようだが少なくとも WSL2 では存在しない。
/// RasPi only で `vcgencmd measure_temp` という手もあるが、
/// 人が読みやすい代わりにパースが難しくなるのでデバイスファイルの方を使う。
async fn get_cpu_temp() -> Result<CpuTemp> {
    let buf = tokio::fs::read("/sys/class/thermal/thermal_zone0/temp").await?;
    let text = String::from_utf8_lossy(&buf);

    // 'C を 1000 倍した整数が得られるので変換する
    let temp: u64 = text.trim().parse()?;
    let temp = temp as f64 / 1000.0;

    Ok(CpuTemp { temp })
}
<commit_msg>Health データ取得全体の整理<commit_after>use crate::sys::config;
use crate::sys::taskserver::Control;
use super::SystemModule;
use anyhow::{Result, anyhow, ensure};
use chrono::NaiveTime;
use log::info;
use serde::{Serialize, Deserialize};
use tokio::process::Command;

#[derive(Clone, Serialize, Deserialize)]
struct HealthConfig {
    enabled: bool,
    debug_exec_once: bool,
}

pub struct Health {
    config: HealthConfig,
    wakeup_list: Vec<NaiveTime>,
}

impl Health {
    pub fn new(wakeup_list: Vec<NaiveTime>) -> Result<Self> {
        info!("[health] initialize");

        let jsobj = config::get_object(&["health"])
            .map_or(Err(anyhow!("Config not found: health")), Ok)?;
        let config: HealthConfig = serde_json::from_value(jsobj)?;

        Ok(Health {
            config,
            wakeup_list,
        })
    }

    async fn health_task(&mut self, ctrl: &Control) -> Result<()> {
        let cpu_info = get_cpu_info().await;
        info!("{:?}", cpu_info);
        let mem_info = get_mem_info().await;
        info!("{:?}", mem_info?);
        let disk_info = get_disk_info().await;
        info!("{:?}", disk_info?);
        let cpu_temp = get_cpu_temp().await;
        info!("{:?}", cpu_temp?);

        Ok(())
    }

    async fn health_task_entry(ctrl: Control) -> Result<()> {
        let mut health = ctrl.sysmods().health.write().await;
        health.health_task(&ctrl).await
    }
}

impl SystemModule for Health {
    fn on_start(&self, ctrl: &Control) {
        info!("[health] on_start");
        if self.config.enabled {
            if self.config.debug_exec_once {
                ctrl.spawn_oneshot_task(
                    "health_check",
                    Health::health_task_entry);
            }
            else {
                ctrl.spawn_periodic_task(
                    "health_check",
                    &self.wakeup_list,
                    Health::health_task_entry);
            }
        }
    }
}

#[derive(Debug, Clone)]
struct CpuInfo {
    cpu_percent_total: f64,
    cpu_percent_list: Vec<f64>,
}

async fn get_cpu_info() -> Result<CpuInfo> {
    let buf = tokio::fs::read("/proc/stat").await?;
    let text = String::from_utf8_lossy(&buf);

    // See `man proc`
    // user   (1) Time spent in user mode.
    // nice   (2) Time spent in user mode with low priority (nice).
    // system (3) Time spent in system mode.
    // idle   (4) Time spent in the idle task.  This value should be USER_HZ times the second entry in the /proc/uptime pseudo-file.
    // iowait (since Linux 2.5.41)
    //        (5) Time waiting for I/O to complete.  This value is not reliable, for the following reasons:
    // irq (since Linux 2.6.0-test4)
    //        (6) Time servicing interrupts.
    // softirq (since Linux 2.6.0-test4)
    //        (7) Time servicing softirqs.
    // steal (since Linux 2.6.11)
    //        (8)  Stolen  time,  which  is the time spent in other operating systems when running in a virtualized environment
    // guest (since Linux 2.6.24)
    //        (9) Time spent running a virtual CPU for guest operating systems under the control of the Linux kernel.
    // guest_nice (since Linux 2.6.33)
    //        (10)  Time spent running a niced guest (virtual CPU for guest operating systems under the
    //        control of the Linux kernel).
    let mut cpu_percent_total = None;
    let mut cpu_percent_list = vec![];
    for line in text.lines() {
        let mut name = None;
        let mut user = None;
        let mut nice = None;
        let mut system = None;
        let mut idle = None;
        for (col_no, elem) in line.split_ascii_whitespace().enumerate() {
            match col_no {
                0 => name = Some(elem),
                1 => user = Some(elem),
                2 => nice = Some(elem),
                3 => system = Some(elem),
                4 => idle = Some(elem),
                _ => (),
            }
        }
        // cpu or cpu%d の行を取り出す
        if name.is_none() || !name.unwrap().starts_with("cpu") {
            continue;
        }

        let user: u64 = user.ok_or(anyhow!("parse error"))?.parse()?;
        let nice: u64 = nice.ok_or(anyhow!("parse error"))?.parse()?;
        let system: u64 = system.ok_or(anyhow!("parse error"))?.parse()?;
        let idle: u64 = idle.ok_or(anyhow!("parse error"))?.parse()?;
        let total = user + nice + system + idle;
        let value = (total - idle) as f64 / total as f64;
        if name == Some("cpu") {
            cpu_percent_total = Some(value);
        }
        else {
            cpu_percent_list.push(value);
        }
    }

    ensure!(cpu_percent_total.is_some());
    ensure!(!cpu_percent_list.is_empty());
    let cpu_percent_total = cpu_percent_total.unwrap();
    Ok(CpuInfo {
        cpu_percent_total,
        cpu_percent_list,
    })
}

#[derive(Debug, Clone, Copy)]
struct MemInfo {
    total_mib: f64,
    avail_mib: f64,
}

async fn get_mem_info() -> Result<MemInfo> {
    let mut cmd = Command::new("free");
	let output = cmd.output().await?;
    ensure!(output.status.success(), "free command failed");

    // sample
    //                total        used        free      shared  buff/cache   available
    // Mem:        13034888     4119272     5561960          68     3353656     8609008
    // Swap:        4194304           0     4194304
    let stdout = String::from_utf8_lossy(&output.stdout);
    let mut total = None;
    let mut avail = None;
    for (line_no, line) in stdout.lines().enumerate() {
        if line_no != 1 {
            continue;
        }
        for (col_no, elem) in line.split_ascii_whitespace().enumerate() {
            match col_no {
                1 => total = Some(elem),
                6 => avail = Some(elem),
                _ => (),
            }
        }
        break;
    }
    let total = total.ok_or(anyhow!("parse error"))?;
    let avail = avail.ok_or(anyhow!("parse error"))?;
    let total_mib = total.parse::<u64>()? as f64 / 1024.0;
    let avail_mib = avail.parse::<u64>()? as f64 / 1024.0;

    Ok(MemInfo { total_mib, avail_mib })
}

#[derive(Debug, Clone, Copy)]
struct DiskInfo {
    total_gib: f64,
    avail_gib: f64,
}

async fn get_disk_info() -> Result<DiskInfo> {
    let mut cmd = Command::new("df");
	let output = cmd.output().await?;
    ensure!(output.status.success(), "df command failed");

    // sample
    // ファイルシス   1K-ブロック     使用    使用可 使用% マウント位置
    // /dev/root        122621412 12964620 104641120   12% /
    // devtmpfs           1800568        0   1800568    0% /dev
    // tmpfs              1965432        0   1965432    0% /dev/shm
    // tmpfs              1965432    17116   1948316    1% /run
    // tmpfs                 5120        4      5116    1% /run/lock
    // tmpfs              1965432        0   1965432    0% /sys/fs/cgroup
    // /dev/mmcblk0p1      258095    49324    208772   20% /boot
    // /dev/sda1         59280316 57109344         0  100% /media/usbbkup
    let stdout = String::from_utf8_lossy(&output.stdout);
    let mut total = None;
    let mut avail = None;
    for line in stdout.lines().skip(1) {
        let mut total_tmp = None;
        let mut avail_tmp = None;
        let mut mp_tmp = None;
        for (col_no, elem) in line.split_ascii_whitespace().enumerate() {
            match col_no {
                1 => total_tmp = Some(elem),
                3 => avail_tmp = Some(elem),
                5 => mp_tmp = Some(elem),
                _ => (),
            }
        }
        if let Some(mp) = mp_tmp {
            if mp == "/" {
                total = total_tmp;
                avail = avail_tmp;
            }
        }
    }
    let total = total.ok_or(anyhow!("parse error"))?;
    let avail = avail.ok_or(anyhow!("parse error"))?;
    let total_gib = total.parse::<u64>()? as f64 / 1024.0 / 1024.0;
    let avail_gib = avail.parse::<u64>()? as f64 / 1024.0 / 1024.0;

    Ok(DiskInfo { total_gib, avail_gib })
}

#[derive(Debug, Clone, Copy)]
struct CpuTemp {
    temp: f64,
}

/// CPU 温度 (正確には違うかもしれない。ボード上の何らかの温度センサの値。) を取得する。
///
/// "/sys/class/thermal/thermal_zone0/temp" による。
/// デバイスファイルが存在しないと [std::io::Error] (NotFound) になる。
/// Linux 汎用のようだが少なくとも WSL2 では存在しない。
/// RasPi only で `vcgencmd measure_temp` という手もあるが、
/// 人が読みやすい代わりにパースが難しくなるのでデバイスファイルの方を使う。
async fn get_cpu_temp() -> Result<CpuTemp> {
    let buf = tokio::fs::read("/sys/class/thermal/thermal_zone0/temp").await?;
    let text = String::from_utf8_lossy(&buf);

    // 'C を 1000 倍した整数が得られるので変換する
    let temp: u64 = text.trim().parse()?;
    let temp = temp as f64 / 1000.0;

    Ok(CpuTemp { temp })
}
<|endoftext|>