<commit_before>use syntax::codemap::Span;
use syntax::ptr::P;
use syntax::tokenstream::TokenTree;

use syntax::ast::Expr;
use syntax::ext::base::{ExtCtxt, MacResult, MacEager};
use syntax::parse::parser::Parser;
use syntax::parse::token::Token;

pub fn expand<'cx>(cx: &'cx mut ExtCtxt, _: Span, tts: &[TokenTree]) -> Box<MacResult + 'cx> {
    let mut parser = cx.new_parser_from_tts(tts);
    let expr = parse_json(cx, &mut parser);
    if &parser.token != &Token::Eof {
        cx.span_fatal(parser.span, "expected end of `json!` macro invocation");
    }
    MacEager::expr(expr)
}

#[cfg(feature="with-rustc-serialize")]
fn parse_json(cx: &ExtCtxt, parser: &mut Parser) -> P<Expr> {
    use syntax::ext::build::AstBuilder;
    use syntax::parse::token::DelimToken;

    macro_rules! comma_sep {
        () =>  {
            ::syntax::parse::common::SeqSep {
                sep: Some(Token::Comma),
                trailing_sep_allowed: true // we could be JSON pedants...
            }
        }
    }

    let orig_span = parser.span;

    match &parser.token {
        &Token::OpenDelim(DelimToken::Bracket) => {
            let _ = parser.bump();
            let r_bracket = Token::CloseDelim(DelimToken::Bracket);
            let exprs = parser.parse_seq_to_end(&r_bracket, comma_sep!(), |p| {
                Ok(parse_json(cx, p))
            }).ok().unwrap();
            let exprs = cx.expr_vec(orig_span, exprs);
            quote_expr!(cx, {
                use ::std::boxed::Box;
                let xs: Box<[_]> = Box::new($exprs);
                ::rustc_serialize::json::Json::Array(xs.into_vec())
            })
        },
        &Token::OpenDelim(DelimToken::Brace) => {
            let _ = parser.bump();
            let r_brace = Token::CloseDelim(DelimToken::Brace);
            let kvs = parser.parse_seq_to_end(&r_brace, comma_sep!(), |p| {
                let (istr, _) = p.parse_str().ok().unwrap();
                let s = &*istr;
                let _ = p.expect(&Token::Colon);
                let key = quote_expr!(cx, {
                    use ::std::borrow::ToOwned;
                    $s.to_owned()
                });
                Ok((key, parse_json(cx, p)))
            }).ok().unwrap();
            let mut insertions = vec![];
            // Can't use `quote_stmt!()` and interpolate a vector of
            // statements, seemingly.  Should consider filing a bug
            // upstream.
            for &(ref key, ref value) in kvs.iter() {
                insertions.push(quote_expr!(cx, {
                    _ob.insert($key, $value);
                }));
            }
            let expr = quote_expr!(cx, {
                let mut _ob = ::std::collections::BTreeMap::new();
                $insertions;
                ::rustc_serialize::json::Json::Object(_ob)
            });
            expr
        },
        &Token::OpenDelim(DelimToken::Paren) => {
            let expr = parser.parse_expr().unwrap();
            quote_expr!(cx, {{
                use ::rustc_serialize::json::ToJson;
                ($expr).to_json()
            }})
        },
        &Token::Ident(id) if id.name.as_str() == "null" => {
            let _ = parser.bump();
            quote_expr!(cx, { ::rustc_serialize::json::Json::Null })
        },
        _ => { // TODO: investigate can_begin_expr (maybe eliminate need for parens)?
            let expr = parser.parse_pat_literal_maybe_minus().ok().unwrap();
            quote_expr!(cx, {{
                use ::rustc_serialize::json::ToJson;
                ($expr).to_json()
            }})
        }
    }
}

#[cfg(feature="with-serde")]
fn parse_json(cx: &ExtCtxt, parser: &mut Parser) -> P<Expr> {
    use syntax::ext::build::AstBuilder;
    use syntax::parse::token::DelimToken;

    macro_rules! comma_sep {
        () =>  {
            ::syntax::parse::common::SeqSep {
                sep: Some(Token::Comma),
                trailing_sep_allowed: true // we could be JSON pedants...
            }
        }
    }

    let orig_span = parser.span;

    match &parser.token {
        &Token::OpenDelim(DelimToken::Bracket) => {
            let _ = parser.bump();
            let r_bracket = Token::CloseDelim(DelimToken::Bracket);
            let exprs = parser.parse_seq_to_end(&r_bracket,
                                                comma_sep!(),
                                                |p| Ok(parse_json(cx, p)))
                .ok()
                .unwrap();
            let exprs = cx.expr_vec(orig_span, exprs);
            quote_expr!(cx, {
                use ::std::boxed::Box;
                let xs: Box<[_]> = Box::new($exprs);
                serde_json::Value::Array(xs.into_vec())
            })
        }
        &Token::OpenDelim(DelimToken::Brace) => {
            let _ = parser.bump();
            let r_brace = Token::CloseDelim(DelimToken::Brace);
            let kvs = parser.parse_seq_to_end(&r_brace, comma_sep!(), |p| {
                let (istr, _) = p.parse_str().ok().unwrap();
                let s = &*istr;
                let _ = p.expect(&Token::Colon);
                let key = quote_expr!(cx, {
                    use ::std::borrow::ToOwned;
                    $s.to_owned()
                });
                Ok((key, parse_json(cx, p)))
            })
                .ok()
                .unwrap();
            let mut insertions = vec![];
            // Can't use `quote_stmt!()` and interpolate a vector of
            // statements, seemingly.  Should consider filing a bug
            // upstream.
            for &(ref key, ref value) in kvs.iter() {
                insertions.push(quote_expr!(cx, {
                    _ob.insert($key, $value);
                }));
            }
            let expr = quote_expr!(cx, {
                let mut _ob = ::std::collections::BTreeMap::new();
                $insertions;
                ::serde_json::Value::Object(_ob)
            });
            expr
        }
        &Token::OpenDelim(DelimToken::Paren) => {
            let expr = parser.parse_expr().unwrap();
            quote_expr!(cx, {{
                ::serde_json::to_value(&$expr)
            }})
        }
        &Token::Ident(id) if id.name.as_str() == "null" => {
            let _ = parser.bump();
            quote_expr!(cx, {
                ::serde_json::Value::Null
            })
        }
        _ => {
            // TODO: investigate can_begin_expr (maybe eliminate need for parens)?
            let expr = parser.parse_pat_literal_maybe_minus().ok().unwrap();
            quote_expr!(cx, {{
                ::serde_json::to_value(&$expr)
            }})
        }
    }
}
<commit_msg>Rustup to rustc 1.16.0-nightly (4ecc85beb 2016-12-28)<commit_after>use syntax::codemap::Span;
use syntax::ptr::P;
use syntax::tokenstream::TokenTree;

use syntax::ast::Expr;
use syntax::ext::base::{ExtCtxt, MacResult, MacEager};
use syntax::parse::parser::Parser;
use syntax::parse::token::Token;

pub fn expand<'cx>(cx: &'cx mut ExtCtxt, _: Span, tts: &[TokenTree]) -> Box<MacResult + 'cx> {
    let mut parser = cx.new_parser_from_tts(tts);
    let expr = parse_json(cx, &mut parser);
    if &parser.token != &Token::Eof {
        cx.span_fatal(parser.span, "expected end of `json!` macro invocation");
    }
    MacEager::expr(expr)
}

#[cfg(feature="with-rustc-serialize")]
fn parse_json(cx: &ExtCtxt, parser: &mut Parser) -> P<Expr> {
    use syntax::ext::build::AstBuilder;
    use syntax::parse::token::DelimToken;

    macro_rules! comma_sep {
        () =>  {
            ::syntax::parse::common::SeqSep {
                sep: Some(Token::Comma),
                trailing_sep_allowed: true // we could be JSON pedants...
            }
        }
    }

    let orig_span = parser.span;

    match &parser.token {
        &Token::OpenDelim(DelimToken::Bracket) => {
            let _ = parser.bump();
            let r_bracket = Token::CloseDelim(DelimToken::Bracket);
            let exprs = parser.parse_seq_to_end(&r_bracket, comma_sep!(), |p| {
                Ok(parse_json(cx, p))
            }).ok().unwrap();
            let exprs = cx.expr_vec(orig_span, exprs);
            quote_expr!(cx, {
                use ::std::boxed::Box;
                let xs: Box<[_]> = Box::new($exprs);
                ::rustc_serialize::json::Json::Array(xs.into_vec())
            })
        },
        &Token::OpenDelim(DelimToken::Brace) => {
            let _ = parser.bump();
            let r_brace = Token::CloseDelim(DelimToken::Brace);
            let kvs = parser.parse_seq_to_end(&r_brace, comma_sep!(), |p| {
                let (istr, _) = p.parse_str().ok().unwrap();
                let s = &*istr.as_str();
                let _ = p.expect(&Token::Colon);
                let key = quote_expr!(cx, {
                    use ::std::borrow::ToOwned;
                    $s.to_owned()
                });
                Ok((key, parse_json(cx, p)))
            }).ok().unwrap();
            let mut insertions = vec![];
            // Can't use `quote_stmt!()` and interpolate a vector of
            // statements, seemingly.  Should consider filing a bug
            // upstream.
            for &(ref key, ref value) in kvs.iter() {
                insertions.push(quote_expr!(cx, {
                    _ob.insert($key, $value);
                }));
            }
            let expr = quote_expr!(cx, {
                let mut _ob = ::std::collections::BTreeMap::new();
                $insertions;
                ::rustc_serialize::json::Json::Object(_ob)
            });
            expr
        },
        &Token::OpenDelim(DelimToken::Paren) => {
            let expr = parser.parse_expr().unwrap();
            quote_expr!(cx, {{
                use ::rustc_serialize::json::ToJson;
                ($expr).to_json()
            }})
        },
        &Token::Ident(id) if id.name == "null" => {
            let _ = parser.bump();
            quote_expr!(cx, { ::rustc_serialize::json::Json::Null })
        },
        _ => { // TODO: investigate can_begin_expr (maybe eliminate need for parens)?
            let expr = parser.parse_pat_literal_maybe_minus().ok().unwrap();
            quote_expr!(cx, {{
                use ::rustc_serialize::json::ToJson;
                ($expr).to_json()
            }})
        }
    }
}

