<commit_before>extern crate glib_sys;
extern crate glib;
extern crate cairo;
extern crate cairo_sys;
extern crate libc;

use self::glib::translate::*;

use color::*;
use node::RsvgNode;
use node::NodeType;
use path_builder::RsvgPathBuilder;
use state::RsvgState;

pub enum RsvgDrawingCtx {}

extern "C" {
    fn rsvg_drawing_ctx_get_dpi (draw_ctx: *const RsvgDrawingCtx,
                                 out_dpi_x: *mut f64,
                                 out_dpi_y: *mut f64);

    fn rsvg_drawing_ctx_get_normalized_font_size (draw_ctx: *const RsvgDrawingCtx) -> f64;

    fn rsvg_drawing_ctx_get_view_box_size (draw_ctx: *const RsvgDrawingCtx,
                                           out_x: *mut f64,
                                           out_y: *mut f64);

    fn rsvg_drawing_ctx_push_view_box (draw_ctx: *const RsvgDrawingCtx,
                                       width:     f64,
                                       height:    f64);

    fn rsvg_drawing_ctx_pop_view_box (draw_ctx: *const RsvgDrawingCtx);

    fn rsvg_drawing_ctx_acquire_node (draw_ctx: *const RsvgDrawingCtx,
                                      url:      *const libc::c_char) -> *mut RsvgNode;

    fn rsvg_drawing_ctx_acquire_node_of_type (draw_ctx:  *const RsvgDrawingCtx,
                                              url:       *const libc::c_char,
                                              node_type: NodeType) -> *mut RsvgNode;

    fn rsvg_drawing_ctx_release_node (draw_ctx: *const RsvgDrawingCtx,
                                      node:     *mut RsvgNode);

    fn rsvg_drawing_ctx_get_current_state_affine (draw_ctx: *const RsvgDrawingCtx) -> cairo::Matrix;

    fn rsvg_drawing_ctx_set_current_state_affine (draw_ctx: *const RsvgDrawingCtx,
                                                  affine:   *const cairo::Matrix);

    fn rsvg_drawing_ctx_add_clipping_rect (draw_ctx: *const RsvgDrawingCtx,
                                           x: f64,
                                           y: f64,
                                           w: f64,
                                           h: f64);

    fn rsvg_drawing_ctx_draw_node_from_stack (draw_ctx: *const RsvgDrawingCtx,
                                              node:     *const RsvgNode,
                                              dominate: i32);

    fn rsvg_current_state (draw_ctx: *const RsvgDrawingCtx) -> *mut RsvgState;
    fn rsvg_state_new () -> *mut RsvgState;
    fn rsvg_state_reinit (state: *mut RsvgState);
    fn rsvg_state_reconstruct (state: *mut RsvgState, node: *const RsvgNode);
    fn rsvg_state_is_overflow (state: *const RsvgState) -> glib_sys::gboolean;
    fn rsvg_state_has_overflow (state: *const RsvgState) -> glib_sys::gboolean;
    fn rsvg_state_get_cond_true (state: *const RsvgState) -> glib_sys::gboolean;
    fn rsvg_state_get_stop_color (state: *const RsvgState) -> *const ColorSpec;
    fn rsvg_state_get_current_color (state: *const RsvgState) -> u32;

    fn rsvg_state_push (draw_ctx: *const RsvgDrawingCtx);
    fn rsvg_state_pop (draw_ctx: *const RsvgDrawingCtx);

    fn rsvg_state_reinherit_top (draw_ctx: *const RsvgDrawingCtx,
                                 state: *mut RsvgState,
                                 dominate: libc::c_int);

    fn rsvg_push_discrete_layer (draw_ctx: *const RsvgDrawingCtx);
    fn rsvg_pop_discrete_layer (draw_ctx: *const RsvgDrawingCtx);

    fn rsvg_render_path_builder (draw_ctx: *const RsvgDrawingCtx,
                                 builder: *const RsvgPathBuilder);

    fn rsvg_cairo_get_cairo_context (draw_ctx: *const RsvgDrawingCtx) -> *mut cairo_sys::cairo_t;
    fn rsvg_cairo_set_cairo_context (draw_ctx: *const RsvgDrawingCtx, cr: *const cairo_sys::cairo_t);
}

pub fn get_dpi (draw_ctx: *const RsvgDrawingCtx) -> (f64, f64) {
    let mut dpi_x: f64 = 0.0;
    let mut dpi_y: f64 = 0.0;

    unsafe { rsvg_drawing_ctx_get_dpi (draw_ctx, &mut dpi_x, &mut dpi_y); }

    (dpi_x, dpi_y)
}

pub fn get_normalized_font_size (draw_ctx: *const RsvgDrawingCtx) -> f64 {
    unsafe { rsvg_drawing_ctx_get_normalized_font_size (draw_ctx) }
}

pub fn get_view_box_size (draw_ctx: *const RsvgDrawingCtx) -> (f64, f64) {
    let mut w: f64 = 0.0;
    let mut h: f64 = 0.0;

    unsafe { rsvg_drawing_ctx_get_view_box_size (draw_ctx, &mut w, &mut h); }

    (w, h)
}

pub fn push_view_box (draw_ctx: *const RsvgDrawingCtx,
                      width:     f64,
                      height:    f64)
{
    unsafe { rsvg_drawing_ctx_push_view_box (draw_ctx, width, height); }
}

pub fn pop_view_box (draw_ctx: *const RsvgDrawingCtx) {
    unsafe { rsvg_drawing_ctx_pop_view_box (draw_ctx); }
}

pub fn acquire_node (draw_ctx: *const RsvgDrawingCtx,
                     url:      &str) -> *mut RsvgNode {
    unsafe { rsvg_drawing_ctx_acquire_node (draw_ctx, str::to_glib_none (url).0) }
}

pub fn acquire_node_of_type (draw_ctx:  *const RsvgDrawingCtx,
                             url:       &str,
                             node_type: NodeType) -> *mut RsvgNode {
    unsafe { rsvg_drawing_ctx_acquire_node_of_type (draw_ctx, str::to_glib_none (url).0, node_type) }
}

pub fn release_node (draw_ctx: *const RsvgDrawingCtx,
                     node:     *mut RsvgNode) {
    unsafe { rsvg_drawing_ctx_release_node (draw_ctx, node); }
}

pub fn state_reinherit_top (draw_ctx: *const RsvgDrawingCtx,
                            state: *mut RsvgState,
                            dominate: i32) {
    unsafe { rsvg_state_reinherit_top (draw_ctx, state, dominate); }
}

pub fn push_discrete_layer (draw_ctx: *const RsvgDrawingCtx) {
    unsafe { rsvg_push_discrete_layer (draw_ctx); }
}

pub fn pop_discrete_layer (draw_ctx: *const RsvgDrawingCtx) {
    unsafe { rsvg_pop_discrete_layer (draw_ctx); }
}

pub fn render_path_builder (draw_ctx: *const RsvgDrawingCtx,
                            builder: &RsvgPathBuilder) {
    unsafe { rsvg_render_path_builder (draw_ctx, builder); }
}

pub fn get_cairo_context (draw_ctx: *const RsvgDrawingCtx) -> cairo::Context {
    unsafe {
        let raw_cr = rsvg_cairo_get_cairo_context (draw_ctx);

        let cr = cairo::Context::from_glib_none (raw_cr);

        cr
    }
}

pub fn set_cairo_context (draw_ctx: *const RsvgDrawingCtx, cr: &cairo::Context) {
    unsafe {
        let raw_cr = cr.to_glib_none ().0;

        rsvg_cairo_set_cairo_context (draw_ctx, raw_cr);
    }
}

pub fn get_current_state_affine (draw_ctx: *const RsvgDrawingCtx) -> cairo::Matrix {
    unsafe {
        rsvg_drawing_ctx_get_current_state_affine (draw_ctx)
    }
}

pub fn set_current_state_affine (draw_ctx: *const RsvgDrawingCtx, affine: cairo::Matrix) {
    unsafe {
        rsvg_drawing_ctx_set_current_state_affine (draw_ctx, &affine);
    }
}

pub fn add_clipping_rect (draw_ctx: *const RsvgDrawingCtx,
                          x: f64,
                          y: f64,
                          w: f64,
                          h: f64) {
    unsafe { rsvg_drawing_ctx_add_clipping_rect (draw_ctx, x, y, w, h); }
}

pub fn draw_node_from_stack (draw_ctx: *const RsvgDrawingCtx,
                             node:     *const RsvgNode,
                             dominate: i32) {
    unsafe { rsvg_drawing_ctx_draw_node_from_stack (draw_ctx, node, dominate); }
}

pub fn get_current_state (draw_ctx: *const RsvgDrawingCtx) -> *mut RsvgState {
    unsafe { rsvg_current_state (draw_ctx) }
}

pub fn state_new () -> *mut RsvgState {
    unsafe { rsvg_state_new () }
}

pub fn state_reinit (state: *mut RsvgState) {
    unsafe { rsvg_state_reinit (state); }
}

pub fn state_reconstruct (state: *mut RsvgState, node: *const RsvgNode) {
    unsafe { rsvg_state_reconstruct (state, node); }
}

pub fn state_is_overflow (state: *const RsvgState) -> bool {
    unsafe { from_glib (rsvg_state_is_overflow (state)) }
}

pub fn state_has_overflow (state: *const RsvgState) -> bool {
    unsafe { from_glib (rsvg_state_has_overflow (state)) }
}

pub fn state_get_cond_true (state: *const RsvgState) -> bool {
    unsafe { from_glib (rsvg_state_get_cond_true (state)) }
}

pub fn state_push (draw_ctx: *const RsvgDrawingCtx) {
    unsafe {
        rsvg_state_push (draw_ctx);
    }
}

pub fn state_pop (draw_ctx: *const RsvgDrawingCtx) {
    unsafe {
        rsvg_state_pop (draw_ctx);
    }
}

pub fn state_get_stop_color (state: *const RsvgState) -> Option<ColorSpec> {
    unsafe {
        let spec_ptr = rsvg_state_get_stop_color (state);

        if spec_ptr.is_null () {
            None
        } else {
            Some (*spec_ptr)
        }
    }
}