#[cfg(feature="with-serde")]
fn parse_json(cx: &ExtCtxt, parser: &mut Parser) -> P<Expr> {
    use syntax::ext::build::AstBuilder;
    use syntax::parse::token::DelimToken;

    macro_rules! comma_sep {
        () =>  {
            ::syntax::parse::common::SeqSep {
                sep: Some(Token::Comma),
                trailing_sep_allowed: true // we could be JSON pedants...
            }
        }
    }

    let orig_span = parser.span;

    match &parser.token {
        &Token::OpenDelim(DelimToken::Bracket) => {
            let _ = parser.bump();
            let r_bracket = Token::CloseDelim(DelimToken::Bracket);
            let exprs = parser.parse_seq_to_end(&r_bracket,
                                                comma_sep!(),
                                                |p| Ok(parse_json(cx, p)))
                .ok()
                .unwrap();
            let exprs = cx.expr_vec(orig_span, exprs);
            quote_expr!(cx, {
                use ::std::boxed::Box;
                let xs: Box<[_]> = Box::new($exprs);
                serde_json::Value::Array(xs.into_vec())
            })
        }
        &Token::OpenDelim(DelimToken::Brace) => {
            let _ = parser.bump();
            let r_brace = Token::CloseDelim(DelimToken::Brace);
            let kvs = parser.parse_seq_to_end(&r_brace, comma_sep!(), |p| {
                let (istr, _) = p.parse_str().ok().unwrap();
                let s = &*istr.as_str();
                let _ = p.expect(&Token::Colon);
                let key = quote_expr!(cx, {
                    use ::std::borrow::ToOwned;
                    $s.to_owned()
                });
                Ok((key, parse_json(cx, p)))
            })
                .ok()
                .unwrap();
            let mut insertions = vec![];
            // Can't use `quote_stmt!()` and interpolate a vector of
            // statements, seemingly.  Should consider filing a bug
            // upstream.
            for &(ref key, ref value) in kvs.iter() {
                insertions.push(quote_expr!(cx, {
                    _ob.insert($key, $value);
                }));
            }
            let expr = quote_expr!(cx, {
                let mut _ob = ::std::collections::BTreeMap::new();
                $insertions;
                ::serde_json::Value::Object(_ob)
            });
            expr
        }
        &Token::OpenDelim(DelimToken::Paren) => {
            let expr = parser.parse_expr().unwrap();
            quote_expr!(cx, {{
                ::serde_json::to_value(&$expr)
            }})
        }
        &Token::Ident(id) if id.name == "null" => {
            let _ = parser.bump();
            quote_expr!(cx, {
                ::serde_json::Value::Null
            })
        }
        _ => {
            // TODO: investigate can_begin_expr (maybe eliminate need for parens)?
            let expr = parser.parse_pat_literal_maybe_minus().ok().unwrap();
            quote_expr!(cx, {{
                ::serde_json::to_value(&$expr)
            }})
        }
    }
}
<|endoftext|>


<commit_before>//! This examples shows the basics of how ggez's file handling
//! works.
//!
//! It doesn't use an event loop, it just runs once and exits,
//! printing a bunch of stuff to the console.

use ggez::{conf, filesystem, ContextBuilder, GameResult};
use std::env;
use std::io::{Read, Write};
use std::path;
use std::str;

pub fn main() -> GameResult {
    let mut cb = ContextBuilder::new("ggez_files_example", "ggez");

    // We add the CARGO_MANIFEST_DIR/resources to the filesystems paths so
    // we we look in the cargo project for files.
    // Using a ContextBuilder is nice for this because it means that
    // it will look for a conf.toml or icon file or such in
    // this directory when the Context is created.
    if let Ok(manifest_dir) = env::var("CARGO_MANIFEST_DIR") {
        let mut path = path::PathBuf::from(manifest_dir);
        path.push("resources");
        println!("Adding path {:?}", path);
        cb = cb.add_resource_path(path);
    }

    let (ctx, _) = &mut cb.build()?;

    println!("Full filesystem info: {:#?}", ctx.filesystem);

    println!("Resource stats:");
    filesystem::print_all(ctx);

    let dir_contents: Vec<_> = filesystem::read_dir(ctx, "/")?.collect();
    println!("Directory has {} things in it:", dir_contents.len());
    for itm in dir_contents {
        println!("   {:?}", itm);
    }

    println!();
    println!("Let's write to a file, it should end up in the user config dir");

    let test_file = path::Path::new("/testfile.txt");
    let bytes = b"test";
    {
        let mut file = filesystem::create(ctx, test_file)?;
        file.write_all(bytes)?;
    }
    println!("Wrote to test file");
    {
        let options = filesystem::OpenOptions::new().append(true);
        let mut file = filesystem::open_options(ctx, test_file, options)?;
        file.write_all(bytes)?;
    }
    println!("Appended to test file");
    {
        let mut buffer = Vec::new();
        let mut file = filesystem::open(ctx, test_file)?;
        file.read_to_end(&mut buffer)?;
        println!(
            "Read from test file: {:?}",
            str::from_utf8(&buffer).unwrap()
        );
    }

    println!();
    println!("Let's read the default conf file");
    if let Ok(_conf) = filesystem::read_config(ctx) {
        println!("Found existing conf file, its contents are:");
        let mut file = filesystem::open(ctx, "/conf.toml")?;
        let mut buffer = Vec::new();
        file.read_to_end(&mut buffer)?;
        println!("{}", str::from_utf8(&buffer).unwrap());

        println!("Now deleting it, re-run the example to recreate it.");
        filesystem::delete(ctx, "/conf.toml")?;
    } else {
        println!("No existing conf file found, saving one out");
        let c = conf::Conf::new();
        filesystem::write_config(ctx, &c)?;
        println!("Should now be a 'conf.toml' file under user config dir");
    }

    println!();
    println!("Now let's try to read a file that does not exist");
    {
        if let Err(e) = filesystem::open(ctx, "/jfkdlasfjdsa") {
            // The error message contains a big hairy list of each
            // directory tried and what error it got from it.
            println!("Got the error: {:#?}", e);
        } else {
            println!("Wait, it does exist?  Weird.")
        }
    }
    Ok(())
}
<commit_msg>port files example<commit_after>//! This examples shows the basics of how ggez's file handling
//! works.
//!
//! It doesn't use an event loop, it just runs once and exits,
//! printing a bunch of stuff to the console.

use ggez::{conf, filesystem, ContextBuilder, GameResult};
use std::env;
use std::io::{Read, Write};
use std::path;
use std::str;

pub fn main() -> GameResult {
    let mut cb = ContextBuilder::new("ggez_files_example", "ggez");

    // We add the CARGO_MANIFEST_DIR/resources to the filesystems paths so
    // we we look in the cargo project for files.
    // Using a ContextBuilder is nice for this because it means that
    // it will look for a conf.toml or icon file or such in
    // this directory when the Context is created.
    if let Ok(manifest_dir) = env::var("CARGO_MANIFEST_DIR") {
        let mut path = path::PathBuf::from(manifest_dir);
        path.push("resources");
        println!("Adding path {:?}", path);
        cb = cb.add_resource_path(path);
    }

    let (ctx, _) = &mut cb.build()?;

    println!("Full filesystem info: {:#?}", ctx.filesystem);

    println!("Resource stats:");
    ctx.filesystem.print_all();

    let dir_contents: Vec<_> = ctx.filesystem.read_dir("/")?.collect();
    println!("Directory has {} things in it:", dir_contents.len());
    for itm in dir_contents {
        println!("   {:?}", itm);
    }

    println!();
    println!("Let's write to a file, it should end up in the user config dir");

    let test_file = path::Path::new("/testfile.txt");
    let bytes = b"test";
    {
        let mut file = ctx.filesystem.create(test_file)?;
        file.write_all(bytes)?;
    }
    println!("Wrote to test file");
    {
        let options = filesystem::OpenOptions::new().append(true);
        let mut file = ctx.filesystem.open_options(test_file, options)?;
        file.write_all(bytes)?;
    }
    println!("Appended to test file");
    {
        let mut buffer = Vec::new();
        let mut file = ctx.filesystem.open(test_file)?;
        file.read_to_end(&mut buffer)?;
        println!(
            "Read from test file: {:?}",
            str::from_utf8(&buffer).unwrap()
        );
    }

    println!();
    println!("Let's read the default conf file");
    if let Ok(_conf) = ctx.filesystem.read_config() {
        println!("Found existing conf file, its contents are:");
        let mut file = ctx.filesystem.open("/conf.toml")?;
        let mut buffer = Vec::new();
        file.read_to_end(&mut buffer)?;
        println!("{}", str::from_utf8(&buffer).unwrap());

        println!("Now deleting it, re-run the example to recreate it.");
        ctx.filesystem.delete("/conf.toml")?;
    } else {
        println!("No existing conf file found, saving one out");
        let c = conf::Conf::new();
        ctx.filesystem.write_config(&c)?;
        println!("Should now be a 'conf.toml' file under user config dir");
    }

    println!();
    println!("Now let's try to read a file that does not exist");
    {
        if let Err(e) = ctx.filesystem.open("/jfkdlasfjdsa") {
            // The error message contains a big hairy list of each
            // directory tried and what error it got from it.
            println!("Got the error: {:#?}", e);
        } else {
            println!("Wait, it does exist?  Weird.")
        }
    }
    Ok(())
}
<|endoftext|>


<commit_before>extern crate euclid;
#[macro_use]
extern crate glium;
extern crate image;

extern crate vitral;

use std::path::Path;
use glium::{DisplayBuild, Surface};
use glium::glutin;
use glium::index::PrimitiveType;
use euclid::Point2D;

use vitral::Context;

type GliumTexture = glium::texture::CompressedSrgbTexture2d;

struct Backend {
    program: glium::Program,
    textures: Vec<GliumTexture>,
}

impl Backend {
    pub fn new(display: &glium::Display) -> Backend {
        let program = program!(
            display,
            150 => {
            vertex: "
                #version 150 core

                uniform mat4 matrix;

                in vec2 pos;
                in vec4 color;
                in vec2 tex_coord;

                out vec4 v_color;
                out vec2 v_tex_coord;

                void main() {
                    gl_Position = vec4(pos, 0.0, 1.0) * matrix;
                    v_color = color;
                    v_tex_coord = tex_coord;
                }
            ",

            fragment: "
                #version 150 core
                uniform sampler2D tex;
                in vec4 v_color;
                in vec2 v_tex_coord;
                out vec4 f_color;

                void main() {
                    f_color = v_color * texture(tex, v_tex_coord);
                }
            "})
                          .unwrap();

        Backend {
            program: program,
            textures: Vec::new(),
        }
    }

    pub fn make_texture(&mut self, display: &glium::Display, img: vitral::ImageBuffer) -> usize {
        let dim = (img.width(), img.height());
        let raw = glium::texture::RawImage2d::from_raw_rgba(img.into_raw(),
                                                            dim);
        let tex = glium::texture::CompressedSrgbTexture2d::new(display,
                                                               raw)
                      .unwrap();
        self.textures.push(tex);
        self.textures.len() - 1
    }

    fn process_events<V>(&self, display: &glium::Display, context: &mut Context<usize, V>) -> bool
        where V: vitral::Vertex
    {
        // polling and handling the events received by the window
        for event in display.poll_events() {
            match event {
                glutin::Event::Closed => return false,
                glutin::Event::MouseMoved(x, y) => {
                    context.input_mouse_move(x, y)
                }
                glutin::Event::MouseInput(state, button) => {
                    context.input_mouse_button(match button {
                                                   glutin::MouseButton::Left => {
                                                       vitral::MouseButton::Left
                                                   }
                                                   glutin::MouseButton::Right => {
                                                       vitral::MouseButton::Right
                                                   }
                                                   _ => vitral::MouseButton::Middle,
                                               },
                                               state == glutin::ElementState::Pressed)
                }
                glutin::Event::ReceivedCharacter(c) => context.input_char(c),
                glutin::Event::KeyboardInput(s, _, Some(vk)) => {
                    let is_down = s == glutin::ElementState::Pressed;
                    use glium::glutin::VirtualKeyCode::*;
                    if let Some(vk) = match vk {
                        Tab => Some(vitral::Keycode::Tab),
                        LShift | RShift => Some(vitral::Keycode::Shift),
                        LControl | RControl => Some(vitral::Keycode::Ctrl),
                        NumpadEnter | Return => Some(vitral::Keycode::Enter),
                        Back => Some(vitral::Keycode::Backspace),
                        Delete => Some(vitral::Keycode::Del),
                        Numpad8 | Up => Some(vitral::Keycode::Up),
                        Numpad2 | Down => Some(vitral::Keycode::Down),
                        Numpad4 | Left => Some(vitral::Keycode::Left),
                        Numpad6 | Right => Some(vitral::Keycode::Right),
                        _ => None
                    } {
                        context.input_key_state(vk, is_down);
                    }
                }
                _ => (),
            }
        }

        true
    }

    pub fn update<V>(&self, display: &glium::Display, context: &mut Context<usize, V>) -> bool
        where V: vitral::Vertex + glium::Vertex
    {
        let mut target = display.draw();
        target.clear_color(0.0, 0.0, 0.0, 0.0);
        let (w, h) = target.get_dimensions();

        for batch in context.end_frame() {
            // building the uniforms
            let uniforms = uniform! {
                matrix: [
                    [2.0 / w as f32, 0.0, 0.0, -1.0],
                    [0.0, -2.0 / h as f32, 0.0, 1.0],
                    [0.0, 0.0, 1.0, 0.0],
                    [0.0, 0.0, 0.0, 1.0f32]
                ],
                tex: glium::uniforms::Sampler::new(&self.textures[batch.texture])
                    .magnify_filter(glium::uniforms::MagnifySamplerFilter::Nearest),
            };

            let vertex_buffer = {
                glium::VertexBuffer::new(display, &batch.vertices)
                    .unwrap()
            };

            // building the index buffer
            let index_buffer =
                glium::IndexBuffer::new(display,
                                        PrimitiveType::TrianglesList,
                                        &batch.triangle_indices)
                    .unwrap();

            let params = glium::draw_parameters::DrawParameters {
                scissor: batch.clip.map(|clip| {
                    glium::Rect {
                        left: clip.origin.x as u32,
                        bottom: h - (clip.origin.y + clip.size.height) as u32,
                        width: clip.size.width as u32,
                        height: clip.size.height as u32,
                    }
                }),
                blend: glium::Blend::alpha_blending(),
                ..Default::default()
            };

            target.draw(&vertex_buffer,
                        &index_buffer,
                        &self.program,
                        &uniforms,
                        &params)
                  .unwrap();
        }

        target.finish().unwrap();

        self.process_events(display, context)
    }
}

// XXX: An exact copy of Vitral vertex struct, just so that I can derive a
// Glium vertex implementatino for it.
#[derive(Copy, Clone)]
pub struct Vertex {
    pub pos: [f32; 2],
    pub color: [f32; 4],
    pub tex_coord: [f32; 2],
}
implement_vertex!(Vertex, pos, color, tex_coord);

impl vitral::Vertex for Vertex {
    fn new(pos: [f32; 2], color: [f32; 4], tex_coord: [f32; 2]) -> Self {
        Vertex {
            pos: pos,
            color: color,
            tex_coord: tex_coord,
        }
    }
}

fn main() {
    // Construct Glium backend.
    let display = glutin::WindowBuilder::new()
                      .build_glium()
                      .unwrap();

    let mut backend = Backend::new(&display);

    // Construct Vitral context.
    let mut context: Context<usize, Vertex>;
    let mut builder = vitral::Builder::new();
    let image = builder.add_image(&image::open(&Path::new("julia.png"))
                                       .unwrap());
    context = builder.build(|img| backend.make_texture(&display, img));

    let font = context.default_font();

    let mut test_input = String::new();

    // Run the program.
    loop {
        context.begin_frame();

        context.draw_image(image,
                           Point2D::new(100.0, 100.0),
                           [1.0, 1.0, 1.0, 1.0]);

        if context.button("Hello, world") {
            println!("Click");
        }

        if context.button("Another button") {
            println!("Clack {}", test_input);
        }

        context.text_input(font,
                           Point2D::new(10.0, 120.0),
                           [0.8, 0.8, 0.8, 1.0],
                           &mut test_input);

        if !backend.update(&display, &mut context) {
            return;
        }
    }
}
<commit_msg>Example tweaking<commit_after>extern crate euclid;
#[macro_use]
extern crate glium;
extern crate image;

extern crate vitral;

use std::path::Path;
use glium::{DisplayBuild, Surface};
use glium::glutin;
use glium::index::PrimitiveType;
use euclid::Point2D;

type Context = vitral::Context<usize, Vertex>;

type GliumTexture = glium::texture::CompressedSrgbTexture2d;

struct Backend {
    program: glium::Program,
    textures: Vec<GliumTexture>,
}

impl Backend {
    pub fn new(display: &glium::Display) -> Backend {
        let program = program!(
            display,
            150 => {
            vertex: "
                #version 150 core

                uniform mat4 matrix;

                in vec2 pos;
                in vec4 color;
                in vec2 tex_coord;

                out vec4 v_color;
                out vec2 v_tex_coord;

                void main() {
                    gl_Position = vec4(pos, 0.0, 1.0) * matrix;
                    v_color = color;
                    v_tex_coord = tex_coord;
                }
            ",

            fragment: "
                #version 150 core
                uniform sampler2D tex;
                in vec4 v_color;
                in vec2 v_tex_coord;
                out vec4 f_color;

                void main() {
                    f_color = v_color * texture(tex, v_tex_coord);
                }
            "})
                          .unwrap();

        Backend {
            program: program,
            textures: Vec::new(),
        }
    }

    pub fn make_texture(&mut self, display: &glium::Display, img: vitral::ImageBuffer) -> usize {
        let dim = (img.width(), img.height());
        let raw = glium::texture::RawImage2d::from_raw_rgba(img.into_raw(),
                                                            dim);
        let tex = glium::texture::CompressedSrgbTexture2d::new(display,
                                                               raw)
                      .unwrap();
        self.textures.push(tex);
        self.textures.len() - 1
    }

    fn process_events<V>(&self, display: &glium::Display, context: &mut vitral::Context<usize, V>) -> bool
        where V: vitral::Vertex
    {
        // polling and handling the events received by the window
        for event in display.poll_events() {
            match event {
                glutin::Event::Closed => return false,
                glutin::Event::MouseMoved(x, y) => {
                    context.input_mouse_move(x, y)
                }
                glutin::Event::MouseInput(state, button) => {
                    context.input_mouse_button(match button {
                                                   glutin::MouseButton::Left => {
                                                       vitral::MouseButton::Left
                                                   }
                                                   glutin::MouseButton::Right => {
                                                       vitral::MouseButton::Right
                                                   }
                                                   _ => vitral::MouseButton::Middle,
                                               },
                                               state == glutin::ElementState::Pressed)
                }
                glutin::Event::ReceivedCharacter(c) => context.input_char(c),
                glutin::Event::KeyboardInput(s, _, Some(vk)) => {
                    let is_down = s == glutin::ElementState::Pressed;
                    use glium::glutin::VirtualKeyCode::*;
                    if let Some(vk) = match vk {
                        Tab => Some(vitral::Keycode::Tab),
                        LShift | RShift => Some(vitral::Keycode::Shift),
                        LControl | RControl => Some(vitral::Keycode::Ctrl),
                        NumpadEnter | Return => Some(vitral::Keycode::Enter),
                        Back => Some(vitral::Keycode::Backspace),
                        Delete => Some(vitral::Keycode::Del),
                        Numpad8 | Up => Some(vitral::Keycode::Up),
                        Numpad2 | Down => Some(vitral::Keycode::Down),
                        Numpad4 | Left => Some(vitral::Keycode::Left),
                        Numpad6 | Right => Some(vitral::Keycode::Right),
                        _ => None
                    } {
                        context.input_key_state(vk, is_down);
                    }
                }
                _ => (),
            }
        }

        true
    }

    pub fn update<V>(&self, display: &glium::Display, context: &mut vitral::Context<usize, V>) -> bool
        where V: vitral::Vertex + glium::Vertex
    {
        let mut target = display.draw();
        target.clear_color(0.0, 0.0, 0.0, 0.0);
        let (w, h) = target.get_dimensions();

        for batch in context.end_frame() {
            // building the uniforms
            let uniforms = uniform! {
                matrix: [
                    [2.0 / w as f32, 0.0, 0.0, -1.0],
                    [0.0, -2.0 / h as f32, 0.0, 1.0],
                    [0.0, 0.0, 1.0, 0.0],
                    [0.0, 0.0, 0.0, 1.0f32]
                ],
                tex: glium::uniforms::Sampler::new(&self.textures[batch.texture])
                    .magnify_filter(glium::uniforms::MagnifySamplerFilter::Nearest),
            };

            let vertex_buffer = {
                glium::VertexBuffer::new(display, &batch.vertices)
                    .unwrap()
            };

            // building the index buffer
            let index_buffer =
                glium::IndexBuffer::new(display,
                                        PrimitiveType::TrianglesList,
                                        &batch.triangle_indices)
                    .unwrap();

            let params = glium::draw_parameters::DrawParameters {
                scissor: batch.clip.map(|clip| {
                    glium::Rect {
                        left: clip.origin.x as u32,
                        bottom: h - (clip.origin.y + clip.size.height) as u32,
                        width: clip.size.width as u32,
                        height: clip.size.height as u32,
                    }
                }),
                blend: glium::Blend::alpha_blending(),
                ..Default::default()
            };

            target.draw(&vertex_buffer,
                        &index_buffer,
                        &self.program,
                        &uniforms,
                        &params)
                  .unwrap();
        }

        target.finish().unwrap();

        self.process_events(display, context)
    }
}

// XXX: An exact copy of Vitral vertex struct, just so that I can derive a
// Glium vertex implementatino for it.
#[derive(Copy, Clone)]
pub struct Vertex {
    pub pos: [f32; 2],
    pub color: [f32; 4],
    pub tex_coord: [f32; 2],
}
implement_vertex!(Vertex, pos, color, tex_coord);

impl vitral::Vertex for Vertex {
    fn new(pos: [f32; 2], color: [f32; 4], tex_coord: [f32; 2]) -> Self {
        Vertex {
            pos: pos,
            color: color,
            tex_coord: tex_coord,
        }
    }
}

fn main() {
    // Construct Glium backend.
    let display = glutin::WindowBuilder::new()
                      .build_glium()
                      .unwrap();

    let mut backend = Backend::new(&display);

    // Construct Vitral context.
    let mut context: Context;
    let mut builder = vitral::Builder::new();
    let image = builder.add_image(&image::open(&Path::new("julia.png"))
                                       .unwrap());
    context = builder.build(|img| backend.make_texture(&display, img));

    let font = context.default_font();

    let mut test_input = String::new();

    // Run the program.
    loop {
        context.begin_frame();

        context.draw_image(image,
                           Point2D::new(100.0, 100.0),
                           [1.0, 1.0, 1.0, 1.0]);

        if context.button("Hello, world") {
            println!("Click");
        }

        if context.button("Another button") {
            println!("Clack {}", test_input);
        }

        context.text_input(font,
                           Point2D::new(10.0, 120.0),
                           [0.8, 0.8, 0.8, 1.0],
                           &mut test_input);

        if !backend.update(&display, &mut context) {
            return;
        }
    }
}
<|endoftext|>


<commit_before>use std::env;
use std::ffi::OsStr;
use std::time::{Duration, UNIX_EPOCH};
use libc::ENOENT;
use fuse::{FileType, FileAttr, Filesystem, Request, ReplyData, ReplyEntry, ReplyAttr, ReplyDirectory};

const TTL: Duration = Duration::from_secs(1);           // 1 second

const HELLO_DIR_ATTR: FileAttr = FileAttr {
    ino: 1,
    size: 0,
    blocks: 0,
    atime: UNIX_EPOCH,                                  // 1970-01-01 00:00:00
    mtime: UNIX_EPOCH,
    ctime: UNIX_EPOCH,
    crtime: UNIX_EPOCH,
    kind: FileType::Directory,
    perm: 0o755,
    nlink: 2,
    uid: 501,
    gid: 20,
    rdev: 0,
    flags: 0,
};

const HELLO_TXT_CONTENT: &str = "Hello World!\n";

const HELLO_TXT_ATTR: FileAttr = FileAttr {
    ino: 2,
    size: 13,
    blocks: 1,
    atime: UNIX_EPOCH,                                  // 1970-01-01 00:00:00
    mtime: UNIX_EPOCH,
    ctime: UNIX_EPOCH,
    crtime: UNIX_EPOCH,
    kind: FileType::RegularFile,
    perm: 0o644,
    nlink: 1,
    uid: 501,
    gid: 20,
    rdev: 0,
    flags: 0,
};

struct HelloFS;

impl Filesystem for HelloFS {
    fn lookup(&mut self, _req: &Request, parent: u64, name: &OsStr, reply: ReplyEntry) {
        if parent == 1 && name.to_str() == Some("hello.txt") {
            reply.entry(&TTL, &HELLO_TXT_ATTR, 0);
        } else {
            reply.error(ENOENT);
        }
    }

    fn getattr(&mut self, _req: &Request, ino: u64, reply: ReplyAttr) {
        match ino {
            1 => reply.attr(&TTL, &HELLO_DIR_ATTR),
            2 => reply.attr(&TTL, &HELLO_TXT_ATTR),
            _ => reply.error(ENOENT),
        }
    }

    fn read(&mut self, _req: &Request, ino: u64, _fh: u64, offset: i64, _size: u32, reply: ReplyData) {
        if ino == 2 {
            reply.data(&HELLO_TXT_CONTENT.as_bytes()[offset as usize..]);
        } else {
            reply.error(ENOENT);
        }
    }

    fn readdir(&mut self, _req: &Request, ino: u64, _fh: u64, offset: i64, mut reply: ReplyDirectory) {
        if ino != 1 {
            reply.error(ENOENT);
            return;
        }

        let entries = vec![
            (1, FileType::Directory, "."),
            (1, FileType::Directory, ".."),
            (2, FileType::RegularFile, "hello.txt"),
        ];

        // Offset of 0 means no offset.
        // Non-zero offset means the passed offset has already been seen, and we should start after
        // it.
        let to_skip = if offset == 0 { offset } else { offset + 1 } as usize;
        for (i, entry) in entries.into_iter().enumerate().skip(to_skip) {
            reply.add(entry.0, i as i64, entry.1, entry.2);
        }
        reply.ok();
    }
}

fn main() {
    env_logger::init();
    let mountpoint = env::args_os().nth(1).unwrap();
    let options = ["-o", "ro", "-o", "fsname=hello"]
        .iter()
        .map(|o| o.as_ref())
        .collect::<Vec<&OsStr>>();
    fuse::mount(HelloFS, mountpoint, &options).unwrap();
}
<commit_msg>Correct offset handling in readdir example<commit_after>use std::env;
use std::ffi::OsStr;
use std::time::{Duration, UNIX_EPOCH};
use libc::ENOENT;
use fuse::{FileType, FileAttr, Filesystem, Request, ReplyData, ReplyEntry, ReplyAttr, ReplyDirectory};

const TTL: Duration = Duration::from_secs(1);           // 1 second

const HELLO_DIR_ATTR: FileAttr = FileAttr {
    ino: 1,
    size: 0,
    blocks: 0,
    atime: UNIX_EPOCH,                                  // 1970-01-01 00:00:00
    mtime: UNIX_EPOCH,
    ctime: UNIX_EPOCH,
    crtime: UNIX_EPOCH,
    kind: FileType::Directory,
    perm: 0o755,
    nlink: 2,
    uid: 501,
    gid: 20,
    rdev: 0,
    flags: 0,
};

const HELLO_TXT_CONTENT: &str = "Hello World!\n";

const HELLO_TXT_ATTR: FileAttr = FileAttr {
    ino: 2,
    size: 13,
    blocks: 1,
    atime: UNIX_EPOCH,                                  // 1970-01-01 00:00:00
    mtime: UNIX_EPOCH,
    ctime: UNIX_EPOCH,
    crtime: UNIX_EPOCH,
    kind: FileType::RegularFile,
    perm: 0o644,
    nlink: 1,
    uid: 501,
    gid: 20,
    rdev: 0,
    flags: 0,
};

struct HelloFS;

impl Filesystem for HelloFS {
    fn lookup(&mut self, _req: &Request, parent: u64, name: &OsStr, reply: ReplyEntry) {
        if parent == 1 && name.to_str() == Some("hello.txt") {
            reply.entry(&TTL, &HELLO_TXT_ATTR, 0);
        } else {
            reply.error(ENOENT);
        }
    }

    fn getattr(&mut self, _req: &Request, ino: u64, reply: ReplyAttr) {
        match ino {
            1 => reply.attr(&TTL, &HELLO_DIR_ATTR),
            2 => reply.attr(&TTL, &HELLO_TXT_ATTR),
            _ => reply.error(ENOENT),
        }
    }

    fn read(&mut self, _req: &Request, ino: u64, _fh: u64, offset: i64, _size: u32, reply: ReplyData) {
        if ino == 2 {
            reply.data(&HELLO_TXT_CONTENT.as_bytes()[offset as usize..]);
        } else {
            reply.error(ENOENT);
        }
    }

    fn readdir(&mut self, _req: &Request, ino: u64, _fh: u64, offset: i64, mut reply: ReplyDirectory) {
        if ino != 1 {
            reply.error(ENOENT);
            return;
        }

        let entries = vec![
            (1, FileType::Directory, "."),
            (1, FileType::Directory, ".."),
            (2, FileType::RegularFile, "hello.txt"),
        ];

        for (i, entry) in entries.into_iter().enumerate().skip(offset as usize) {
            // i + 1 means the index of the next entry
            reply.add(entry.0, (i + 1) as i64, entry.1, entry.2);
        }
        reply.ok();
    }
}

fn main() {
    env_logger::init();
    let mountpoint = env::args_os().nth(1).unwrap();
    let options = ["-o", "ro", "-o", "fsname=hello"]
        .iter()
        .map(|o| o.as_ref())
        .collect::<Vec<&OsStr>>();
    fuse::mount(HelloFS, mountpoint, &options).unwrap();
}
<|endoftext|>


<commit_before>use std::collections::hash_map::DefaultHasher;
use std::f64;
use std::fmt;
use std::hash::{BuildHasher, Hash};

use utils::{HashIter, MyBuildHasherDefault};

/// Abstract, but safe counter.
pub trait Counter: Copy + fmt::Debug + Ord + Sized {
    /// Add self to another counter.
    ///
    /// Returns `Some(Self)` when the addition was successfull (i.e. no overflow occured) and
    /// `None` in case of an error.
    fn checked_add(self, other: Self) -> Option<Self>;

    /// Return a counter representing zero.
    fn zero() -> Self;

    /// Return a counter representing one.
    fn one() -> Self;

    /// Checks whether the counter is zero.
    fn is_zero(&self) -> bool;
}

macro_rules! impl_counter {
    ($t:ty) => {
        impl Counter for $t {
            #[inline]
            fn checked_add(self, other: Self) -> Option<Self> {
                self.checked_add(other)
            }

            #[inline]
            fn zero() -> Self {
                0
            }

            #[inline]
            fn one() -> Self {
                1
            }

            #[inline]
            fn is_zero(&self) -> bool {
                *self == 0
            }
        }
    }
}

impl_counter!(usize);
impl_counter!(u64);
impl_counter!(u32);
impl_counter!(u16);
impl_counter!(u8);

/// Simple implementation of a
/// [Count-min sketch](https://en.wikipedia.org/wiki/Count%E2%80%93min_sketch)
///
/// The type parameter `C` sets the type of the counter in the internal table and can be used to
/// reduce memory consumption when low counts are expected.
#[derive(Clone)]
pub struct CountMinSketch<C = usize, B = MyBuildHasherDefault<DefaultHasher>>
where
    C: Counter,
    B: BuildHasher + Clone + Eq,
{
    table: Vec<C>,
    w: usize,
    d: usize,
    buildhasher: B,
}

impl<C> CountMinSketch<C>
where
    C: Counter,
{
    /// Create new CountMinSketch based on table size.
    ///
    /// - `w` sets the number of columns
    /// - `d` sets the number of rows
    pub fn with_params(w: usize, d: usize) -> CountMinSketch<C> {
        let bh = MyBuildHasherDefault::<DefaultHasher>::default();
        Self::with_params_and_hasher(w, d, bh)
    }

    /// Create new CountMinSketch with the following properties for a point query:
    ///
    /// - `a` is the real count of observed objects
    /// - `a'` is the guessed count of observed objects
    /// - `N` is the total count in the internal table
    /// - `a <= a'` always holds
    /// - `a' <= a + epsilon * N` holds with `p > 1 - delta`
    ///
    /// The following conditions must hold:
    ///
    /// - `epsilon > 0`
    /// - `delta > 0` and `delta < 1`
    ///
    /// Panics when the input conditions do not hold.
    pub fn with_point_query_properties(epsilon: f64, delta: f64) -> CountMinSketch<C> {
        let bh = MyBuildHasherDefault::<DefaultHasher>::default();
        Self::with_point_query_properties_and_hasher(epsilon, delta, bh)
    }
}

impl<C, B> CountMinSketch<C, B>
where
    C: Counter,
    B: BuildHasher + Clone + Eq,
{
    /// Same as `with_params` but with a specific `BuildHasher`.
    pub fn with_params_and_hasher(w: usize, d: usize, buildhasher: B) -> CountMinSketch<C, B> {
        let table = vec![C::zero(); w.checked_mul(d).unwrap()];
        CountMinSketch {
            table: table,
            w: w,
            d: d,
            buildhasher: buildhasher,
        }
    }

    /// Same as `with_params_and_hasher` but with a specific `BuildHasher`.
    pub fn with_point_query_properties_and_hasher(
        epsilon: f64,
        delta: f64,
        buildhasher: B,
    ) -> CountMinSketch<C, B> {
        assert!(epsilon > 0.);
        assert!(delta > 0.);
        assert!(delta < 1.);

        let w = (f64::consts::E / epsilon).ceil() as usize;
        let d = (1. / delta).ln().ceil() as usize;
        CountMinSketch::with_params_and_hasher(w, d, buildhasher)
    }

    /// Get number of columns of internal counter table.
    pub fn w(&self) -> usize {
        self.w
    }

    /// Get number of rows of internal counter table.
    pub fn d(&self) -> usize {
        self.d
    }

    /// Get `BuildHasher`
    pub fn buildhasher(&self) -> &B {
        &self.buildhasher
    }

    /// Check whether the CountMinSketch is empty (i.e. no elements seen yet).
    pub fn is_empty(&self) -> bool {
        self.table.iter().all(|x| x.is_zero())
    }

    /// Add one to the counter of the given element.
    pub fn add<T>(&mut self, obj: &T)
    where
        T: Hash,
    {
        self.add_n(&obj, C::one())
    }

    /// Add `n` to the counter of the given element.
    pub fn add_n<T>(&mut self, obj: &T, n: C)
    where
        T: Hash,
    {
        for (i, pos) in HashIter::new(self.w, self.d, obj, &self.buildhasher).enumerate() {
            let x = i * self.w + pos;
            self.table[x] = self.table[x].checked_add(n).unwrap();
        }
    }

    /// Runs a point query, i.e. a query for the count of a single object.
    pub fn query_point<T>(&self, obj: &T) -> C
    where
        T: Hash,
    {
        HashIter::new(self.w, self.d, obj, &self.buildhasher)
            .enumerate()
            .map(|(i, pos)| i * self.w + pos)
            .map(|x| self.table[x])
            .min()
            .unwrap()
    }

    /// Merge self with another CountMinSketch.
    ///
    /// After this operation `self` will be in the same state as when it would have seen all
    /// elements from `self` and `other`.
    ///
    /// Panics when `d`, `w` or `buildhasher` from `self` and `other` differ.
    pub fn merge(&mut self, other: &CountMinSketch<C, B>) {
        assert_eq!(self.d, other.d);
        assert_eq!(self.w, other.w);
        assert!(self.buildhasher == other.buildhasher);

        self.table = self.table
            .iter()
            .zip(other.table.iter())
            .map(|x| x.0.checked_add(*x.1).unwrap())
            .collect();
    }

    /// Clear internal counters to a fresh state (i.e. no objects seen).
    pub fn clear(&mut self) {
        self.table = vec![C::zero(); self.w.checked_mul(self.d).unwrap()];
    }
}

impl fmt::Debug for CountMinSketch {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "CountMinSketch {{ w: {}, d: {} }}", self.w, self.d)
    }
}

impl<T> Extend<T> for CountMinSketch
where
    T: Hash,
{
    fn extend<S: IntoIterator<Item = T>>(&mut self, iter: S) {
        for elem in iter {
            self.add(&elem);
        }
    }
}

#[cfg(test)]
mod tests {
    use super::CountMinSketch;

    #[test]
    fn getter() {
        let cms = CountMinSketch::<usize>::with_params(10, 20);
        assert_eq!(cms.w(), 10);
        assert_eq!(cms.d(), 20);
        cms.buildhasher();
    }

    #[test]
    fn properties() {
        let cms = CountMinSketch::<usize>::with_point_query_properties(0.01, 0.1);
        assert_eq!(cms.w(), 272);
        assert_eq!(cms.d(), 3);
    }

    #[test]
    fn empty() {
        let cms = CountMinSketch::<usize>::with_params(10, 10);
        assert_eq!(cms.query_point(&1), 0);
        assert!(cms.is_empty());
    }

    #[test]
    fn add_1() {
        let mut cms = CountMinSketch::<usize>::with_params(10, 10);

        cms.add(&1);
        assert_eq!(cms.query_point(&1), 1);
        assert_eq!(cms.query_point(&2), 0);
    }

    #[test]
    fn add_2() {
        let mut cms = CountMinSketch::<usize>::with_params(10, 10);

        cms.add(&1);
        cms.add(&1);
        assert_eq!(cms.query_point(&1), 2);
        assert_eq!(cms.query_point(&2), 0);
    }

    #[test]
    fn add_2_1a() {
        let mut cms = CountMinSketch::<usize>::with_params(10, 10);

        cms.add(&1);
        cms.add(&2);
        cms.add(&1);
        assert_eq!(cms.query_point(&1), 2);
        assert_eq!(cms.query_point(&2), 1);
        assert_eq!(cms.query_point(&3), 0);
    }

    #[test]
    fn add_2_1b() {
        let mut cms = CountMinSketch::<usize>::with_params(10, 10);

        cms.add_n(&1, 2);
        cms.add(&2);
        assert_eq!(cms.query_point(&1), 2);
        assert_eq!(cms.query_point(&2), 1);
        assert_eq!(cms.query_point(&3), 0);
    }

    #[test]
    fn merge() {
        let mut cms1 = CountMinSketch::<usize>::with_params(10, 10);
        let mut cms2 = CountMinSketch::<usize>::with_params(10, 10);

        cms1.add_n(&1, 1);
        cms1.add_n(&2, 2);
        assert_eq!(cms1.query_point(&1), 1);
        assert_eq!(cms1.query_point(&2), 2);
        assert_eq!(cms1.query_point(&3), 0);
        assert_eq!(cms1.query_point(&4), 0);

        cms2.add_n(&2, 20);
        cms2.add_n(&3, 30);
        assert_eq!(cms2.query_point(&1), 0);
        assert_eq!(cms2.query_point(&2), 20);
        assert_eq!(cms2.query_point(&3), 30);
        assert_eq!(cms2.query_point(&4), 0);

        cms1.merge(&cms2);
        assert_eq!(cms1.query_point(&1), 1);
        assert_eq!(cms1.query_point(&2), 22);
        assert_eq!(cms1.query_point(&3), 30);
        assert_eq!(cms1.query_point(&4), 0);
    }

    #[test]
    fn clear() {
        let mut cms = CountMinSketch::<usize>::with_params(10, 10);

        cms.add(&1);
        assert_eq!(cms.query_point(&1), 1);
        assert!(!cms.is_empty());

        cms.clear();
        assert_eq!(cms.query_point(&1), 0);
        assert!(cms.is_empty());
    }

    #[test]
    fn clone() {
        let mut cms1 = CountMinSketch::<usize>::with_params(10, 10);

        cms1.add(&1);
        assert_eq!(cms1.query_point(&1), 1);
        assert_eq!(cms1.query_point(&2), 0);

        let cms2 = cms1.clone();
        assert_eq!(cms2.query_point(&1), 1);
        assert_eq!(cms2.query_point(&2), 0);

        cms1.add(&1);
        assert_eq!(cms1.query_point(&1), 2);
        assert_eq!(cms1.query_point(&2), 0);
        assert_eq!(cms2.query_point(&1), 1);
        assert_eq!(cms2.query_point(&2), 0);
    }

    #[test]
    fn debug() {
        let cms = CountMinSketch::<usize>::with_params(10, 20);
        assert_eq!(format!("{:?}", cms), "CountMinSketch { w: 10, d: 20 }");
    }

    #[test]
    fn extend() {
        let mut cms = CountMinSketch::<usize>::with_params(10, 10);

        cms.extend(vec![1, 1]);
        assert_eq!(cms.query_point(&1), 2);
        assert_eq!(cms.query_point(&2), 0);
    }
}
<commit_msg>countminsketch: u128 support<commit_after>use std::collections::hash_map::DefaultHasher;
use std::f64;
use std::fmt;
use std::hash::{BuildHasher, Hash};

use utils::{HashIter, MyBuildHasherDefault};

/// Abstract, but safe counter.
pub trait Counter: Copy + fmt::Debug + Ord + Sized {
    /// Add self to another counter.
    ///
    /// Returns `Some(Self)` when the addition was successfull (i.e. no overflow occured) and
    /// `None` in case of an error.
    fn checked_add(self, other: Self) -> Option<Self>;

    /// Return a counter representing zero.
    fn zero() -> Self;

    /// Return a counter representing one.
    fn one() -> Self;

    /// Checks whether the counter is zero.
    fn is_zero(&self) -> bool;
}

macro_rules! impl_counter {
    ($t:ty) => {
        impl Counter for $t {
            #[inline]
            fn checked_add(self, other: Self) -> Option<Self> {
                self.checked_add(other)
            }

            #[inline]
            fn zero() -> Self {
                0
            }

            #[inline]
            fn one() -> Self {
                1
            }

            #[inline]
            fn is_zero(&self) -> bool {
                *self == 0
            }
        }
    }
}

impl_counter!(usize);
impl_counter!(u128);
impl_counter!(u64);
impl_counter!(u32);
impl_counter!(u16);
impl_counter!(u8);

/// Simple implementation of a
/// [Count-min sketch](https://en.wikipedia.org/wiki/Count%E2%80%93min_sketch)
///
/// The type parameter `C` sets the type of the counter in the internal table and can be used to
/// reduce memory consumption when low counts are expected.
#[derive(Clone)]
pub struct CountMinSketch<C = usize, B = MyBuildHasherDefault<DefaultHasher>>
where
    C: Counter,
    B: BuildHasher + Clone + Eq,
{
    table: Vec<C>,
    w: usize,
    d: usize,
    buildhasher: B,
}

impl<C> CountMinSketch<C>
where
    C: Counter,
{
    /// Create new CountMinSketch based on table size.
    ///
    /// - `w` sets the number of columns
    /// - `d` sets the number of rows
    pub fn with_params(w: usize, d: usize) -> CountMinSketch<C> {
        let bh = MyBuildHasherDefault::<DefaultHasher>::default();
        Self::with_params_and_hasher(w, d, bh)
    }

    /// Create new CountMinSketch with the following properties for a point query:
    ///
    /// - `a` is the real count of observed objects
    /// - `a'` is the guessed count of observed objects
    /// - `N` is the total count in the internal table
    /// - `a <= a'` always holds
    /// - `a' <= a + epsilon * N` holds with `p > 1 - delta`
    ///
    /// The following conditions must hold:
    ///
    /// - `epsilon > 0`
    /// - `delta > 0` and `delta < 1`
    ///
    /// Panics when the input conditions do not hold.
    pub fn with_point_query_properties(epsilon: f64, delta: f64) -> CountMinSketch<C> {
        let bh = MyBuildHasherDefault::<DefaultHasher>::default();
        Self::with_point_query_properties_and_hasher(epsilon, delta, bh)
    }
}

impl<C, B> CountMinSketch<C, B>
where
    C: Counter,
    B: BuildHasher + Clone + Eq,
{
    /// Same as `with_params` but with a specific `BuildHasher`.
    pub fn with_params_and_hasher(w: usize, d: usize, buildhasher: B) -> CountMinSketch<C, B> {
        let table = vec![C::zero(); w.checked_mul(d).unwrap()];
        CountMinSketch {
            table: table,
            w: w,
            d: d,
            buildhasher: buildhasher,
        }
    }

    /// Same as `with_params_and_hasher` but with a specific `BuildHasher`.
    pub fn with_point_query_properties_and_hasher(
        epsilon: f64,
        delta: f64,
        buildhasher: B,
    ) -> CountMinSketch<C, B> {
        assert!(epsilon > 0.);
        assert!(delta > 0.);
        assert!(delta < 1.);

        let w = (f64::consts::E / epsilon).ceil() as usize;
        let d = (1. / delta).ln().ceil() as usize;
        CountMinSketch::with_params_and_hasher(w, d, buildhasher)
    }

    /// Get number of columns of internal counter table.
    pub fn w(&self) -> usize {
        self.w
    }

    /// Get number of rows of internal counter table.
    pub fn d(&self) -> usize {
        self.d
    }

    /// Get `BuildHasher`
    pub fn buildhasher(&self) -> &B {
        &self.buildhasher
    }

    /// Check whether the CountMinSketch is empty (i.e. no elements seen yet).
    pub fn is_empty(&self) -> bool {
        self.table.iter().all(|x| x.is_zero())
    }

    /// Add one to the counter of the given element.
    pub fn add<T>(&mut self, obj: &T)
    where
        T: Hash,
    {
        self.add_n(&obj, C::one())
    }

    /// Add `n` to the counter of the given element.
    pub fn add_n<T>(&mut self, obj: &T, n: C)
    where
        T: Hash,
    {
        for (i, pos) in HashIter::new(self.w, self.d, obj, &self.buildhasher).enumerate() {
            let x = i * self.w + pos;
            self.table[x] = self.table[x].checked_add(n).unwrap();
        }
    }

    /// Runs a point query, i.e. a query for the count of a single object.
    pub fn query_point<T>(&self, obj: &T) -> C
    where
        T: Hash,
    {
        HashIter::new(self.w, self.d, obj, &self.buildhasher)
            .enumerate()
            .map(|(i, pos)| i * self.w + pos)
            .map(|x| self.table[x])
            .min()
            .unwrap()
    }

    /// Merge self with another CountMinSketch.
    ///
    /// After this operation `self` will be in the same state as when it would have seen all
    /// elements from `self` and `other`.
    ///
    /// Panics when `d`, `w` or `buildhasher` from `self` and `other` differ.
    pub fn merge(&mut self, other: &CountMinSketch<C, B>) {
        assert_eq!(self.d, other.d);
        assert_eq!(self.w, other.w);
        assert!(self.buildhasher == other.buildhasher);

        self.table = self.table
            .iter()
            .zip(other.table.iter())
            .map(|x| x.0.checked_add(*x.1).unwrap())
            .collect();
    }

    /// Clear internal counters to a fresh state (i.e. no objects seen).
    pub fn clear(&mut self) {
        self.table = vec![C::zero(); self.w.checked_mul(self.d).unwrap()];
    }
}

impl fmt::Debug for CountMinSketch {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "CountMinSketch {{ w: {}, d: {} }}", self.w, self.d)
    }
}