pub fn state_get_current_color (state: *const RsvgState) -> u32 {
    unsafe {
        rsvg_state_get_current_color (state)
    }
}
<commit_msg>drawing_ctx::state_get_stop_color(): Return a Result<Color>, not a ColorSpec<commit_after>extern crate glib_sys;
extern crate glib;
extern crate cairo;
extern crate cairo_sys;
extern crate libc;

use self::glib::translate::*;

use color::*;
use error::*;
use opacity::*;
use node::RsvgNode;
use node::NodeType;
use path_builder::RsvgPathBuilder;
use state::RsvgState;

pub enum RsvgDrawingCtx {}

extern "C" {
    fn rsvg_drawing_ctx_get_dpi (draw_ctx: *const RsvgDrawingCtx,
                                 out_dpi_x: *mut f64,
                                 out_dpi_y: *mut f64);

    fn rsvg_drawing_ctx_get_normalized_font_size (draw_ctx: *const RsvgDrawingCtx) -> f64;

    fn rsvg_drawing_ctx_get_view_box_size (draw_ctx: *const RsvgDrawingCtx,
                                           out_x: *mut f64,
                                           out_y: *mut f64);

    fn rsvg_drawing_ctx_push_view_box (draw_ctx: *const RsvgDrawingCtx,
                                       width:     f64,
                                       height:    f64);

    fn rsvg_drawing_ctx_pop_view_box (draw_ctx: *const RsvgDrawingCtx);

    fn rsvg_drawing_ctx_acquire_node (draw_ctx: *const RsvgDrawingCtx,
                                      url:      *const libc::c_char) -> *mut RsvgNode;

    fn rsvg_drawing_ctx_acquire_node_of_type (draw_ctx:  *const RsvgDrawingCtx,
                                              url:       *const libc::c_char,
                                              node_type: NodeType) -> *mut RsvgNode;

    fn rsvg_drawing_ctx_release_node (draw_ctx: *const RsvgDrawingCtx,
                                      node:     *mut RsvgNode);

    fn rsvg_drawing_ctx_get_current_state_affine (draw_ctx: *const RsvgDrawingCtx) -> cairo::Matrix;

    fn rsvg_drawing_ctx_set_current_state_affine (draw_ctx: *const RsvgDrawingCtx,
                                                  affine:   *const cairo::Matrix);

    fn rsvg_drawing_ctx_add_clipping_rect (draw_ctx: *const RsvgDrawingCtx,
                                           x: f64,
                                           y: f64,
                                           w: f64,
                                           h: f64);

    fn rsvg_drawing_ctx_draw_node_from_stack (draw_ctx: *const RsvgDrawingCtx,
                                              node:     *const RsvgNode,
                                              dominate: i32);

    fn rsvg_current_state (draw_ctx: *const RsvgDrawingCtx) -> *mut RsvgState;
    fn rsvg_state_new () -> *mut RsvgState;
    fn rsvg_state_reinit (state: *mut RsvgState);
    fn rsvg_state_reconstruct (state: *mut RsvgState, node: *const RsvgNode);
    fn rsvg_state_is_overflow (state: *const RsvgState) -> glib_sys::gboolean;
    fn rsvg_state_has_overflow (state: *const RsvgState) -> glib_sys::gboolean;
    fn rsvg_state_get_cond_true (state: *const RsvgState) -> glib_sys::gboolean;
    fn rsvg_state_get_stop_color (state: *const RsvgState) -> *const ColorSpec;
    fn rsvg_state_get_current_color (state: *const RsvgState) -> u32;

    fn rsvg_state_push (draw_ctx: *const RsvgDrawingCtx);
    fn rsvg_state_pop (draw_ctx: *const RsvgDrawingCtx);

    fn rsvg_state_reinherit_top (draw_ctx: *const RsvgDrawingCtx,
                                 state: *mut RsvgState,
                                 dominate: libc::c_int);

    fn rsvg_push_discrete_layer (draw_ctx: *const RsvgDrawingCtx);
    fn rsvg_pop_discrete_layer (draw_ctx: *const RsvgDrawingCtx);

    fn rsvg_render_path_builder (draw_ctx: *const RsvgDrawingCtx,
                                 builder: *const RsvgPathBuilder);

    fn rsvg_cairo_get_cairo_context (draw_ctx: *const RsvgDrawingCtx) -> *mut cairo_sys::cairo_t;
    fn rsvg_cairo_set_cairo_context (draw_ctx: *const RsvgDrawingCtx, cr: *const cairo_sys::cairo_t);
}

pub fn get_dpi (draw_ctx: *const RsvgDrawingCtx) -> (f64, f64) {
    let mut dpi_x: f64 = 0.0;
    let mut dpi_y: f64 = 0.0;

    unsafe { rsvg_drawing_ctx_get_dpi (draw_ctx, &mut dpi_x, &mut dpi_y); }

    (dpi_x, dpi_y)
}

pub fn get_normalized_font_size (draw_ctx: *const RsvgDrawingCtx) -> f64 {
    unsafe { rsvg_drawing_ctx_get_normalized_font_size (draw_ctx) }
}

pub fn get_view_box_size (draw_ctx: *const RsvgDrawingCtx) -> (f64, f64) {
    let mut w: f64 = 0.0;
    let mut h: f64 = 0.0;

    unsafe { rsvg_drawing_ctx_get_view_box_size (draw_ctx, &mut w, &mut h); }

    (w, h)
}

pub fn push_view_box (draw_ctx: *const RsvgDrawingCtx,
                      width:     f64,
                      height:    f64)
{
    unsafe { rsvg_drawing_ctx_push_view_box (draw_ctx, width, height); }
}

pub fn pop_view_box (draw_ctx: *const RsvgDrawingCtx) {
    unsafe { rsvg_drawing_ctx_pop_view_box (draw_ctx); }
}

pub fn acquire_node (draw_ctx: *const RsvgDrawingCtx,
                     url:      &str) -> *mut RsvgNode {
    unsafe { rsvg_drawing_ctx_acquire_node (draw_ctx, str::to_glib_none (url).0) }
}

pub fn acquire_node_of_type (draw_ctx:  *const RsvgDrawingCtx,
                             url:       &str,
                             node_type: NodeType) -> *mut RsvgNode {
    unsafe { rsvg_drawing_ctx_acquire_node_of_type (draw_ctx, str::to_glib_none (url).0, node_type) }
}

pub fn release_node (draw_ctx: *const RsvgDrawingCtx,
                     node:     *mut RsvgNode) {
    unsafe { rsvg_drawing_ctx_release_node (draw_ctx, node); }
}

pub fn state_reinherit_top (draw_ctx: *const RsvgDrawingCtx,
                            state: *mut RsvgState,
                            dominate: i32) {
    unsafe { rsvg_state_reinherit_top (draw_ctx, state, dominate); }
}

pub fn push_discrete_layer (draw_ctx: *const RsvgDrawingCtx) {
    unsafe { rsvg_push_discrete_layer (draw_ctx); }
}

pub fn pop_discrete_layer (draw_ctx: *const RsvgDrawingCtx) {
    unsafe { rsvg_pop_discrete_layer (draw_ctx); }
}

pub fn render_path_builder (draw_ctx: *const RsvgDrawingCtx,
                            builder: &RsvgPathBuilder) {
    unsafe { rsvg_render_path_builder (draw_ctx, builder); }
}

pub fn get_cairo_context (draw_ctx: *const RsvgDrawingCtx) -> cairo::Context {
    unsafe {
        let raw_cr = rsvg_cairo_get_cairo_context (draw_ctx);

        let cr = cairo::Context::from_glib_none (raw_cr);

        cr
    }
}

pub fn set_cairo_context (draw_ctx: *const RsvgDrawingCtx, cr: &cairo::Context) {
    unsafe {
        let raw_cr = cr.to_glib_none ().0;

        rsvg_cairo_set_cairo_context (draw_ctx, raw_cr);
    }
}

pub fn get_current_state_affine (draw_ctx: *const RsvgDrawingCtx) -> cairo::Matrix {
    unsafe {
        rsvg_drawing_ctx_get_current_state_affine (draw_ctx)
    }
}

pub fn set_current_state_affine (draw_ctx: *const RsvgDrawingCtx, affine: cairo::Matrix) {
    unsafe {
        rsvg_drawing_ctx_set_current_state_affine (draw_ctx, &affine);
    }
}

pub fn add_clipping_rect (draw_ctx: *const RsvgDrawingCtx,
                          x: f64,
                          y: f64,
                          w: f64,
                          h: f64) {
    unsafe { rsvg_drawing_ctx_add_clipping_rect (draw_ctx, x, y, w, h); }
}

pub fn draw_node_from_stack (draw_ctx: *const RsvgDrawingCtx,
                             node:     *const RsvgNode,
                             dominate: i32) {
    unsafe { rsvg_drawing_ctx_draw_node_from_stack (draw_ctx, node, dominate); }
}

pub fn get_current_state (draw_ctx: *const RsvgDrawingCtx) -> *mut RsvgState {
    unsafe { rsvg_current_state (draw_ctx) }
}

pub fn state_new () -> *mut RsvgState {
    unsafe { rsvg_state_new () }
}

pub fn state_reinit (state: *mut RsvgState) {
    unsafe { rsvg_state_reinit (state); }
}

pub fn state_reconstruct (state: *mut RsvgState, node: *const RsvgNode) {
    unsafe { rsvg_state_reconstruct (state, node); }
}

pub fn state_is_overflow (state: *const RsvgState) -> bool {
    unsafe { from_glib (rsvg_state_is_overflow (state)) }
}

pub fn state_has_overflow (state: *const RsvgState) -> bool {
    unsafe { from_glib (rsvg_state_has_overflow (state)) }
}

pub fn state_get_cond_true (state: *const RsvgState) -> bool {
    unsafe { from_glib (rsvg_state_get_cond_true (state)) }
}

pub fn state_push (draw_ctx: *const RsvgDrawingCtx) {
    unsafe {
        rsvg_state_push (draw_ctx);
    }
}