impl<T> Extend<T> for CountMinSketch
where
    T: Hash,
{
    fn extend<S: IntoIterator<Item = T>>(&mut self, iter: S) {
        for elem in iter {
            self.add(&elem);
        }
    }
}

#[cfg(test)]
mod tests {
    use super::CountMinSketch;

    #[test]
    fn getter() {
        let cms = CountMinSketch::<usize>::with_params(10, 20);
        assert_eq!(cms.w(), 10);
        assert_eq!(cms.d(), 20);
        cms.buildhasher();
    }

    #[test]
    fn properties() {
        let cms = CountMinSketch::<usize>::with_point_query_properties(0.01, 0.1);
        assert_eq!(cms.w(), 272);
        assert_eq!(cms.d(), 3);
    }

    #[test]
    fn empty() {
        let cms = CountMinSketch::<usize>::with_params(10, 10);
        assert_eq!(cms.query_point(&1), 0);
        assert!(cms.is_empty());
    }

    #[test]
    fn add_1() {
        let mut cms = CountMinSketch::<usize>::with_params(10, 10);

        cms.add(&1);
        assert_eq!(cms.query_point(&1), 1);
        assert_eq!(cms.query_point(&2), 0);
    }

    #[test]
    fn add_2() {
        let mut cms = CountMinSketch::<usize>::with_params(10, 10);

        cms.add(&1);
        cms.add(&1);
        assert_eq!(cms.query_point(&1), 2);
        assert_eq!(cms.query_point(&2), 0);
    }