pub fn state_pop (draw_ctx: *const RsvgDrawingCtx) {
    unsafe {
        rsvg_state_pop (draw_ctx);
    }
}

pub fn state_get_stop_color (state: *const RsvgState) -> Result<Option<Color>, AttributeError> {
    unsafe {
        let spec_ptr = rsvg_state_get_stop_color (state);

        if spec_ptr.is_null () {
            Ok (None)
        } else {
            Color::from_color_spec (&*spec_ptr).map (|color| Some (color))
        }
    }
}

pub fn state_get_current_color (state: *const RsvgState) -> u32 {
    unsafe {
        rsvg_state_get_current_color (state)
    }
}
<|endoftext|>


<commit_before>import std::map::{hashmap,str_hash};
import driver::session::session;
import lib::llvm::{TypeRef, ValueRef};
import syntax::ast;
import back::abi;
import common::*;
import build::*;
import base::*;
import type_of::*;
import ast::def_id;
import util::ppaux::ty_to_str;

enum reflector = {
    visitor_val: ValueRef,
    visitor_methods: @[ty::method],
    mut bcx: block
};

impl methods for reflector {

    fn c_uint(u: uint) -> ValueRef {
        C_uint(self.bcx.ccx(), u)
    }

    fn c_int(i: int) -> ValueRef {
        C_int(self.bcx.ccx(), i)
    }

    fn c_slice(s: str) -> ValueRef {
        let ss = C_estr_slice(self.bcx.ccx(), s);
        do_spill_noroot(self.bcx, ss)
    }

    fn c_size_and_align(t: ty::t) -> [ValueRef] {
        let tr = type_of::type_of(self.bcx.ccx(), t);
        let s = shape::llsize_of_real(self.bcx.ccx(), tr);
        let a = shape::llalign_of_min(self.bcx.ccx(), tr);
        ret [self.c_uint(s),
             self.c_uint(a)];
    }

    fn visit(ty_name: str, args: [ValueRef]) {
        let tcx = self.bcx.tcx();
        let mth_idx = option::get(ty::method_idx(@("visit_" + ty_name),
                                                 *self.visitor_methods));
        let mth_ty = ty::mk_fn(tcx, self.visitor_methods[mth_idx].fty);
        let v = self.visitor_val;
        let get_lval = {|bcx|
            let callee =
                impl::trans_iface_callee(bcx, v, mth_ty, mth_idx);
            #debug("calling mth ty %s, lltype %s",
                   ty_to_str(bcx.ccx().tcx, mth_ty),
                   val_str(bcx.ccx().tn, callee.val));
            callee
        };
        #debug("passing %u args:", vec::len(args));
        let bcx = self.bcx;
        for args.eachi {|i, a|
            #debug("arg %u: %s", i, val_str(bcx.ccx().tn, a));
        }
        self.bcx =
            trans_call_inner(self.bcx, none, mth_ty, ty::mk_bool(tcx),
                             get_lval, arg_vals(args), ignore);
    }

    fn visit_tydesc(t: ty::t) {
        self.bcx =
            call_tydesc_glue(self.bcx, self.visitor_val, t,
                             abi::tydesc_field_visit_glue);
    }

    fn bracketed_t(bracket_name: str, t: ty::t, extra: [ValueRef]) {
        self.visit("enter_" + bracket_name, extra);
        self.visit_tydesc(t);
        self.visit("leave_" + bracket_name, extra);
    }

    fn bracketed_mt(bracket_name: str, mt: ty::mt, extra: [ValueRef]) {
        self.bracketed_t(bracket_name, mt.ty,
                         [self.c_uint(mt.mutbl as uint)] + extra);
    }

    fn vstore_name_and_extra(vstore: ty::vstore,
                             f: fn(str,[ValueRef])) {
        alt vstore {
          ty::vstore_fixed(n) { f("fixed", [self.c_uint(n)]) }
          ty::vstore_slice(_) { f("slice", []) }
          ty::vstore_uniq { f("uniq", []);}
          ty::vstore_box { f("box", []); }
        }
    }

    fn leaf(name: str) {
        self.visit(name, []);
    }

    // Entrypoint
    fn visit_ty(t: ty::t) {

        let bcx = self.bcx;
        #debug("reflect::visit_ty %s",
               ty_to_str(bcx.ccx().tcx, t));

        alt ty::get(t).struct {
          ty::ty_bot { self.leaf("bot") }
          ty::ty_nil { self.leaf("nil") }
          ty::ty_bool { self.leaf("bool") }
          ty::ty_int(ast::ty_i) { self.leaf("int") }
          ty::ty_int(ast::ty_char) { self.leaf("char") }
          ty::ty_int(ast::ty_i8) { self.leaf("i8") }
          ty::ty_int(ast::ty_i16) { self.leaf("i16") }
          ty::ty_int(ast::ty_i32) { self.leaf("i32") }
          ty::ty_int(ast::ty_i64) { self.leaf("i64") }
          ty::ty_uint(ast::ty_u) { self.leaf("uint") }
          ty::ty_uint(ast::ty_u8) { self.leaf("u8") }
          ty::ty_uint(ast::ty_u16) { self.leaf("u16") }
          ty::ty_uint(ast::ty_u32) { self.leaf("u32") }
          ty::ty_uint(ast::ty_u64) { self.leaf("u64") }
          ty::ty_float(ast::ty_f) { self.leaf("float") }
          ty::ty_float(ast::ty_f32) { self.leaf("f32") }
          ty::ty_float(ast::ty_f64) { self.leaf("f64") }
          ty::ty_str { self.leaf("str") }

          ty::ty_vec(mt) { self.bracketed_mt("vec", mt, []) }
          ty::ty_estr(vst) {
            self.vstore_name_and_extra(vst) {|name, extra|
                self.visit("estr_" + name, extra)
            }
          }
          ty::ty_evec(mt, vst) {
            self.vstore_name_and_extra(vst) {|name, extra|
                self.bracketed_mt("evec_" + name, mt, extra)
            }
          }
          ty::ty_box(mt) { self.bracketed_mt("box", mt, []) }
          ty::ty_uniq(mt) { self.bracketed_mt("uniq", mt, []) }
          ty::ty_ptr(mt) { self.bracketed_mt("ptr", mt, []) }
          ty::ty_rptr(_, mt) { self.bracketed_mt("rptr", mt, []) }

          ty::ty_rec(fields) {
            self.visit("enter_rec", [self.c_uint(vec::len(fields))]);
            for fields.eachi {|i, field|
                self.bracketed_mt("rec_field", field.mt,
                                  [self.c_uint(i),
                                   self.c_slice(*field.ident)]);
            }
            self.visit("leave_rec", [self.c_uint(vec::len(fields))]);
          }

          ty::ty_tup(tys) {
            self.visit("enter_tup", [self.c_uint(vec::len(tys))]);
            for tys.eachi {|i, t|
                self.bracketed_t("tup_field", t, [self.c_uint(i)]);
            }
            self.visit("leave_tup", [self.c_uint(vec::len(tys))]);
          }

          // FIXME: fetch constants out of intrinsic:: for the numbers.
          ty::ty_fn(fty) {
            let pureval = alt fty.purity {
              ast::pure_fn { 0u }
              ast::unsafe_fn { 1u }
              ast::impure_fn { 2u }
              ast::crust_fn { 3u }
            };
            let protoval = alt fty.proto {
              ast::proto_bare { 0u }
              ast::proto_any { 1u }
              ast::proto_uniq { 2u }
              ast::proto_box { 3u }
              ast::proto_block { 4u }
            };
            let retval = alt fty.ret_style {
              ast::noreturn { 0u }
              ast::return_val { 1u }
            };
            let extra = [self.c_uint(pureval),
                         self.c_uint(protoval),
                         self.c_uint(vec::len(fty.inputs)),
                         self.c_uint(retval)];
            self.visit("enter_fn", extra);
            for fty.inputs.eachi {|i, arg|
                let modeval = alt arg.mode {
                  ast::infer(_) { 0u }
                  ast::expl(e) {
                    alt e {
                      ast::by_ref { 1u }
                      ast::by_val { 2u }
                      ast::by_mutbl_ref { 3u }
                      ast::by_move { 4u }
                      ast::by_copy { 5u }
                    }
                  }
                };
                self.bracketed_t("fn_input", arg.ty,
                                 [self.c_uint(i),
                                  self.c_uint(modeval)]);
            }
            self.bracketed_t("fn_output", fty.output,
                             [self.c_uint(retval)]);
            self.visit("leave_fn", extra);
          }

          ty::ty_class(did, substs) {
            let bcx = self.bcx;
            let tcx = bcx.ccx().tcx;
            let fields = ty::class_items_as_fields(tcx, did, substs);
            self.visit("enter_class", [self.c_uint(vec::len(fields))]);
            for fields.eachi {|i, field|
                self.bracketed_mt("class_field", field.mt,
                                  [self.c_uint(i),
                                   self.c_slice(*field.ident)]);
            }
            self.visit("leave_class", [self.c_uint(vec::len(fields))]);
          }

          // FIXME: visiting all the variants in turn is probably
          // not ideal. It'll work but will get costly on big enums.
          // Maybe let the visitor tell us if it wants to visit only
          // a particular variant?
          ty::ty_enum(did, substs) {
            let bcx = self.bcx;
            let tcx = bcx.ccx().tcx;
            let variants = ty::substd_enum_variants(tcx, did, substs);

            self.visit("enter_enum", [self.c_uint(vec::len(variants))]);
            for variants.eachi {|i, v|
                let extra = [self.c_uint(i),
                             self.c_int(v.disr_val),
                             self.c_uint(vec::len(v.args)),
                             self.c_slice(*v.name)];
                self.visit("enter_enum_variant", extra);
                for v.args.eachi {|j, a|
                    self.bracketed_t("enum_variant_field", a,
                                     [self.c_uint(j)]);
                }
                self.visit("leave_enum_variant", extra);
            }
            self.visit("leave_enum", [self.c_uint(vec::len(variants))]);
          }

          // Miscallaneous extra types
          ty::ty_iface(_, _) { self.leaf("iface") }
          ty::ty_res(_, t, _) { self.bracketed_t("res", t, []) }
          ty::ty_var(_) { self.leaf("var") }
          ty::ty_var_integral(_) { self.leaf("var_integral") }
          ty::ty_param(n, _) { self.visit("param", [self.c_uint(n)]) }
          ty::ty_self { self.leaf("self") }
          ty::ty_type { self.leaf("type") }
          ty::ty_opaque_box { self.leaf("opaque_box") }
          ty::ty_constr(t, _) { self.bracketed_t("constr", t, []) }
          ty::ty_opaque_closure_ptr(ck) {
            let ckval = alt ck {
              ty::ck_block { 0u }
              ty::ck_box { 1u }
              ty::ck_uniq { 2u }
            };
            self.visit("closure_ptr", [self.c_uint(ckval)])
          }
          ty::ty_unboxed_vec(mt) { self.bracketed_mt("vec", mt, []) }
        }
    }
}