    #[test]
    fn add_2_1a() {
        let mut cms = CountMinSketch::<usize>::with_params(10, 10);

        cms.add(&1);
        cms.add(&2);
        cms.add(&1);
        assert_eq!(cms.query_point(&1), 2);
        assert_eq!(cms.query_point(&2), 1);
        assert_eq!(cms.query_point(&3), 0);
    }

    #[test]
    fn add_2_1b() {
        let mut cms = CountMinSketch::<usize>::with_params(10, 10);

        cms.add_n(&1, 2);
        cms.add(&2);
        assert_eq!(cms.query_point(&1), 2);
        assert_eq!(cms.query_point(&2), 1);
        assert_eq!(cms.query_point(&3), 0);
    }

    #[test]
    fn merge() {
        let mut cms1 = CountMinSketch::<usize>::with_params(10, 10);
        let mut cms2 = CountMinSketch::<usize>::with_params(10, 10);

        cms1.add_n(&1, 1);
        cms1.add_n(&2, 2);
        assert_eq!(cms1.query_point(&1), 1);
        assert_eq!(cms1.query_point(&2), 2);
        assert_eq!(cms1.query_point(&3), 0);
        assert_eq!(cms1.query_point(&4), 0);

        cms2.add_n(&2, 20);
        cms2.add_n(&3, 30);
        assert_eq!(cms2.query_point(&1), 0);
        assert_eq!(cms2.query_point(&2), 20);
        assert_eq!(cms2.query_point(&3), 30);
        assert_eq!(cms2.query_point(&4), 0);

        cms1.merge(&cms2);
        assert_eq!(cms1.query_point(&1), 1);
        assert_eq!(cms1.query_point(&2), 22);
        assert_eq!(cms1.query_point(&3), 30);
        assert_eq!(cms1.query_point(&4), 0);
    }

    #[test]
    fn clear() {
        let mut cms = CountMinSketch::<usize>::with_params(10, 10);

        cms.add(&1);
        assert_eq!(cms.query_point(&1), 1);
        assert!(!cms.is_empty());

        cms.clear();
        assert_eq!(cms.query_point(&1), 0);
        assert!(cms.is_empty());
    }

    #[test]
    fn clone() {
        let mut cms1 = CountMinSketch::<usize>::with_params(10, 10);

        cms1.add(&1);
        assert_eq!(cms1.query_point(&1), 1);
        assert_eq!(cms1.query_point(&2), 0);

        let cms2 = cms1.clone();
        assert_eq!(cms2.query_point(&1), 1);
        assert_eq!(cms2.query_point(&2), 0);

        cms1.add(&1);
        assert_eq!(cms1.query_point(&1), 2);
        assert_eq!(cms1.query_point(&2), 0);
        assert_eq!(cms2.query_point(&1), 1);
        assert_eq!(cms2.query_point(&2), 0);
    }

    #[test]
    fn debug() {
        let cms = CountMinSketch::<usize>::with_params(10, 20);
        assert_eq!(format!("{:?}", cms), "CountMinSketch { w: 10, d: 20 }");
    }

    #[test]
    fn extend() {
        let mut cms = CountMinSketch::<usize>::with_params(10, 10);

        cms.extend(vec![1, 1]);
        assert_eq!(cms.query_point(&1), 2);
        assert_eq!(cms.query_point(&2), 0);
    }
}
<|endoftext|>


<commit_before>use hyper::server::Request;
use hyper::status::StatusCode;
use hyper::method::Method;
use uuid::Uuid;

use super::super::{Result, ErrorKind};
use super::super::sdk::SdkInfo;
use super::server::{ServerContext, load_request_data};
use super::types::{ApiResponse, ApiError};

#[derive(Deserialize)]
struct SymbolQuery {
    addr: u64,
    image_addr: u64,
    image_vmaddr: Option<u64>,
    image_uuid: Option<Uuid>,
    image_path: Option<String>,
}

#[derive(Deserialize)]
struct SymbolLookupRequest {
    sdk_id: String,
    cpu_name: String,
    symbols: Vec<SymbolQuery>,
}

#[derive(Serialize)]
struct Symbol {
    object_name: String,
    symbol: String,
    addr: u64,
}

#[derive(Serialize)]
struct SymbolResponse {
    symbols: Vec<Option<Symbol>>,
}

pub fn healthcheck_handler(ctx: &ServerContext, req: Request) -> Result<ApiResponse>
{
    if req.method != Method::Get {
        return Err(ApiError::MethodNotAllowed.into());
    }
    let rv = ctx.check_health()?;
    let status = if rv.is_healthy {
        StatusCode::Ok
    } else {
        StatusCode::ServiceUnavailable
    };
    ApiResponse::new(rv, status)
}

pub fn lookup_symbol_handler(ctx: &ServerContext, mut req: Request) -> Result<ApiResponse>
{
    if req.method != Method::Post {
        return Err(ApiError::MethodNotAllowed.into());
    }
    let data : SymbolLookupRequest = load_request_data(&mut req)?;

    let sdk = match ctx.stash.get_memdb_from_sdk_id(&data.sdk_id) {
        Ok(sdk) => sdk,
        Err(err) => {
            if let &ErrorKind::UnknownSdk = err.kind() {
                return Err(ApiError::SdkNotFound.into());
            } else {
                return Err(err)
            }
        },
    };

    let mut rv = vec![];
    for symbol_query in data.symbols {
        let mut rvsym = None;
        if let Some(ref uuid) = symbol_query.image_uuid {
            if let Some(sym) = sdk.lookup_by_uuid(uuid, symbol_query.addr) {
                rvsym = Some(sym);
            }
        } else if let Some(ref name) = symbol_query.image_path {
            if let Some(sym) = sdk.lookup_by_object_name(
                name, &data.cpu_name, symbol_query.addr)
            {
                rvsym = Some(sym);
            }
        }
        rv.push(rvsym.map(|sym| {
            Symbol {
                object_name: sym.object_name().to_string(),
                symbol: sym.symbol().to_string(),
                addr: sym.addr(),
            }
        }));
    }

    ApiResponse::new(SymbolResponse {
        symbols: rv,
    }, StatusCode::Ok)
}
<commit_msg>Renamed some vars<commit_after>use hyper::server::Request;
use hyper::status::StatusCode;
use hyper::method::Method;
use uuid::Uuid;

use super::super::{Result, ErrorKind};
use super::server::{ServerContext, load_request_data};
use super::types::{ApiResponse, ApiError};

#[derive(Deserialize)]
struct SymbolQuery {
    addr: u64,
    image_uuid: Option<Uuid>,
    image_path: Option<String>,
}

#[derive(Deserialize)]
struct SymbolLookupRequest {
    sdk_id: String,
    cpu_name: String,
    symbols: Vec<SymbolQuery>,
}

#[derive(Serialize)]
struct Symbol {
    object_name: String,
    symbol: String,
    addr: u64,
}

#[derive(Serialize)]
struct SymbolResponse {
    symbols: Vec<Option<Symbol>>,
}

pub fn healthcheck_handler(ctx: &ServerContext, req: Request) -> Result<ApiResponse>
{
    if req.method != Method::Get {
        return Err(ApiError::MethodNotAllowed.into());
    }
    let rv = ctx.check_health()?;
    let status = if rv.is_healthy {
        StatusCode::Ok
    } else {
        StatusCode::ServiceUnavailable
    };
    ApiResponse::new(rv, status)
}