// Emit a sequence of calls to visit_ty::visit_foo
fn emit_calls_to_iface_visit_ty(bcx: block, t: ty::t,
                                visitor_val: ValueRef,
                                visitor_iid: def_id) -> block {

    let r = reflector({
        visitor_val: visitor_val,
        visitor_methods: ty::iface_methods(bcx.tcx(), visitor_iid),
        mut bcx: bcx
    });

    r.visit_ty(t);
    ret r.bcx;
}
<commit_msg>Comments only: annotate FIXMEs in reflect<commit_after>import std::map::{hashmap,str_hash};
import driver::session::session;
import lib::llvm::{TypeRef, ValueRef};
import syntax::ast;
import back::abi;
import common::*;
import build::*;
import base::*;
import type_of::*;
import ast::def_id;
import util::ppaux::ty_to_str;

enum reflector = {
    visitor_val: ValueRef,
    visitor_methods: @[ty::method],
    mut bcx: block
};

impl methods for reflector {

    fn c_uint(u: uint) -> ValueRef {
        C_uint(self.bcx.ccx(), u)
    }

    fn c_int(i: int) -> ValueRef {
        C_int(self.bcx.ccx(), i)
    }

    fn c_slice(s: str) -> ValueRef {
        let ss = C_estr_slice(self.bcx.ccx(), s);
        do_spill_noroot(self.bcx, ss)
    }

    fn c_size_and_align(t: ty::t) -> [ValueRef] {
        let tr = type_of::type_of(self.bcx.ccx(), t);
        let s = shape::llsize_of_real(self.bcx.ccx(), tr);
        let a = shape::llalign_of_min(self.bcx.ccx(), tr);
        ret [self.c_uint(s),
             self.c_uint(a)];
    }

    fn visit(ty_name: str, args: [ValueRef]) {
        let tcx = self.bcx.tcx();
        let mth_idx = option::get(ty::method_idx(@("visit_" + ty_name),
                                                 *self.visitor_methods));
        let mth_ty = ty::mk_fn(tcx, self.visitor_methods[mth_idx].fty);
        let v = self.visitor_val;
        let get_lval = {|bcx|
            let callee =
                impl::trans_iface_callee(bcx, v, mth_ty, mth_idx);
            #debug("calling mth ty %s, lltype %s",
                   ty_to_str(bcx.ccx().tcx, mth_ty),
                   val_str(bcx.ccx().tn, callee.val));
            callee
        };
        #debug("passing %u args:", vec::len(args));
        let bcx = self.bcx;
        for args.eachi {|i, a|
            #debug("arg %u: %s", i, val_str(bcx.ccx().tn, a));
        }
        self.bcx =
            trans_call_inner(self.bcx, none, mth_ty, ty::mk_bool(tcx),
                             get_lval, arg_vals(args), ignore);
    }

    fn visit_tydesc(t: ty::t) {
        self.bcx =
            call_tydesc_glue(self.bcx, self.visitor_val, t,
                             abi::tydesc_field_visit_glue);
    }

    fn bracketed_t(bracket_name: str, t: ty::t, extra: [ValueRef]) {
        self.visit("enter_" + bracket_name, extra);
        self.visit_tydesc(t);
        self.visit("leave_" + bracket_name, extra);
    }

    fn bracketed_mt(bracket_name: str, mt: ty::mt, extra: [ValueRef]) {
        self.bracketed_t(bracket_name, mt.ty,
                         [self.c_uint(mt.mutbl as uint)] + extra);
    }

    fn vstore_name_and_extra(vstore: ty::vstore,
                             f: fn(str,[ValueRef])) {
        alt vstore {
          ty::vstore_fixed(n) { f("fixed", [self.c_uint(n)]) }
          ty::vstore_slice(_) { f("slice", []) }
          ty::vstore_uniq { f("uniq", []);}
          ty::vstore_box { f("box", []); }
        }
    }

    fn leaf(name: str) {
        self.visit(name, []);
    }

    // Entrypoint
    fn visit_ty(t: ty::t) {

        let bcx = self.bcx;
        #debug("reflect::visit_ty %s",
               ty_to_str(bcx.ccx().tcx, t));

        alt ty::get(t).struct {
          ty::ty_bot { self.leaf("bot") }
          ty::ty_nil { self.leaf("nil") }
          ty::ty_bool { self.leaf("bool") }
          ty::ty_int(ast::ty_i) { self.leaf("int") }
          ty::ty_int(ast::ty_char) { self.leaf("char") }
          ty::ty_int(ast::ty_i8) { self.leaf("i8") }
          ty::ty_int(ast::ty_i16) { self.leaf("i16") }
          ty::ty_int(ast::ty_i32) { self.leaf("i32") }
          ty::ty_int(ast::ty_i64) { self.leaf("i64") }
          ty::ty_uint(ast::ty_u) { self.leaf("uint") }
          ty::ty_uint(ast::ty_u8) { self.leaf("u8") }
          ty::ty_uint(ast::ty_u16) { self.leaf("u16") }
          ty::ty_uint(ast::ty_u32) { self.leaf("u32") }
          ty::ty_uint(ast::ty_u64) { self.leaf("u64") }
          ty::ty_float(ast::ty_f) { self.leaf("float") }
          ty::ty_float(ast::ty_f32) { self.leaf("f32") }
          ty::ty_float(ast::ty_f64) { self.leaf("f64") }
          ty::ty_str { self.leaf("str") }

          ty::ty_vec(mt) { self.bracketed_mt("vec", mt, []) }
          ty::ty_estr(vst) {
            self.vstore_name_and_extra(vst) {|name, extra|
                self.visit("estr_" + name, extra)
            }
          }
          ty::ty_evec(mt, vst) {
            self.vstore_name_and_extra(vst) {|name, extra|
                self.bracketed_mt("evec_" + name, mt, extra)
            }
          }
          ty::ty_box(mt) { self.bracketed_mt("box", mt, []) }
          ty::ty_uniq(mt) { self.bracketed_mt("uniq", mt, []) }
          ty::ty_ptr(mt) { self.bracketed_mt("ptr", mt, []) }
          ty::ty_rptr(_, mt) { self.bracketed_mt("rptr", mt, []) }

          ty::ty_rec(fields) {
            self.visit("enter_rec", [self.c_uint(vec::len(fields))]);
            for fields.eachi {|i, field|
                self.bracketed_mt("rec_field", field.mt,
                                  [self.c_uint(i),
                                   self.c_slice(*field.ident)]);
            }
            self.visit("leave_rec", [self.c_uint(vec::len(fields))]);
          }

          ty::ty_tup(tys) {
            self.visit("enter_tup", [self.c_uint(vec::len(tys))]);
            for tys.eachi {|i, t|
                self.bracketed_t("tup_field", t, [self.c_uint(i)]);
            }
            self.visit("leave_tup", [self.c_uint(vec::len(tys))]);
          }

          // FIXME: fetch constants out of intrinsic:: for the numbers.
          // (#2594)
          ty::ty_fn(fty) {
            let pureval = alt fty.purity {
              ast::pure_fn { 0u }
              ast::unsafe_fn { 1u }
              ast::impure_fn { 2u }
              ast::crust_fn { 3u }
            };
            let protoval = alt fty.proto {
              ast::proto_bare { 0u }
              ast::proto_any { 1u }
              ast::proto_uniq { 2u }
              ast::proto_box { 3u }
              ast::proto_block { 4u }
            };
            let retval = alt fty.ret_style {
              ast::noreturn { 0u }
              ast::return_val { 1u }
            };
            let extra = [self.c_uint(pureval),
                         self.c_uint(protoval),
                         self.c_uint(vec::len(fty.inputs)),
                         self.c_uint(retval)];
            self.visit("enter_fn", extra);
            for fty.inputs.eachi {|i, arg|
                let modeval = alt arg.mode {
                  ast::infer(_) { 0u }
                  ast::expl(e) {
                    alt e {
                      ast::by_ref { 1u }
                      ast::by_val { 2u }
                      ast::by_mutbl_ref { 3u }
                      ast::by_move { 4u }
                      ast::by_copy { 5u }
                    }
                  }
                };
                self.bracketed_t("fn_input", arg.ty,
                                 [self.c_uint(i),
                                  self.c_uint(modeval)]);
            }
            self.bracketed_t("fn_output", fty.output,
                             [self.c_uint(retval)]);
            self.visit("leave_fn", extra);
          }

          ty::ty_class(did, substs) {
            let bcx = self.bcx;
            let tcx = bcx.ccx().tcx;
            let fields = ty::class_items_as_fields(tcx, did, substs);
            self.visit("enter_class", [self.c_uint(vec::len(fields))]);
            for fields.eachi {|i, field|
                self.bracketed_mt("class_field", field.mt,
                                  [self.c_uint(i),
                                   self.c_slice(*field.ident)]);
            }
            self.visit("leave_class", [self.c_uint(vec::len(fields))]);
          }

          // FIXME: visiting all the variants in turn is probably
          // not ideal. It'll work but will get costly on big enums.
          // Maybe let the visitor tell us if it wants to visit only
          // a particular variant? (#2595)
          ty::ty_enum(did, substs) {
            let bcx = self.bcx;
            let tcx = bcx.ccx().tcx;
            let variants = ty::substd_enum_variants(tcx, did, substs);

            self.visit("enter_enum", [self.c_uint(vec::len(variants))]);
            for variants.eachi {|i, v|
                let extra = [self.c_uint(i),
                             self.c_int(v.disr_val),
                             self.c_uint(vec::len(v.args)),
                             self.c_slice(*v.name)];
                self.visit("enter_enum_variant", extra);
                for v.args.eachi {|j, a|
                    self.bracketed_t("enum_variant_field", a,
                                     [self.c_uint(j)]);
                }
                self.visit("leave_enum_variant", extra);
            }
            self.visit("leave_enum", [self.c_uint(vec::len(variants))]);
          }

          // Miscallaneous extra types
          ty::ty_iface(_, _) { self.leaf("iface") }
          ty::ty_res(_, t, _) { self.bracketed_t("res", t, []) }
          ty::ty_var(_) { self.leaf("var") }
          ty::ty_var_integral(_) { self.leaf("var_integral") }
          ty::ty_param(n, _) { self.visit("param", [self.c_uint(n)]) }
          ty::ty_self { self.leaf("self") }
          ty::ty_type { self.leaf("type") }
          ty::ty_opaque_box { self.leaf("opaque_box") }
          ty::ty_constr(t, _) { self.bracketed_t("constr", t, []) }
          ty::ty_opaque_closure_ptr(ck) {
            let ckval = alt ck {
              ty::ck_block { 0u }
              ty::ck_box { 1u }
              ty::ck_uniq { 2u }
            };
            self.visit("closure_ptr", [self.c_uint(ckval)])
          }
          ty::ty_unboxed_vec(mt) { self.bracketed_mt("vec", mt, []) }
        }
    }
}