pub fn lookup_symbol_handler(ctx: &ServerContext, mut req: Request) -> Result<ApiResponse>
{
    if req.method != Method::Post {
        return Err(ApiError::MethodNotAllowed.into());
    }
    let data : SymbolLookupRequest = load_request_data(&mut req)?;

    let sdk = match ctx.stash.get_memdb_from_sdk_id(&data.sdk_id) {
        Ok(sdk) => sdk,
        Err(err) => {
            if let &ErrorKind::UnknownSdk = err.kind() {
                return Err(ApiError::SdkNotFound.into());
            } else {
                return Err(err)
            }
        },
    };

    let mut rv = vec![];
    for symq in data.symbols {
        let mut rvsym = None;
        if let Some(ref uuid) = symq.image_uuid {
            if let Some(sym) = sdk.lookup_by_uuid(uuid, symq.addr) {
                rvsym = Some(sym);
            }
        } else if let Some(ref name) = symq.image_path {
            if let Some(sym) = sdk.lookup_by_object_name(
                name, &data.cpu_name, symq.addr)
            {
                rvsym = Some(sym);
            }
        }
        rv.push(rvsym.map(|sym| {
            Symbol {
                object_name: sym.object_name().to_string(),
                symbol: sym.symbol().to_string(),
                addr: sym.addr(),
            }
        }));
    }

    ApiResponse::new(SymbolResponse {
        symbols: rv,
    }, StatusCode::Ok)
}
<|endoftext|>


<commit_before>extern crate erl_ast;

use erl_ast::ast2::ModuleDecl;
use std::env;
use std::thread;

fn main() {
    thread::Builder::new()
        .stack_size(32 * 1024 * 1024)
        .spawn(move || {
            for file in env::args().skip(1) {
                let _ = ModuleDecl::from_beam_file(file.clone()).map_err(|err| {
                    println!("FAILED");
                    println!("======");
                    println!("");
                    println!("FILE: {}", file);
                    println!("");
                    println!("REASON:");
                    println!("{}", err);
                    // std::process::exit(1);
                    println!("");
                });
            }
        })
        .unwrap()
        .join()
        .unwrap();
}
<commit_msg>Delete temporary example file<commit_after><|endoftext|>


<commit_before>#![cfg_attr(feature="unstable", feature(unboxed_closures,core))]

#[macro_use]
extern crate units;

mod currencies {
    units! {
        Currency {
            CurrencyEurope => Euro[euro],
            CurrencyUS => Dollar[dollar]
        }
    }
}

use currencies::f64::{euro, dollar};

#[cfg(not(feature = "unstable"))]
fn main() {
    // the conversion factor could also be retrieved from a database
    let dollar_per_euro = 1.1006*dollar/euro;

    let a = 2.0*euro;

    let b = a*dollar_per_euro;
    println!("{:?} = {:?}", a, b);

    let c = 3.0*dollar;
    let d = c/dollar_per_euro;
    println!("{:?} = {:?}", c, d);
}

#[cfg(feature = "unstable")]
fn main() {
    let dollar_per_euro = (dollar/euro)(1.1006);
    let a = euro(2.0);

    let b = a*dollar_per_euro;
    println!("{:?} = {:?}", a, b);

    let c = dollar(3.0);
    let d = c/dollar_per_euro;
    println!("{:?} = {:?}", c, d);
}
<commit_msg>Fixed and extended currencies example<commit_after>#![cfg_attr(feature="unstable", feature(unboxed_closures,core,zero_one))]

#[macro_use]
extern crate units;

mod currencies {
    units! {
        Currency {
            CurrencyEurope => Euro[euro],
            CurrencyUS => Dollar[dollar]
        }
    }
}

use currencies::f64::{euro, dollar, Euro};

#[cfg(not(feature = "unstable"))]
fn main() {
    // the conversion factor could also be retrieved from a database
    let dollar_per_euro = 1.1006*dollar/euro;

    let a = 2.0*euro;
    let b = a*dollar_per_euro;
    println!("{:?} = {:?}", a, b);

    let euro2dollar = |x: Euro| x * dollar_per_euro;
    println!("{:?} = {:?}", 4.0*euro, euro2dollar(4.0*euro));

    let c = 3.0*dollar;
    let d = c/dollar_per_euro;
    println!("{:?} = {:?}", c, d);
}

#[cfg(feature = "unstable")]
fn main() {
    let dollar_per_euro = (dollar/euro)(1.1006);

    let a = euro(2.0);
    let b = a*dollar_per_euro;
    println!("{:?} = {:?}", a, b);

    let euro2dollar = |x: Euro| x * dollar_per_euro;
    println!("{:?} = {:?}", euro(4.0), euro2dollar(euro(4.0)));

    let c = dollar(3.0);
    let d = c/dollar_per_euro;
    println!("{:?} = {:?}", c, d);
}
<|endoftext|>


<commit_before>// Copyright © 2017 Cormac O'Brien
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software
// and associated documentation files (the "Software"), to deal in the Software without
// restriction, including without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
// BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

extern crate byteorder;
extern crate num;
extern crate pnet;
extern crate richter;

use byteorder::{LittleEndian, ReadBytesExt};
use num::FromPrimitive;
use std::io::Cursor;
use std::str::{self, FromStr};
use pnet::packet::Packet;
use pnet::packet::udp::UdpPacket;
use pnet::packet::ip::IpNextHeaderProtocols::Udp;
use pnet::transport::{self, TransportChannelType};
use richter::qw::{self, ClCmd, MoveDeltaFlags, SvCmd};
use richter::util;

static USAGE: &'static str = "Usage: cl-sniff <client IP> <client port> <server IP> <server port>";

fn transcribe_clcmd<'a>(src: &'a [u8]) -> String {
    let mut result = String::new();
    let mut curs = Cursor::new(src);

    let qport = curs.read_u16::<LittleEndian>().unwrap();
    result += &format!("qport={} ", qport);

    let opcode = match curs.read_u8() {
        Ok(o) => o,
        Err(why) => {
            result += &format!("ERROR: {}", why);
            return result;
        }
    };

    let clcmd = match ClCmd::from_u8(opcode) {
        Some(c) => c,
        None => {
            result += &format!("ERROR: Unrecognized opcode {}", opcode);
            return result;
        }
    };

    match clcmd {

        // TODO: use MoveDelta::from_bytes
        ClCmd::Move => {
            result += &format!("Move ");
            result += &format!("crc={} ", curs.read_u8().unwrap());
            result += &format!("loss={} ", curs.read_u8().unwrap());
            result += "\n";

            for i in 0..3 {
                result += &format!("| [D{}] ", i);

                let flags = MoveDeltaFlags::from_bits(curs.read_u8().unwrap()).unwrap();

                result += &format!("flags={:08b} ", flags.bits());

                if flags.contains(qw::MOVE_ANGLE1) {
                    result += &format!("angle1={} ", curs.read_u16::<LittleEndian>().unwrap());
                }

                if flags.contains(qw::MOVE_ANGLE2) {
                    result += &format!("angle2={} ", curs.read_u16::<LittleEndian>().unwrap());
                }

                if flags.contains(qw::MOVE_ANGLE3) {
                    result += &format!("angle3={} ", curs.read_u16::<LittleEndian>().unwrap());
                }

                if flags.contains(qw::MOVE_FORWARD) {
                    result += &format!("forward={} ", curs.read_u16::<LittleEndian>().unwrap());
                }

                if flags.contains(qw::MOVE_SIDE) {
                    result += &format!("side={} ", curs.read_u16::<LittleEndian>().unwrap());
                }

                if flags.contains(qw::MOVE_UP) {
                    result += &format!("up={} ", curs.read_u16::<LittleEndian>().unwrap());
                }

                if flags.contains(qw::MOVE_BUTTONS) {
                    result += &format!("buttons={} ", curs.read_u8().unwrap());
                }

                if flags.contains(qw::MOVE_IMPULSE) {
                    result += &format!("impulse={} ", curs.read_u8().unwrap());
                }

                result += &format!("msec={} ", curs.read_u8().unwrap());
                result += "\n";
            }
        }

        ClCmd::StringCmd => {
            let cmd = util::read_cstring(&mut curs).unwrap();
            result += &format!("cmd=\"{}\"", cmd);
        }

        c => {
            result += &format!("{:?} ", c);
        }
    }

    return result;
}

fn transcribe_svcmd<'a>(src: &'a [u8]) -> String {
    let mut result = String::new();
    let mut curs = Cursor::new(src);

    let cmdbyte = curs.read_u8().unwrap();

    match SvCmd::from_u8(cmdbyte).unwrap() {
        SvCmd::Disconnect => {
            result += "disconnect";
        }

        SvCmd::ModelList => {
            result += "modellist ";

            let modellist = qw::ModelListPacket::from_bytes(&mut curs).unwrap();

            result += &format!("count={} ", modellist.get_count());

            let list = modellist.get_list();
            result += "\nMODEL LIST\n==========\n";
            for model in list.into_iter() {
                result += &format!("\"{}\"\n", model);
            }
            result += "==========\n";
            result += &format!("progress={}\n", modellist.get_progress());
        }

        SvCmd::PlayerInfo => {
            result += "playerinfo ";

            let playerinfo = qw::PlayerInfoPacket::from_bytes(&mut curs).unwrap();
            result += &format!("{:#?} ", playerinfo);
        }

        SvCmd::Print => {
            result += "print ";

            let print_type = qw::PrintType::from_u8(curs.read_u8().unwrap()).unwrap();
            result += &format!("type={:?} ", print_type);

            let msg = util::read_cstring(&mut curs).unwrap();
            result += &format!("msg=\"{}\"", msg);
        }

        SvCmd::ServerData => {
            result += "serverdata ";
            let data = qw::ServerDataPacket::from_bytes(&mut curs).unwrap();

            result += &format!("proto={} ", data.get_protocol_version());
            result += &format!("servercount={} ", data.get_server_count());
            result += &format!("gamedir=\"{}\" ", data.get_game_directory());
            result += &format!("playerno={} ", data.get_player_number());
            result += &format!("levelname=\"{}\" ", data.get_level_name());
            result += &format!("gravity={} ", data.get_gravity());
            result += &format!("stopspeed={} ", data.get_stop_speed());
            result += &format!("maxspeed={} ", data.get_max_speed());
            result += &format!("spectatormaxspeed={} ", data.get_spec_max_speed());
            result += &format!("accelerate={} ", data.get_accelerate());
            result += &format!("airaccelerate={} ", data.get_air_accelerate());
            result += &format!("wateraccelerate={} ", data.get_water_accelerate());
            result += &format!("friction={} ", data.get_friction());
            result += &format!("waterfriction={} ", data.get_water_friction());
            result += &format!("entgravity={} ", data.get_ent_gravity());
        }

        SvCmd::SoundList => {
            result += "soundlist ";

            let soundlist = qw::SoundListPacket::from_bytes(&mut curs).unwrap();

            result += &format!("count={} ", soundlist.get_count());

            let list = soundlist.get_list();
            result += "\nSOUND LIST\n==========\n";
            for sound in list.into_iter() {
                result += &format!("\"{}\"\n", sound);
            }
            result += "==========\n";
            result += &format!("progress={}\n", soundlist.get_progress());
        }

        s => {
            result += &format!("{:?} ", s);
        }
    }

    return result;
}