// Emit a sequence of calls to visit_ty::visit_foo
fn emit_calls_to_iface_visit_ty(bcx: block, t: ty::t,
                                visitor_val: ValueRef,
                                visitor_iid: def_id) -> block {

    let r = reflector({
        visitor_val: visitor_val,
        visitor_methods: ty::iface_methods(bcx.tcx(), visitor_iid),
        mut bcx: bcx
    });

    r.visit_ty(t);
    ret r.bcx;
}
<|endoftext|>


<commit_before>extern crate tempdir;

extern crate grpc_compiler;

extern crate protobuf;
extern crate protoc;
extern crate protoc_rust;

use std::fs;
use std::io;
use std::io::Read;
use std::io::Write;

pub type Error = io::Error;
pub type Result<T> = io::Result<T>;

#[derive(Debug, Default)]
pub struct Args<'a> {
    /// --lang_out= param
    pub out_dir: &'a str,
    /// -I args
    pub includes: &'a [&'a str],
    /// List of .proto files to compile
    pub input: &'a [&'a str],
    /// Generate rust-protobuf files along with rust-gprc
    pub rust_protobuf: bool,
    /// Customize rust-protobuf codegen
    pub rust_protobuf_customize: protoc_rust::Customize,
}

pub fn run(args: Args) -> Result<()> {
    let protoc = protoc::Protoc::from_env_path();
    let version = protoc.version().expect("protoc version");
    if !version.is_3() {
        panic!("protobuf must have version 3");
    }

    if args.rust_protobuf {
        protoc_rust::run(protoc_rust::Args {
            out_dir: args.out_dir,
            includes: args.includes,
            input: args.input,
            customize: args.rust_protobuf_customize,
            ..Default::default()
        })?;
    }

    let temp_dir = tempdir::TempDir::new("protoc-rust")?;
    let temp_file = temp_dir.path().join("descriptor.pbbin");
    let temp_file = temp_file.to_str().expect("utf-8 file name");

    protoc.write_descriptor_set(protoc::DescriptorSetOutArgs {
        out: temp_file,
        includes: args.includes,
        input: args.input,
        include_imports: true,
    })?;

    let mut fds = Vec::new();
    let mut file = fs::File::open(temp_file)?;
    file.read_to_end(&mut fds)?;

    drop(file);
    drop(temp_dir);

    let fds: protobuf::descriptor::FileDescriptorSet =
        protobuf::parse_from_bytes(&fds).map_err(|e| io::Error::new(io::ErrorKind::Other, e))?;

    let mut includes = args.includes;
    if includes.is_empty() {
        static DOT_SLICE: &'static [&'static str] = &["."];
        includes = DOT_SLICE;
    }

    let mut files_to_generate = Vec::new();
    'outer: for file in args.input {
        for include in includes {
            if let Some(truncated) = remove_path_prefix(file, include) {
                files_to_generate.push(truncated.to_owned());
                continue 'outer;
            }
        }

        return Err(Error::new(
            io::ErrorKind::Other,
            format!(
                "file {:?} is not found in includes {:?}",
                file, args.includes
            ),
        ));
    }

    let gen_result = grpc_compiler::codegen::gen(fds.get_file(), &files_to_generate);

    for r in gen_result {
        let r: protobuf::compiler_plugin::GenResult = r;
        let file = format!("{}/{}", args.out_dir, r.name);
        let mut file = fs::File::create(&file)?;
        file.write_all(&r.content)?;
        file.flush()?;
    }

    Ok(())
}

fn remove_dot_slash(path: &str) -> &str {
    if path == "." {
        ""
    } else if path.starts_with("./") || path.starts_with(".\\") {
        &path[2..]
    } else {
        path
    }
}

fn remove_path_prefix<'a>(mut path: &'a str, mut prefix: &str) -> Option<&'a str> {
    path = remove_dot_slash(path);
    prefix = remove_dot_slash(prefix);

    if prefix == "" {
        return Some(path);
    }

    if prefix.ends_with("/") || prefix.ends_with("\\") {
        prefix = &prefix[..prefix.len() - 1];
    }

    if !path.starts_with(prefix) {
        return None;
    }

    if path.len() <= prefix.len() {
        return None;
    }

    if path.as_bytes()[prefix.len()] == b'/' || path.as_bytes()[prefix.len()] == b'\\' {
        return Some(&path[prefix.len() + 1..]);
    } else {
        return None;
    }
}

#[cfg(test)]
mod test {
    #[test]
    fn remove_path_prefix() {
        assert_eq!(
            Some("abc.proto"),
            super::remove_path_prefix("xxx/abc.proto", "xxx")
        );
        assert_eq!(
            Some("abc.proto"),
            super::remove_path_prefix("xxx/abc.proto", "xxx/")
        );
        assert_eq!(
            Some("abc.proto"),
            super::remove_path_prefix("../xxx/abc.proto", "../xxx/")
        );
        assert_eq!(
            Some("abc.proto"),
            super::remove_path_prefix("abc.proto", ".")
        );
        assert_eq!(
            Some("abc.proto"),
            super::remove_path_prefix("abc.proto", "./")
        );
        assert_eq!(None, super::remove_path_prefix("xxx/abc.proto", "yyy"));
        assert_eq!(None, super::remove_path_prefix("xxx/abc.proto", "yyy/"));
    }
}
<commit_msg>Use modern rust-protobuf API<commit_after>extern crate tempdir;

extern crate grpc_compiler;

extern crate protobuf;
extern crate protoc;
extern crate protoc_rust;

use std::fs;
use std::io;
use std::io::Read;
use std::io::Write;

pub type Error = io::Error;
pub type Result<T> = io::Result<T>;

#[derive(Debug, Default)]
pub struct Args<'a> {
    /// --lang_out= param
    pub out_dir: &'a str,
    /// -I args
    pub includes: &'a [&'a str],
    /// List of .proto files to compile
    pub input: &'a [&'a str],
    /// Generate rust-protobuf files along with rust-gprc
    pub rust_protobuf: bool,
    /// Customize rust-protobuf codegen
    pub rust_protobuf_customize: protoc_rust::Customize,
}

// TODO: replace with `Codegen` object
pub fn run(args: Args) -> Result<()> {
    let protoc = protoc::Protoc::from_env_path();
    let version = protoc.version().expect("protoc version");
    if !version.is_3() {
        panic!("protobuf must have version 3");
    }

    if args.rust_protobuf {
        protoc_rust::Codegen::new()
            .out_dir(args.out_dir)
            .includes(args.includes)
            .inputs(args.input)
            .customize(args.rust_protobuf_customize)
            .run()?;
    }

    let temp_dir = tempdir::TempDir::new("protoc-rust")?;
    let temp_file = temp_dir.path().join("descriptor.pbbin");
    let temp_file = temp_file.to_str().expect("utf-8 file name");

    protoc.write_descriptor_set(protoc::DescriptorSetOutArgs {
        out: temp_file,
        includes: args.includes,
        input: args.input,
        include_imports: true,
    })?;

    let mut fds = Vec::new();
    let mut file = fs::File::open(temp_file)?;
    file.read_to_end(&mut fds)?;

    drop(file);
    drop(temp_dir);

    let fds: protobuf::descriptor::FileDescriptorSet =
        protobuf::parse_from_bytes(&fds).map_err(|e| io::Error::new(io::ErrorKind::Other, e))?;

    let mut includes = args.includes;
    if includes.is_empty() {
        static DOT_SLICE: &'static [&'static str] = &["."];
        includes = DOT_SLICE;
    }

    let mut files_to_generate = Vec::new();
    'outer: for file in args.input {
        for include in includes {
            if let Some(truncated) = remove_path_prefix(file, include) {
                files_to_generate.push(truncated.to_owned());
                continue 'outer;
            }
        }

        return Err(Error::new(
            io::ErrorKind::Other,
            format!(
                "file {:?} is not found in includes {:?}",
                file, args.includes
            ),
        ));
    }

    let gen_result = grpc_compiler::codegen::gen(fds.get_file(), &files_to_generate);

    for r in gen_result {
        let r: protobuf::compiler_plugin::GenResult = r;
        let file = format!("{}/{}", args.out_dir, r.name);
        let mut file = fs::File::create(&file)?;
        file.write_all(&r.content)?;
        file.flush()?;
    }

    Ok(())
}

fn remove_dot_slash(path: &str) -> &str {
    if path == "." {
        ""
    } else if path.starts_with("./") || path.starts_with(".\\") {
        &path[2..]
    } else {
        path
    }
}