fn main() {
    let args: Vec<String> = std::env::args().collect();
    if args.len() != 5 {
        println!("{}", USAGE);
        std::process::exit(1);
    }

    let client_ip = std::net::Ipv4Addr::from_str(&args[1]).unwrap();
    let client_port = u16::from_str(&args[2]).unwrap();
    let server_ip = std::net::Ipv4Addr::from_str(&args[3]).unwrap();
    let server_port = u16::from_str(&args[4]).unwrap();

    let (_, mut rx) =
        match pnet::transport::transport_channel(4096, TransportChannelType::Layer3(Udp)) {
            Ok((tx, rx)) => (tx, rx),
            Err(why) => panic!("Error creating channel: {}", why),
        };

    let mut iter = transport::ipv4_packet_iter(&mut rx);
    loop {
        match iter.next() {
            Ok((packet, _)) => {
                let udp_packet = UdpPacket::new(packet.payload()).unwrap();
                let dest_ip = packet.get_destination();
                let dest_port = udp_packet.get_destination();

                if dest_ip == server_ip && dest_port == server_port {
                    print!("CL: ");
                } else if dest_ip == client_ip && dest_port == client_port {
                    print!("SV: ");
                } else {
                    continue;
                }

                let qw_packet = qw::Packet::new(udp_packet.payload()).unwrap();
                match qw_packet {
                    qw::Packet::OutOfBand(oob_packet) => {
                        match oob_packet {
                            qw::OutOfBandPacket::GetChallenge => print!("getchallenge"),
                            qw::OutOfBandPacket::Challenge(challenge) => {
                                print!("challenge={}", challenge)
                            }
                            qw::OutOfBandPacket::Connect(conn_packet) => print!("{}", conn_packet),
                            qw::OutOfBandPacket::Accept => print!("accept"),
                            _ => (),
                        }
                    }

                    qw::Packet::NetChan(nc_packet) => {
                        print!("seq={} [", nc_packet.get_sequence());
                        if nc_packet.get_sequence_reliable() {
                            print!("R");
                        } else {
                            print!(" ");
                        }
                        print!("] ack={} ", nc_packet.get_ack_sequence());

                        if dest_ip == server_ip && dest_port == server_port {
                            print!("{} ", transcribe_clcmd(nc_packet.payload()));
                        } else if dest_ip == client_ip && dest_port == client_port {
                            if nc_packet.payload().len() != 0 {
                                print!("{} ", transcribe_svcmd(nc_packet.payload()));
                            } else {
                                print!("empty");
                            }
                        }
                    }
                }

                println!("");
            }

            Err(why) => panic!("Error reading packet: {}", why),
        }
    }
}
<commit_msg>Fix MoveDeltaFlags identifiers<commit_after>// Copyright © 2017 Cormac O'Brien
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software
// and associated documentation files (the "Software"), to deal in the Software without
// restriction, including without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
// BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

extern crate byteorder;
extern crate num;
extern crate pnet;
extern crate richter;

use byteorder::{LittleEndian, ReadBytesExt};
use num::FromPrimitive;
use std::io::Cursor;
use std::str::{self, FromStr};
use pnet::packet::Packet;
use pnet::packet::udp::UdpPacket;
use pnet::packet::ip::IpNextHeaderProtocols::Udp;
use pnet::transport::{self, TransportChannelType};
use richter::qw::{self, ClCmd, MoveDeltaFlags, SvCmd};
use richter::util;

static USAGE: &'static str = "Usage: cl-sniff <client IP> <client port> <server IP> <server port>";

fn transcribe_clcmd<'a>(src: &'a [u8]) -> String {
    let mut result = String::new();
    let mut curs = Cursor::new(src);

    let qport = curs.read_u16::<LittleEndian>().unwrap();
    result += &format!("qport={} ", qport);

    let opcode = match curs.read_u8() {
        Ok(o) => o,
        Err(why) => {
            result += &format!("ERROR: {}", why);
            return result;
        }
    };

    let clcmd = match ClCmd::from_u8(opcode) {
        Some(c) => c,
        None => {
            result += &format!("ERROR: Unrecognized opcode {}", opcode);
            return result;
        }
    };

    match clcmd {

        // TODO: use MoveDelta::from_bytes
        ClCmd::Move => {
            result += &format!("Move ");
            result += &format!("crc={} ", curs.read_u8().unwrap());
            result += &format!("loss={} ", curs.read_u8().unwrap());
            result += "\n";

            for i in 0..3 {
                result += &format!("| [D{}] ", i);

                let flags = MoveDeltaFlags::from_bits(curs.read_u8().unwrap()).unwrap();

                result += &format!("flags={:08b} ", flags.bits());

                if flags.contains(MoveDeltaFlags::MOVE_ANGLE1) {
                    result += &format!("angle1={} ", curs.read_u16::<LittleEndian>().unwrap());
                }

                if flags.contains(MoveDeltaFlags::MOVE_ANGLE2) {
                    result += &format!("angle2={} ", curs.read_u16::<LittleEndian>().unwrap());
                }

                if flags.contains(MoveDeltaFlags::MOVE_ANGLE3) {
                    result += &format!("angle3={} ", curs.read_u16::<LittleEndian>().unwrap());
                }

                if flags.contains(MoveDeltaFlags::MOVE_FORWARD) {
                    result += &format!("forward={} ", curs.read_u16::<LittleEndian>().unwrap());
                }

                if flags.contains(MoveDeltaFlags::MOVE_SIDE) {
                    result += &format!("side={} ", curs.read_u16::<LittleEndian>().unwrap());
                }

                if flags.contains(MoveDeltaFlags::MOVE_UP) {
                    result += &format!("up={} ", curs.read_u16::<LittleEndian>().unwrap());
                }

                if flags.contains(MoveDeltaFlags::MOVE_BUTTONS) {
                    result += &format!("buttons={} ", curs.read_u8().unwrap());
                }

                if flags.contains(MoveDeltaFlags::MOVE_IMPULSE) {
                    result += &format!("impulse={} ", curs.read_u8().unwrap());
                }

                result += &format!("msec={} ", curs.read_u8().unwrap());
                result += "\n";
            }
        }

        ClCmd::StringCmd => {
            let cmd = util::read_cstring(&mut curs).unwrap();
            result += &format!("cmd=\"{}\"", cmd);
        }

        c => {
            result += &format!("{:?} ", c);
        }
    }

    return result;
}

fn transcribe_svcmd<'a>(src: &'a [u8]) -> String {
    let mut result = String::new();
    let mut curs = Cursor::new(src);

    let cmdbyte = curs.read_u8().unwrap();

    match SvCmd::from_u8(cmdbyte).unwrap() {
        SvCmd::Disconnect => {
            result += "disconnect";
        }

        SvCmd::ModelList => {
            result += "modellist ";

            let modellist = qw::ModelListPacket::from_bytes(&mut curs).unwrap();

            result += &format!("count={} ", modellist.get_count());

            let list = modellist.get_list();
            result += "\nMODEL LIST\n==========\n";
            for model in list.into_iter() {
                result += &format!("\"{}\"\n", model);
            }
            result += "==========\n";
            result += &format!("progress={}\n", modellist.get_progress());
        }

        SvCmd::PlayerInfo => {
            result += "playerinfo ";

            let playerinfo = qw::PlayerInfoPacket::from_bytes(&mut curs).unwrap();
            result += &format!("{:#?} ", playerinfo);
        }

        SvCmd::Print => {
            result += "print ";

            let print_type = qw::PrintType::from_u8(curs.read_u8().unwrap()).unwrap();
            result += &format!("type={:?} ", print_type);

            let msg = util::read_cstring(&mut curs).unwrap();
            result += &format!("msg=\"{}\"", msg);
        }

        SvCmd::ServerData => {
            result += "serverdata ";
            let data = qw::ServerDataPacket::from_bytes(&mut curs).unwrap();

            result += &format!("proto={} ", data.get_protocol_version());
            result += &format!("servercount={} ", data.get_server_count());
            result += &format!("gamedir=\"{}\" ", data.get_game_directory());
            result += &format!("playerno={} ", data.get_player_number());
            result += &format!("levelname=\"{}\" ", data.get_level_name());
            result += &format!("gravity={} ", data.get_gravity());
            result += &format!("stopspeed={} ", data.get_stop_speed());
            result += &format!("maxspeed={} ", data.get_max_speed());
            result += &format!("spectatormaxspeed={} ", data.get_spec_max_speed());
            result += &format!("accelerate={} ", data.get_accelerate());
            result += &format!("airaccelerate={} ", data.get_air_accelerate());
            result += &format!("wateraccelerate={} ", data.get_water_accelerate());
            result += &format!("friction={} ", data.get_friction());
            result += &format!("waterfriction={} ", data.get_water_friction());
            result += &format!("entgravity={} ", data.get_ent_gravity());
        }

        SvCmd::SoundList => {
            result += "soundlist ";

            let soundlist = qw::SoundListPacket::from_bytes(&mut curs).unwrap();

            result += &format!("count={} ", soundlist.get_count());

            let list = soundlist.get_list();
            result += "\nSOUND LIST\n==========\n";
            for sound in list.into_iter() {
                result += &format!("\"{}\"\n", sound);
            }
            result += "==========\n";
            result += &format!("progress={}\n", soundlist.get_progress());
        }

        s => {
            result += &format!("{:?} ", s);
        }
    }

    return result;
}

fn main() {
    let args: Vec<String> = std::env::args().collect();
    if args.len() != 5 {
        println!("{}", USAGE);
        std::process::exit(1);
    }

    let client_ip = std::net::Ipv4Addr::from_str(&args[1]).unwrap();
    let client_port = u16::from_str(&args[2]).unwrap();
    let server_ip = std::net::Ipv4Addr::from_str(&args[3]).unwrap();
    let server_port = u16::from_str(&args[4]).unwrap();

    let (_, mut rx) =
        match pnet::transport::transport_channel(4096, TransportChannelType::Layer3(Udp)) {
            Ok((tx, rx)) => (tx, rx),
            Err(why) => panic!("Error creating channel: {}", why),
        };

    let mut iter = transport::ipv4_packet_iter(&mut rx);
    loop {
        match iter.next() {
            Ok((packet, _)) => {
                let udp_packet = UdpPacket::new(packet.payload()).unwrap();
                let dest_ip = packet.get_destination();
                let dest_port = udp_packet.get_destination();

                if dest_ip == server_ip && dest_port == server_port {
                    print!("CL: ");
                } else if dest_ip == client_ip && dest_port == client_port {
                    print!("SV: ");
                } else {
                    continue;
                }

                let qw_packet = qw::Packet::new(udp_packet.payload()).unwrap();
                match qw_packet {
                    qw::Packet::OutOfBand(oob_packet) => {
                        match oob_packet {
                            qw::OutOfBandPacket::GetChallenge => print!("getchallenge"),
                            qw::OutOfBandPacket::Challenge(challenge) => {
                                print!("challenge={}", challenge)
                            }
                            qw::OutOfBandPacket::Connect(conn_packet) => print!("{}", conn_packet),
                            qw::OutOfBandPacket::Accept => print!("accept"),
                            _ => (),
                        }
                    }

                    qw::Packet::NetChan(nc_packet) => {
                        print!("seq={} [", nc_packet.get_sequence());
                        if nc_packet.get_sequence_reliable() {
                            print!("R");
                        } else {
                            print!(" ");
                        }
                        print!("] ack={} ", nc_packet.get_ack_sequence());

                        if dest_ip == server_ip && dest_port == server_port {
                            print!("{} ", transcribe_clcmd(nc_packet.payload()));
                        } else if dest_ip == client_ip && dest_port == client_port {
                            if nc_packet.payload().len() != 0 {
                                print!("{} ", transcribe_svcmd(nc_packet.payload()));
                            } else {
                                print!("empty");
                            }
                        }
                    }
                }

                println!("");
            }

            Err(why) => panic!("Error reading packet: {}", why),
        }
    }
}
<|endoftext|>