fn remove_path_prefix<'a>(mut path: &'a str, mut prefix: &str) -> Option<&'a str> {
    path = remove_dot_slash(path);
    prefix = remove_dot_slash(prefix);

    if prefix == "" {
        return Some(path);
    }

    if prefix.ends_with("/") || prefix.ends_with("\\") {
        prefix = &prefix[..prefix.len() - 1];
    }

    if !path.starts_with(prefix) {
        return None;
    }

    if path.len() <= prefix.len() {
        return None;
    }

    if path.as_bytes()[prefix.len()] == b'/' || path.as_bytes()[prefix.len()] == b'\\' {
        return Some(&path[prefix.len() + 1..]);
    } else {
        return None;
    }
}

#[cfg(test)]
mod test {
    #[test]
    fn remove_path_prefix() {
        assert_eq!(
            Some("abc.proto"),
            super::remove_path_prefix("xxx/abc.proto", "xxx")
        );
        assert_eq!(
            Some("abc.proto"),
            super::remove_path_prefix("xxx/abc.proto", "xxx/")
        );
        assert_eq!(
            Some("abc.proto"),
            super::remove_path_prefix("../xxx/abc.proto", "../xxx/")
        );
        assert_eq!(
            Some("abc.proto"),
            super::remove_path_prefix("abc.proto", ".")
        );
        assert_eq!(
            Some("abc.proto"),
            super::remove_path_prefix("abc.proto", "./")
        );
        assert_eq!(None, super::remove_path_prefix("xxx/abc.proto", "yyy"));
        assert_eq!(None, super::remove_path_prefix("xxx/abc.proto", "yyy/"));
    }
}
<|endoftext|>


<commit_before>pub mod grammar;

use fall_tree::File;
use fall_parse::{self, TreeBuilder};
use self::grammar::*;

pub fn parse(text: String) -> File {
    register_node_types();
    fall_parse::parse(
        text,
        grammar::FILE,
        grammar::TOKENIZER,
        &parse_file
    )
}

fn parse_file(b: &mut TreeBuilder) {
    parse_nodes(b);
    b.skip_until(&[KW_TOKENIZER]);
    parse_tokenizer(b);

    b.parse_many(&parse_syn_rule)
}

fn parse_nodes(b: &mut TreeBuilder) -> bool {
    b.start(NODES_DEF);
    if !b.try_eat(KW_NODES) {
        b.rollback(NODES_DEF);
        return false;
    }
    if b.try_eat(LBRACE) {
        b.parse_many(&|b| b.try_eat(IDENT));
        b.try_eat(RBRACE);
    }
    b.finish(NODES_DEF);
    true
}

fn parse_tokenizer(b: &mut TreeBuilder) -> bool {
    b.start(TOKENIZER_DEF);
    if !b.try_eat(KW_TOKENIZER) {
        b.rollback(TOKENIZER_DEF);
        return false;
    }
    if b.try_eat(LBRACE) {
        b.parse_many(&|b| {
            b.skip_until(&[RBRACE, IDENT]);
            parse_lex_rule(b)
        });
        b.try_eat(RBRACE);
    }
    b.finish(TOKENIZER_DEF);
    true
}

fn parse_lex_rule(b: &mut TreeBuilder) -> bool {
    b.start(TOKEN_DEF);
    if !b.try_eat(IDENT) {
        b.rollback(TOKEN_DEF);
        return false
    }
    parse_string(b) && parse_string(b);
    b.finish(TOKEN_DEF);
    true
}

fn parse_syn_rule(b: &mut TreeBuilder) -> bool {
    b.start(RULE_DEF);
    if !b.try_eat(KW_RULE) {
        b.rollback(RULE_DEF);
        return false;
    }
    let r = b.try_eat(IDENT) && b.try_eat(LBRACE);
    if r {
        b.start(ALT);
        b.parse_many(&|b| {
            if b.next_is(RBRACE) || b.current().is_none() {
                false
            } else  {
                b.bump();
                true
            }
        });
        b.finish(ALT);
        b.try_eat(RBRACE);
    }
    b.finish(RULE_DEF);
    true
}

fn parse_string(b: &mut TreeBuilder) -> bool {
    b.start(STRING);
    if b.try_eat(SIMPLE_STRING) || b.try_eat(HASH_STRING) {
        b.finish(STRING);
        true
    } else {
        b.rollback(STRING);
        false
    }
}

fn parse_raw_string(s: &str) -> Option<usize> {
    let quote_start = s.find('"').unwrap();
    let closing = &"\"########################"[..quote_start];
    s[quote_start + 1..].find(closing).map(|i| i + quote_start + 1 + closing.len())
}

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

    fn match_ast(actual: &str, expected: &str) {
        let actual = actual.trim();
        let expected = expected.trim();
        if actual != expected {
            panic!("Actual:\n{}\nExpected:\n{}\n", actual, expected)
        }
    }

    fn ast(code: &str) -> String {
        parse(code.to_owned()).dump()
    }

    #[test]
    fn empty_file() {
        match_ast(&ast(""), r#"FILE """#)
    }

    #[test]
    fn nodes() {
        match_ast(&ast("nodes { foo bar }"), r#"
FILE
  NODES_DEF
    KW_NODES "nodes"
    LBRACE "{"
    IDENT "foo"
    IDENT "bar"
    RBRACE "}"
"#)
    }

    #[test]
    fn tokenizer() {
        match_ast(&ast(r#"nodes {} tokenizer { foo "foo" id r"\w+" ext "ext" "super::ext"}"#), r#"
FILE
  NODES_DEF
    KW_NODES "nodes"
    LBRACE "{"
    RBRACE "}"
  TOKENIZER_DEF
    KW_TOKENIZER "tokenizer"
    LBRACE "{"
    TOKEN_DEF
      IDENT "foo"
      STRING
        SIMPLE_STRING "\"foo\""
    TOKEN_DEF
      IDENT "id"
      STRING
        SIMPLE_STRING "r\"\\w+\""
    TOKEN_DEF
      IDENT "ext"
      STRING
        SIMPLE_STRING "\"ext\""
      STRING
        SIMPLE_STRING "\"super::ext\""
    RBRACE "}"
"#)
    }

    #[test]
    fn rules() {
        match_ast(&ast(r#"nodes {} tokenizer {}
rule f { foo <commit> ( bar )* }

rule b { foo | bar }"#), r#"
FILE
  NODES_DEF
    KW_NODES "nodes"
    LBRACE "{"
    RBRACE "}"
  TOKENIZER_DEF
    KW_TOKENIZER "tokenizer"
    LBRACE "{"
    RBRACE "}"
  RULE_DEF
    KW_RULE "rule"
    IDENT "f"
    LBRACE "{"
    ALT
      IDENT "foo"
      ERROR "<"
      IDENT "commit"
      ERROR ">"
      ERROR "("
      IDENT "bar"
      ERROR ")"
      START "*"
    RBRACE "}"
  RULE_DEF
    KW_RULE "rule"
    IDENT "b"
    LBRACE "{"
    ALT
      IDENT "foo"
      PIPE "|"
      IDENT "bar"
    RBRACE "}"
"#)
    }
}
<commit_msg>Nicer errors in tests<commit_after>pub mod grammar;

use fall_tree::File;
use fall_parse::{self, TreeBuilder};
use self::grammar::*;

pub fn parse(text: String) -> File {
    register_node_types();
    fall_parse::parse(
        text,
        grammar::FILE,
        grammar::TOKENIZER,
        &parse_file
    )
}

fn parse_file(b: &mut TreeBuilder) {
    parse_nodes(b);
    b.skip_until(&[KW_TOKENIZER]);
    parse_tokenizer(b);

    b.parse_many(&parse_syn_rule)
}

fn parse_nodes(b: &mut TreeBuilder) -> bool {
    b.start(NODES_DEF);
    if !b.try_eat(KW_NODES) {
        b.rollback(NODES_DEF);
        return false;
    }
    if b.try_eat(LBRACE) {
        b.parse_many(&|b| b.try_eat(IDENT));
        b.try_eat(RBRACE);
    }
    b.finish(NODES_DEF);
    true
}

fn parse_tokenizer(b: &mut TreeBuilder) -> bool {
    b.start(TOKENIZER_DEF);
    if !b.try_eat(KW_TOKENIZER) {
        b.rollback(TOKENIZER_DEF);
        return false;
    }
    if b.try_eat(LBRACE) {
        b.parse_many(&|b| {
            b.skip_until(&[RBRACE, IDENT]);
            parse_lex_rule(b)
        });
        b.try_eat(RBRACE);
    }
    b.finish(TOKENIZER_DEF);
    true
}

fn parse_lex_rule(b: &mut TreeBuilder) -> bool {
    b.start(TOKEN_DEF);
    if !b.try_eat(IDENT) {
        b.rollback(TOKEN_DEF);
        return false
    }
    parse_string(b) && parse_string(b);
    b.finish(TOKEN_DEF);
    true
}

fn parse_syn_rule(b: &mut TreeBuilder) -> bool {
    b.start(RULE_DEF);
    if !b.try_eat(KW_RULE) {
        b.rollback(RULE_DEF);
        return false;
    }
    let r = b.try_eat(IDENT) && b.try_eat(LBRACE);
    if r {
        b.start(ALT);
        b.parse_many(&|b| {
            if b.next_is(RBRACE) || b.current().is_none() {
                false
            } else  {
                b.bump();
                true
            }
        });
        b.finish(ALT);
        b.try_eat(RBRACE);
    }
    b.finish(RULE_DEF);
    true
}

fn parse_string(b: &mut TreeBuilder) -> bool {
    b.start(STRING);
    if b.try_eat(SIMPLE_STRING) || b.try_eat(HASH_STRING) {
        b.finish(STRING);
        true
    } else {
        b.rollback(STRING);
        false
    }
}

fn parse_raw_string(s: &str) -> Option<usize> {
    let quote_start = s.find('"').unwrap();
    let closing = &"\"########################"[..quote_start];
    s[quote_start + 1..].find(closing).map(|i| i + quote_start + 1 + closing.len())
}

#[cfg(test)]
mod tests {
    extern crate difference;
    use super::*;

    fn match_ast(actual: &str, expected: &str) {
        if expected.trim() != actual.trim() {
            difference::print_diff(&actual, &expected, "\n");
            panic!("Mismatch!")
        }
    }

    fn ast(code: &str) -> String {
        parse(code.to_owned()).dump()
    }

    #[test]
    fn empty_file() {
        match_ast(&ast(""), r#"FILE """#)
    }

    #[test]
    fn nodes() {
        match_ast(&ast("nodes { foo bar }"), r#"
FILE
  NODES_DEF
    KW_NODES "nodes"
    LBRACE "{"
    IDENT "foo"
    IDENT "bar"
    RBRACE "}"
"#)
    }

    #[test]
    fn tokenizer() {
        match_ast(&ast(r#"nodes {} tokenizer { foo "foo" id r"\w+" ext "ext" "super::ext"}"#), r#"
FILE
  NODES_DEF
    KW_NODES "nodes"
    LBRACE "{"
    RBRACE "}"
  TOKENIZER_DEF
    KW_TOKENIZER "tokenizer"
    LBRACE "{"
    TOKEN_DEF
      IDENT "foo"
      STRING
        SIMPLE_STRING "\"foo\""
    TOKEN_DEF
      IDENT "id"
      STRING
        SIMPLE_STRING "r\"\\w+\""
    TOKEN_DEF
      IDENT "ext"
      STRING
        SIMPLE_STRING "\"ext\""
      STRING
        SIMPLE_STRING "\"super::ext\""
    RBRACE "}"
"#)
    }

    #[test]
    fn rules() {
        match_ast(&ast(r#"nodes {} tokenizer {}
rule f { foo <commit> ( bar )* }

rule b { foo | bar }"#), r#"
FILE
  NODES_DEF
    KW_NODES "nodes"
    LBRACE "{"
    RBRACE "}"
  TOKENIZER_DEF
    KW_TOKENIZER "tokenizer"
    LBRACE "{"
    RBRACE "}"
  RULE_DEF
    KW_RULE "rule"
    IDENT "f"
    LBRACE "{"
    ALT
      IDENT "foo"
      ERROR "<"
      IDENT "commit"
      ERROR ">"
      ERROR "("
      IDENT "bar"
      ERROR ")"
      START "*"
    RBRACE "}"
  RULE_DEF
    KW_RULE "rule"
    IDENT "b"
    LBRACE "{"
    ALT
      IDENT "foo"
      PIPE "|"
      IDENT "bar"
    RBRACE "}"
"#)
    }
}
<|endoftext|>


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

/*================================================================================================*/
/*------STRUCTS-----------------------------------------------------------------------------------*/
/*================================================================================================*/

/// The app
///
/// This is the main control center of ionCore.
/// It is in charge of initialization, updating, and shutdown of all modules,
/// as well as the handing of any inter-module communication.
#[derive (Clone)]
pub struct App{

    // Public
    /// The name of the application
    pub name : String
}
<commit_msg>Changed app name to &str<commit_after>/*================================================================================================*/
// Copyright 2016 Kyle Finlay
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/*================================================================================================*/

/*================================================================================================*/
/*------STRUCTS-----------------------------------------------------------------------------------*/
/*================================================================================================*/

/// The app
///
/// This is the main control center of ionCore.
/// It is in charge of initialization, updating, and shutdown of all modules,
/// as well as the handing of any inter-module communication.
#[derive (Clone)]
pub struct App <'a> {

    // Public
    /// The name of the application
    pub name : &'a str
}
<|endoftext|>


<commit_before>mod client;

mod network;

#[cfg(test)]
mod tests {
    #[test]
    fn it_works() {
    }
}
<commit_msg>Add public modifier to client module<commit_after>pub mod client;

mod network;

#[cfg(test)]
mod tests {
    #[test]
    fn it_works() {
    }
}
<|endoftext|>


<commit_before>use bson::Bson;
use bson::Document;
use bson::Bson::{FloatingPoint, I32};
use mongodb::client::wire_protocol::flags::{OpInsertFlags, OpQueryFlags,
                                            OpUpdateFlags};
use mongodb::client::wire_protocol::operations::Message;
use std::io::Write;
use std::net::TcpStream;

// #[test]
fn insert_single_key_doc() {
    match TcpStream::connect("localhost:27017") {
        Ok(mut stream) => {
            let mut doc = Document::new();
            doc.insert("foo".to_owned(), FloatingPoint(42.0));
            let docs = vec![doc];
            let flags = OpInsertFlags::no_flags();
            let name = "test.test".to_owned();
            let res = Message::with_insert(1, flags, name, docs);

            let cm = match res {
                Ok(message) => message,
                Err(_) => panic!("Could not create message!")
            };

            match cm.write(&mut stream) {
                Ok(_) => (),
                Err(s) => panic!("{}", s)
            };

            let doc = Document::new();
            let flags = OpQueryFlags::no_flags();
            let name = "test.test".to_owned();
            let res = Message::with_query(1, flags, name, 0, 0, doc, None);

            let cm = match res {
                Ok(message) => message,
                Err(s) => panic!("{}", s)
            };

            match cm.write(&mut stream) {
                Ok(_) => (),
                Err(s) => panic!("{}", s)
            };

            let reply = match Message::read(&mut stream) {
                Ok(m) => m,
                Err(s) => panic!("{}", s)
            };

            let docs = match reply {
                Message::OpReply { header: _, flags: _, cursor_id:_,
                                   starting_from: _, number_returned: _,
                                   documents: d } => d,
                _ => panic!("Invalid response read from server")
            };

            assert_eq!(docs.len() as i32, 1);

            match docs[0].get("foo") {
                Some(&FloatingPoint(42.0)) => (),
                _ => panic!("Wrong value returned!")
            };
        },
        Err(_) => {
            panic!("Could not connect to server")
        }
    }
}

// #[test]
fn insert_multi_key_doc() {
    match TcpStream::connect("localhost:27017") {
        Ok(mut stream) => {
            let mut doc = Document::new();
            doc.insert("foo".to_owned(), FloatingPoint(42.0));
            doc.insert("bar".to_owned(), Bson::String("__z&".to_owned()));
            let docs = vec![doc];
            let flags = OpInsertFlags::no_flags();
            let name = "test.test".to_owned();
            let res = Message::with_insert(1, flags, name, docs);

            let cm = match res {
                Ok(message) => message,
                Err(s) => panic!("{}", s)
            };

            match cm.write(&mut stream) {
                Ok(_) => (),
                Err(s) => panic!("{}", s)
            };

            let doc = Document::new();
            let flags = OpQueryFlags::no_flags();
            let name = "test.test".to_owned();
            let res = Message::with_query(1, flags, name, 0, 0, doc, None);

            let cm = match res {
                Ok(message) => message,
                Err(s) => panic!("{}", s)
            };

            match cm.write(&mut stream) {
                Ok(_) => (),
                Err(s) => panic!("{}", s)
            };

            let reply = match Message::read(&mut stream) {
                Ok(m) => m,
                Err(s) => panic!("{}", s)
            };

            let docs = match reply {
                Message::OpReply { header: _, flags: _, cursor_id:_,
                                   starting_from: _, number_returned: _,
                                   documents: d } => d,
                _ => panic!("Invalid response read from server")
            };

            assert_eq!(docs.len() as i32, 1);

            match docs[0].get("foo") {
                Some(&FloatingPoint(42.0)) => (),
                _ => panic!("Wrong value returned!")
            };

            match docs[0].get("bar") {
                Some(&Bson::String(ref s)) => assert_eq!(s, "__z&"),
                _ => panic!("Wrong value returned!")
            };
        },
        Err(_) => {
            panic!("Could not connect to server")
        }
    }
}

#[test]
fn insert_docs() {
    match TcpStream::connect("localhost:27017") {
        Ok(mut stream) => {
            let mut doc1 = Document::new();
            doc1.insert("foo".to_owned(), FloatingPoint(42.0));
            doc1.insert("bar".to_owned(), Bson::String("__z&".to_owned()));

            let mut doc2 = Document::new();
            doc2.insert("booyah".to_owned(), I32(23));

            let docs = vec![doc1, doc2];
            let flags = OpInsertFlags::no_flags();
            let name = "test.test".to_owned();
            let res = Message::with_insert(1, flags, name, docs);

            let cm = match res {
                Ok(message) => message,
                Err(s) => panic!("{}", s)
            };

            match cm.write(&mut stream) {
                Ok(_) => (),
                Err(s) => panic!("{}", s)
            };

            let doc = Document::new();
            let flags = OpQueryFlags::no_flags();
            let name = "test.test".to_owned();
            let res = Message::with_query(1, flags, name, 0, 0, doc, None);

            let cm = match res {
                Ok(message) => message,
                Err(s) => panic!("{}", s)
            };

            match cm.write(&mut stream) {
                Ok(_) => (),
                Err(s) => panic!("{}", s)
            };

            let reply = match Message::read(&mut stream) {
                Ok(m) => m,
                Err(s) => panic!("{}", s)
            };

            let docs = match reply {
                Message::OpReply { header: _, flags: _, cursor_id:_,
                                   starting_from: _, number_returned: _,
                                   documents: d } => d,
                _ => panic!("Invalid response read from server")
            };

            assert_eq!(docs.len() as i32, 2);

            match docs[0].get("foo") {
                Some(&FloatingPoint(42.0)) => (),
                _ => panic!("Wrong value returned!")
            };

            match docs[0].get("bar") {
                Some(&Bson::String(ref s)) => assert_eq!(s, "__z&"),
                _ => panic!("Wrong value returned!")
            };

            match docs[1].get("booyah") {
                Some(&I32(23)) => (),
                _ => panic!("Wrong value returned!")
            };
        },
        Err(_) => {
            panic!("Could not connect to server")
        }
    }
}

#[test]
fn insert_update_then_query() {
    match TcpStream::connect("localhost:27017") {
        Ok(mut stream) => {
            let mut doc = Document::new();
            doc.insert("foo".to_owned(), FloatingPoint(42.0));
            let docs = vec![doc];
            let flags = OpInsertFlags::no_flags();
            let name = "test.test".to_owned();
            let res = Message::with_insert(1, flags, name, docs);

            let cm = match res {
                Ok(message) => message,
                Err(_) => panic!("Could not create insert message!")
            };

            match cm.write(&mut stream) {
                Ok(_) => (),
                Err(s) => panic!("{}", s)
            };

            let selector = Document::new();
            let mut update = Document::new();
            update.insert("foo".to_owned(), Bson::String("bar".to_owned()));
            let flags = OpUpdateFlags::no_flags();
            let name = "test.test".to_owned();
            let res = Message::with_update(2, name, flags, selector, update);

            let cm = match res {
                Ok(message) => message,
                Err(_) => panic!("Could not create update message!")
            };

            match cm.write(&mut stream) {
                Ok(_) => (),
                Err(s) => panic!("{}", s)
            };

            let doc = Document::new();
            let flags = OpQueryFlags::no_flags();
            let name = "test.test".to_owned();
            let res = Message::with_query(3, flags, name, 0, 0, doc, None);

            let cm = match res {
                Ok(message) => message,
                Err(_) => panic!("Could not create query message!")
            };

            match cm.write(&mut stream) {
                Ok(_) => (),
                Err(s) => panic!("{}", s)
            };

            let reply = match Message::read(&mut stream) {
                Ok(m) => m,
                Err(s) => panic!("Could not read response: {}", s)
            };

            let docs = match reply {
                Message::OpReply { header: _, flags: _, cursor_id:_,
                                   starting_from: _, number_returned: _,
                                   documents: d } => d,
                _ => panic!("Invalid response read from server")
            };

            assert_eq!(docs.len() as i32, 1);

            match docs[0].get("foo") {
                Some(&Bson::String(ref s)) => assert_eq!(s, "bar"),
                _ => panic!("Wrong value returned!")
            };
        },
        Err(_) => {
            panic!("Could not connect to server")
        }
    }
}
<commit_msg>changed test collection names<commit_after>use bson::Bson;
use bson::Document;
use bson::Bson::{FloatingPoint, I32};
use mongodb::client::wire_protocol::flags::{OpInsertFlags, OpQueryFlags,
                                            OpUpdateFlags};
use mongodb::client::wire_protocol::operations::Message;
use std::io::Write;
use std::net::TcpStream;

#[test]
fn insert_single_key_doc() {
    match TcpStream::connect("localhost:27017") {
        Ok(mut stream) => {
            let mut doc = Document::new();
            doc.insert("foo".to_owned(), FloatingPoint(42.0));
            let docs = vec![doc];
            let flags = OpInsertFlags::no_flags();
            let name = "test.single_key".to_owned();
            let res = Message::with_insert(1, flags, name, docs);

            let cm = match res {
                Ok(message) => message,
                Err(_) => panic!("Could not create message!")
            };

            match cm.write(&mut stream) {
                Ok(_) => (),
                Err(s) => panic!("{}", s)
            };

            let doc = Document::new();
            let flags = OpQueryFlags::no_flags();
            let name = "test.single_key".to_owned();
            let res = Message::with_query(1, flags, name, 0, 0, doc, None);

            let cm = match res {
                Ok(message) => message,
                Err(s) => panic!("{}", s)
            };

            match cm.write(&mut stream) {
                Ok(_) => (),
                Err(s) => panic!("{}", s)
            };

            let reply = match Message::read(&mut stream) {
                Ok(m) => m,
                Err(s) => panic!("{}", s)
            };

            let docs = match reply {
                Message::OpReply { header: _, flags: _, cursor_id:_,
                                   starting_from: _, number_returned: _,
                                   documents: d } => d,
                _ => panic!("Invalid response read from server")
            };

            assert_eq!(docs.len() as i32, 1);

            match docs[0].get("foo") {
                Some(&FloatingPoint(42.0)) => (),
                _ => panic!("Wrong value returned!")
            };
        },
        Err(_) => {
            panic!("Could not connect to server")
        }
    }
}

#[test]
fn insert_multi_key_doc() {
    match TcpStream::connect("localhost:27017") {
        Ok(mut stream) => {
            let mut doc = Document::new();
            doc.insert("foo".to_owned(), FloatingPoint(42.0));
            doc.insert("bar".to_owned(), Bson::String("__z&".to_owned()));
            let docs = vec![doc];
            let flags = OpInsertFlags::no_flags();
            let name = "test.multi_key".to_owned();
            let res = Message::with_insert(1, flags, name, docs);

            let cm = match res {
                Ok(message) => message,
                Err(s) => panic!("{}", s)
            };

            match cm.write(&mut stream) {
                Ok(_) => (),
                Err(s) => panic!("{}", s)
            };

            let doc = Document::new();
            let flags = OpQueryFlags::no_flags();
            let name = "test.multi_key".to_owned();
            let res = Message::with_query(1, flags, name, 0, 0, doc, None);

            let cm = match res {
                Ok(message) => message,
                Err(s) => panic!("{}", s)
            };

            match cm.write(&mut stream) {
                Ok(_) => (),
                Err(s) => panic!("{}", s)
            };

            let reply = match Message::read(&mut stream) {
                Ok(m) => m,
                Err(s) => panic!("{}", s)
            };

            let docs = match reply {
                Message::OpReply { header: _, flags: _, cursor_id:_,
                                   starting_from: _, number_returned: _,
                                   documents: d } => d,
                _ => panic!("Invalid response read from server")
            };

            assert_eq!(docs.len() as i32, 1);

            match docs[0].get("foo") {
                Some(&FloatingPoint(42.0)) => (),
                _ => panic!("Wrong value returned!")
            };

            match docs[0].get("bar") {
                Some(&Bson::String(ref s)) => assert_eq!(s, "__z&"),
                _ => panic!("Wrong value returned!")
            };
        },
        Err(_) => {
            panic!("Could not connect to server")
        }
    }
}

#[test]
fn insert_docs() {
    match TcpStream::connect("localhost:27017") {
        Ok(mut stream) => {
            let mut doc1 = Document::new();
            doc1.insert("foo".to_owned(), FloatingPoint(42.0));
            doc1.insert("bar".to_owned(), Bson::String("__z&".to_owned()));

            let mut doc2 = Document::new();
            doc2.insert("booyah".to_owned(), I32(23));

            let docs = vec![doc1, doc2];
            let flags = OpInsertFlags::no_flags();
            let name = "test.multi_doc".to_owned();
            let res = Message::with_insert(1, flags, name, docs);

            let cm = match res {
                Ok(message) => message,
                Err(s) => panic!("{}", s)
            };

            match cm.write(&mut stream) {
                Ok(_) => (),
                Err(s) => panic!("{}", s)
            };

            let doc = Document::new();
            let flags = OpQueryFlags::no_flags();
            let name = "test.multi_doc".to_owned();
            let res = Message::with_query(1, flags, name, 0, 0, doc, None);

            let cm = match res {
                Ok(message) => message,
                Err(s) => panic!("{}", s)
            };

            match cm.write(&mut stream) {
                Ok(_) => (),
                Err(s) => panic!("{}", s)
            };

            let reply = match Message::read(&mut stream) {
                Ok(m) => m,
                Err(s) => panic!("{}", s)
            };

            let docs = match reply {
                Message::OpReply { header: _, flags: _, cursor_id:_,
                                   starting_from: _, number_returned: _,
                                   documents: d } => d,
                _ => panic!("Invalid response read from server")
            };

            assert_eq!(docs.len() as i32, 2);

            match docs[0].get("foo") {
                Some(&FloatingPoint(42.0)) => (),
                _ => panic!("Wrong value returned!")
            };

            match docs[0].get("bar") {
                Some(&Bson::String(ref s)) => assert_eq!(s, "__z&"),
                _ => panic!("Wrong value returned!")
            };

            match docs[1].get("booyah") {
                Some(&I32(23)) => (),
                _ => panic!("Wrong value returned!")
            };
        },
        Err(_) => {
            panic!("Could not connect to server")
        }
    }
}

#[test]
fn insert_update_then_query() {
    match TcpStream::connect("localhost:27017") {
        Ok(mut stream) => {
            let mut doc = Document::new();
            doc.insert("foo".to_owned(), FloatingPoint(42.0));
            let docs = vec![doc];
            let flags = OpInsertFlags::no_flags();
            let name = "test.update".to_owned();
            let res = Message::with_insert(1, flags, name, docs);

            let cm = match res {
                Ok(message) => message,
                Err(_) => panic!("Could not create insert message!")
            };

            match cm.write(&mut stream) {
                Ok(_) => (),
                Err(s) => panic!("{}", s)
            };

            let selector = Document::new();
            let mut update = Document::new();
            update.insert("foo".to_owned(), Bson::String("bar".to_owned()));
            let flags = OpUpdateFlags::no_flags();
            let name = "test.update".to_owned();
            let res = Message::with_update(2, name, flags, selector, update);

            let cm = match res {
                Ok(message) => message,
                Err(_) => panic!("Could not create update message!")
            };

            match cm.write(&mut stream) {
                Ok(_) => (),
                Err(s) => panic!("{}", s)
            };

            let doc = Document::new();
            let flags = OpQueryFlags::no_flags();
            let name = "test.update".to_owned();
            let res = Message::with_query(3, flags, name, 0, 0, doc, None);

            let cm = match res {
                Ok(message) => message,
                Err(_) => panic!("Could not create query message!")
            };

            match cm.write(&mut stream) {
                Ok(_) => (),
                Err(s) => panic!("{}", s)
            };

            let reply = match Message::read(&mut stream) {
                Ok(m) => m,
                Err(s) => panic!("Could not read response: {}", s)
            };

            let docs = match reply {
                Message::OpReply { header: _, flags: _, cursor_id:_,
                                   starting_from: _, number_returned: _,
                                   documents: d } => d,
                _ => panic!("Invalid response read from server")
            };

            assert_eq!(docs.len() as i32, 1);

            match docs[0].get("foo") {
                Some(&Bson::String(ref s)) => assert_eq!(s, "bar"),
                _ => panic!("Wrong value returned!")
            };
        },
        Err(_) => {
            panic!("Could not connect to server")
        }
    }
}
<|endoftext|>