<commit_before>#![feature(rustc_private)]
extern crate miri;
extern crate getopts;
extern crate rustc;
extern crate rustc_metadata;
extern crate rustc_driver;
extern crate rustc_errors;
extern crate rustc_codegen_utils;
extern crate rustc_interface;
extern crate syntax;

use std::path::Path;
use std::io::Write;
use std::sync::{Mutex, Arc};
use std::io;

use rustc_interface::interface;
use rustc::hir::{self, itemlikevisit};
use rustc::ty::TyCtxt;
use rustc::hir::def_id::LOCAL_CRATE;

use miri::MiriConfig;

struct MiriCompilerCalls {
    /// whether we are building for the host
    host_target: bool,
}

impl rustc_driver::Callbacks for MiriCompilerCalls {
    fn after_parsing(&mut self, compiler: &interface::Compiler) -> bool {
        let attr = (
            syntax::symbol::Symbol::intern("miri"),
            syntax::feature_gate::AttributeType::Whitelisted,
        );
        compiler.session().plugin_attributes.borrow_mut().push(attr);

        // Continue execution
        true
    }

    fn after_analysis(&mut self, compiler: &interface::Compiler) -> bool {
        compiler.session().abort_if_errors();
        compiler.global_ctxt().unwrap().peek_mut().enter(|tcx| {
            if std::env::args().any(|arg| arg == "--test") {
                struct Visitor<'tcx>(TyCtxt<'tcx>);
                impl<'tcx, 'hir> itemlikevisit::ItemLikeVisitor<'hir> for Visitor<'tcx> {
                    fn visit_item(&mut self, i: &'hir hir::Item) {
                        if let hir::ItemKind::Fn(.., body_id) = i.node {
                            if i.attrs.iter().any(|attr| attr.check_name(syntax::symbol::sym::test)) {
                                let config = MiriConfig { validate: true, args: vec![], seed: None };
                                let did = self.0.hir().body_owner_def_id(body_id);
                                println!("running test: {}", self.0.def_path_debug_str(did));
                                miri::eval_main(self.0, did, config);
                                self.0.sess.abort_if_errors();
                            }
                        }
                    }
                    fn visit_trait_item(&mut self, _trait_item: &'hir hir::TraitItem) {}
                    fn visit_impl_item(&mut self, _impl_item: &'hir hir::ImplItem) {}
                }
                tcx.hir().krate().visit_all_item_likes(&mut Visitor(tcx));
            } else if let Some((entry_def_id, _)) = tcx.entry_fn(LOCAL_CRATE) {
                let config = MiriConfig { validate: true, args: vec![], seed: None };
                miri::eval_main(tcx, entry_def_id, config);

                compiler.session().abort_if_errors();
            } else {
                println!("no main function found, assuming auxiliary build");
            }
        });

        // Continue execution on host target
        self.host_target
    }
}

fn main() {
    let path = option_env!("MIRI_RUSTC_TEST")
        .map(String::from)
        .unwrap_or_else(|| {
            std::env::var("MIRI_RUSTC_TEST")
                .expect("need to set MIRI_RUSTC_TEST to path of rustc tests")
        });

    let mut mir_not_found = Vec::new();
    let mut crate_not_found = Vec::new();
    let mut success = 0;
    let mut failed = Vec::new();
    let mut c_abi_fns = Vec::new();
    let mut abi = Vec::new();
    let mut unsupported = Vec::new();
    let mut unimplemented_intrinsic = Vec::new();
    let mut limits = Vec::new();
    let mut files: Vec<_> = std::fs::read_dir(path).unwrap().collect();
    while let Some(file) = files.pop() {
        let file = file.unwrap();
        let path = file.path();
        if file.metadata().unwrap().is_dir() {
            if !path.to_str().unwrap().ends_with("auxiliary") {
                // add subdirs recursively
                files.extend(std::fs::read_dir(path).unwrap());
            }
            continue;
        }
        if !file.metadata().unwrap().is_file() || !path.to_str().unwrap().ends_with(".rs") {
            continue;
        }
        let stderr = std::io::stderr();
        write!(stderr.lock(), "test [miri-pass] {} ... ", path.display()).unwrap();
        let mut host_target = false;
        let mut args: Vec<String> = std::env::args().filter(|arg| {
            if arg == "--miri_host_target" {
                host_target = true;
                false // remove the flag, rustc doesn't know it
            } else {
                true
            }
        }).collect();
        args.splice(1..1, miri::miri_default_args().iter().map(ToString::to_string));
        // file to process
        args.push(path.display().to_string());

        let sysroot_flag = String::from("--sysroot");
        if !args.contains(&sysroot_flag) {
            args.push(sysroot_flag);
            args.push(Path::new(&std::env::var("HOME").unwrap()).join(".xargo").join("HOST").display().to_string());
        }

        // A threadsafe buffer for writing.
        #[derive(Default, Clone)]
        struct BufWriter(Arc<Mutex<Vec<u8>>>);

        impl Write for BufWriter {
            fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
                self.0.lock().unwrap().write(buf)
            }
            fn flush(&mut self) -> io::Result<()> {
                self.0.lock().unwrap().flush()
            }
        }
        let buf = BufWriter::default();
        let output = buf.clone();
        let result = std::panic::catch_unwind(|| {
            let _ = rustc_driver::run_compiler(&args, &mut MiriCompilerCalls { host_target }, None, Some(Box::new(buf)));
        });

        match result {
            Ok(()) => {
                success += 1;
                writeln!(stderr.lock(), "ok").unwrap()
            },
            Err(_) => {
                let output = output.0.lock().unwrap();
                let output_err = std::str::from_utf8(&output).unwrap();
                if let Some(text) = output_err.splitn(2, "no mir for `").nth(1) {
                    let end = text.find('`').unwrap();
                    mir_not_found.push(text[..end].to_string());
                    writeln!(stderr.lock(), "NO MIR FOR `{}`", &text[..end]).unwrap();
                } else if let Some(text) = output_err.splitn(2, "can't find crate for `").nth(1) {
                    let end = text.find('`').unwrap();
                    crate_not_found.push(text[..end].to_string());
                    writeln!(stderr.lock(), "CAN'T FIND CRATE FOR `{}`", &text[..end]).unwrap();
                } else {
                    for text in output_err.split("error: ").skip(1) {
                        let end = text.find('\n').unwrap_or(text.len());
                        let c_abi = "can't call C ABI function: ";
                        let unimplemented_intrinsic_s = "unimplemented intrinsic: ";
                        let unsupported_s = "miri does not support ";
                        let abi_s = "can't handle function with ";
                        let limit_s = "reached the configured maximum ";
                        if text.starts_with(c_abi) {
                            c_abi_fns.push(text[c_abi.len()..end].to_string());
                        } else if text.starts_with(unimplemented_intrinsic_s) {
                            unimplemented_intrinsic.push(text[unimplemented_intrinsic_s.len()..end].to_string());
                        } else if text.starts_with(unsupported_s) {
                            unsupported.push(text[unsupported_s.len()..end].to_string());
                        } else if text.starts_with(abi_s) {
                            abi.push(text[abi_s.len()..end].to_string());
                        } else if text.starts_with(limit_s) {
                            limits.push(text[limit_s.len()..end].to_string());
                        } else if text.find("aborting").is_none() {
                            failed.push(text[..end].to_string());
                        }
                    }
                    writeln!(stderr.lock(), "stderr: \n {}", output_err).unwrap();
                }
            }
        }
    }
    let stderr = std::io::stderr();
    let mut stderr = stderr.lock();
    writeln!(stderr, "{} success, {} no mir, {} crate not found, {} failed, \
                        {} C fn, {} ABI, {} unsupported, {} intrinsic",
                        success, mir_not_found.len(), crate_not_found.len(), failed.len(),
                        c_abi_fns.len(), abi.len(), unsupported.len(), unimplemented_intrinsic.len()).unwrap();
    writeln!(stderr, "# The \"other reasons\" errors").unwrap();
    writeln!(stderr, "(sorted, deduplicated)").unwrap();
    print_vec(&mut stderr, failed);

    writeln!(stderr, "# can't call C ABI function").unwrap();
    print_vec(&mut stderr, c_abi_fns);

    writeln!(stderr, "# unsupported ABI").unwrap();
    print_vec(&mut stderr, abi);

    writeln!(stderr, "# unsupported").unwrap();
    print_vec(&mut stderr, unsupported);

    writeln!(stderr, "# unimplemented intrinsics").unwrap();
    print_vec(&mut stderr, unimplemented_intrinsic);

    writeln!(stderr, "# mir not found").unwrap();
    print_vec(&mut stderr, mir_not_found);

    writeln!(stderr, "# crate not found").unwrap();
    print_vec(&mut stderr, crate_not_found);
}

fn print_vec<W: std::io::Write>(stderr: &mut W, v: Vec<String>) {
    writeln!(stderr, "```").unwrap();
    for (n, s) in vec_to_hist(v).into_iter().rev() {
        writeln!(stderr, "{:4} {}", n, s).unwrap();
    }
    writeln!(stderr, "```").unwrap();
}

fn vec_to_hist<T: PartialEq + Ord>(mut v: Vec<T>) -> Vec<(usize, T)> {
    v.sort();
    let mut v = v.into_iter();
    let mut result = Vec::new();
    let mut current = v.next();
    'outer: while let Some(current_val) = current {
        let mut n = 1;
        for next in &mut v {
            if next == current_val {
                n += 1;
            } else {
                result.push((n, current_val));
                current = Some(next);
                continue 'outer;
            }
        }
        result.push((n, current_val));
        break;
    }
    result.sort();
    result
}
<commit_msg>fix miri-rustc-tests<commit_after>#![feature(rustc_private)]
extern crate miri;
extern crate getopts;
extern crate rustc;
extern crate rustc_metadata;
extern crate rustc_driver;
extern crate rustc_errors;
extern crate rustc_codegen_utils;
extern crate rustc_interface;
extern crate syntax;

use std::path::Path;
use std::io::Write;
use std::sync::{Mutex, Arc};
use std::io;

use rustc_interface::interface;
use rustc::hir::{self, itemlikevisit};
use rustc::ty::TyCtxt;
use rustc::hir::def_id::LOCAL_CRATE;
use rustc_driver::Compilation;

use miri::MiriConfig;

struct MiriCompilerCalls {
    /// whether we are building for the host
    host_target: bool,
}

impl rustc_driver::Callbacks for MiriCompilerCalls {
    fn after_parsing(&mut self, compiler: &interface::Compiler) -> Compilation {
        let attr = (
            syntax::symbol::Symbol::intern("miri"),
            syntax::feature_gate::AttributeType::Whitelisted,
        );
        compiler.session().plugin_attributes.borrow_mut().push(attr);

        Compilation::Continue
    }

    fn after_analysis(&mut self, compiler: &interface::Compiler) -> Compilation {
        compiler.session().abort_if_errors();
        compiler.global_ctxt().unwrap().peek_mut().enter(|tcx| {
            if std::env::args().any(|arg| arg == "--test") {
                struct Visitor<'tcx>(TyCtxt<'tcx>);
                impl<'tcx, 'hir> itemlikevisit::ItemLikeVisitor<'hir> for Visitor<'tcx> {
                    fn visit_item(&mut self, i: &'hir hir::Item) {
                        if let hir::ItemKind::Fn(.., body_id) = i.node {
                            if i.attrs.iter().any(|attr| attr.check_name(syntax::symbol::sym::test)) {
                                let config = MiriConfig { validate: true, args: vec![], seed: None };
                                let did = self.0.hir().body_owner_def_id(body_id);
                                println!("running test: {}", self.0.def_path_debug_str(did));
                                miri::eval_main(self.0, did, config);
                                self.0.sess.abort_if_errors();
                            }
                        }
                    }
                    fn visit_trait_item(&mut self, _trait_item: &'hir hir::TraitItem) {}
                    fn visit_impl_item(&mut self, _impl_item: &'hir hir::ImplItem) {}
                }
                tcx.hir().krate().visit_all_item_likes(&mut Visitor(tcx));
            } else if let Some((entry_def_id, _)) = tcx.entry_fn(LOCAL_CRATE) {
                let config = MiriConfig { validate: true, args: vec![], seed: None };
                miri::eval_main(tcx, entry_def_id, config);

                compiler.session().abort_if_errors();
            } else {
                println!("no main function found, assuming auxiliary build");
            }
        });

        // Continue execution on host target
        if self.host_target { Compilation::Continue } else { Compilation::Stop }
    }
}

fn main() {
    let path = option_env!("MIRI_RUSTC_TEST")
        .map(String::from)
        .unwrap_or_else(|| {
            std::env::var("MIRI_RUSTC_TEST")
                .expect("need to set MIRI_RUSTC_TEST to path of rustc tests")
        });

    let mut mir_not_found = Vec::new();
    let mut crate_not_found = Vec::new();
    let mut success = 0;
    let mut failed = Vec::new();
    let mut c_abi_fns = Vec::new();
    let mut abi = Vec::new();
    let mut unsupported = Vec::new();
    let mut unimplemented_intrinsic = Vec::new();
    let mut limits = Vec::new();
    let mut files: Vec<_> = std::fs::read_dir(path).unwrap().collect();
    while let Some(file) = files.pop() {
        let file = file.unwrap();
        let path = file.path();
        if file.metadata().unwrap().is_dir() {
            if !path.to_str().unwrap().ends_with("auxiliary") {
                // add subdirs recursively
                files.extend(std::fs::read_dir(path).unwrap());
            }
            continue;
        }
        if !file.metadata().unwrap().is_file() || !path.to_str().unwrap().ends_with(".rs") {
            continue;
        }
        let stderr = std::io::stderr();
        write!(stderr.lock(), "test [miri-pass] {} ... ", path.display()).unwrap();
        let mut host_target = false;
        let mut args: Vec<String> = std::env::args().filter(|arg| {
            if arg == "--miri_host_target" {
                host_target = true;
                false // remove the flag, rustc doesn't know it
            } else {
                true
            }
        }).collect();
        args.splice(1..1, miri::miri_default_args().iter().map(ToString::to_string));
        // file to process
        args.push(path.display().to_string());

        let sysroot_flag = String::from("--sysroot");
        if !args.contains(&sysroot_flag) {
            args.push(sysroot_flag);
            args.push(Path::new(&std::env::var("HOME").unwrap()).join(".xargo").join("HOST").display().to_string());
        }

        // A threadsafe buffer for writing.
        #[derive(Default, Clone)]
        struct BufWriter(Arc<Mutex<Vec<u8>>>);

        impl Write for BufWriter {
            fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
                self.0.lock().unwrap().write(buf)
            }
            fn flush(&mut self) -> io::Result<()> {
                self.0.lock().unwrap().flush()
            }
        }
        let buf = BufWriter::default();
        let output = buf.clone();
        let result = std::panic::catch_unwind(|| {
            let _ = rustc_driver::run_compiler(&args, &mut MiriCompilerCalls { host_target }, None, Some(Box::new(buf)));
        });

        match result {
            Ok(()) => {
                success += 1;
                writeln!(stderr.lock(), "ok").unwrap()
            },
            Err(_) => {
                let output = output.0.lock().unwrap();
                let output_err = std::str::from_utf8(&output).unwrap();
                if let Some(text) = output_err.splitn(2, "no mir for `").nth(1) {
                    let end = text.find('`').unwrap();
                    mir_not_found.push(text[..end].to_string());
                    writeln!(stderr.lock(), "NO MIR FOR `{}`", &text[..end]).unwrap();
                } else if let Some(text) = output_err.splitn(2, "can't find crate for `").nth(1) {
                    let end = text.find('`').unwrap();
                    crate_not_found.push(text[..end].to_string());
                    writeln!(stderr.lock(), "CAN'T FIND CRATE FOR `{}`", &text[..end]).unwrap();
                } else {
                    for text in output_err.split("error: ").skip(1) {
                        let end = text.find('\n').unwrap_or(text.len());
                        let c_abi = "can't call C ABI function: ";
                        let unimplemented_intrinsic_s = "unimplemented intrinsic: ";
                        let unsupported_s = "miri does not support ";
                        let abi_s = "can't handle function with ";
                        let limit_s = "reached the configured maximum ";
                        if text.starts_with(c_abi) {
                            c_abi_fns.push(text[c_abi.len()..end].to_string());
                        } else if text.starts_with(unimplemented_intrinsic_s) {
                            unimplemented_intrinsic.push(text[unimplemented_intrinsic_s.len()..end].to_string());
                        } else if text.starts_with(unsupported_s) {
                            unsupported.push(text[unsupported_s.len()..end].to_string());
                        } else if text.starts_with(abi_s) {
                            abi.push(text[abi_s.len()..end].to_string());
                        } else if text.starts_with(limit_s) {
                            limits.push(text[limit_s.len()..end].to_string());
                        } else if text.find("aborting").is_none() {
                            failed.push(text[..end].to_string());
                        }
                    }
                    writeln!(stderr.lock(), "stderr: \n {}", output_err).unwrap();
                }
            }
        }
    }
    let stderr = std::io::stderr();
    let mut stderr = stderr.lock();
    writeln!(stderr, "{} success, {} no mir, {} crate not found, {} failed, \
                        {} C fn, {} ABI, {} unsupported, {} intrinsic",
                        success, mir_not_found.len(), crate_not_found.len(), failed.len(),
                        c_abi_fns.len(), abi.len(), unsupported.len(), unimplemented_intrinsic.len()).unwrap();
    writeln!(stderr, "# The \"other reasons\" errors").unwrap();
    writeln!(stderr, "(sorted, deduplicated)").unwrap();
    print_vec(&mut stderr, failed);

    writeln!(stderr, "# can't call C ABI function").unwrap();
    print_vec(&mut stderr, c_abi_fns);

    writeln!(stderr, "# unsupported ABI").unwrap();
    print_vec(&mut stderr, abi);

    writeln!(stderr, "# unsupported").unwrap();
    print_vec(&mut stderr, unsupported);

    writeln!(stderr, "# unimplemented intrinsics").unwrap();
    print_vec(&mut stderr, unimplemented_intrinsic);

    writeln!(stderr, "# mir not found").unwrap();
    print_vec(&mut stderr, mir_not_found);

    writeln!(stderr, "# crate not found").unwrap();
    print_vec(&mut stderr, crate_not_found);
}

fn print_vec<W: std::io::Write>(stderr: &mut W, v: Vec<String>) {
    writeln!(stderr, "```").unwrap();
    for (n, s) in vec_to_hist(v).into_iter().rev() {
        writeln!(stderr, "{:4} {}", n, s).unwrap();
    }
    writeln!(stderr, "```").unwrap();
}

fn vec_to_hist<T: PartialEq + Ord>(mut v: Vec<T>) -> Vec<(usize, T)> {
    v.sort();
    let mut v = v.into_iter();
    let mut result = Vec::new();
    let mut current = v.next();
    'outer: while let Some(current_val) = current {
        let mut n = 1;
        for next in &mut v {
            if next == current_val {
                n += 1;
            } else {
                result.push((n, current_val));
                current = Some(next);
                continue 'outer;
            }
        }
        result.push((n, current_val));
        break;
    }
    result.sort();
    result
}
<|endoftext|>


<commit_before>#[macro_export]
macro_rules! gc_ref_type {
    { @as_item $it:item } => { $it };

    {
        pub struct $($x:tt)*
    } => {
        gc_ref_type! {
            @gc_heap_struct (pub) struct $($x)*
        }
    };
    {
        struct $($x:tt)*
    } => {
        gc_ref_type! {
            @gc_heap_struct () struct $($x)*
        }
    };

    {
        @gc_heap_struct ( $($maybe_pub:tt)* )
        struct $fields_type:ident / $ref_type:ident / $storage_type:ident / $ref_storage_type:ident <'a> {
            $($field_name:ident / $field_setter_name:ident : $field_type: ty),*
        }
    } => {
        // === $storage_type: the InHeap representation of the struct
        gc_ref_type! {
            @as_item
            $($maybe_pub)* struct $storage_type<'a> {
                $( pub $field_name: <$field_type as $crate::traits::IntoHeap<'a>>::In ),*
            }
        }

        unsafe impl<'a> $crate::traits::InHeap<'a> for $storage_type<'a> {
            type Out = $fields_type<'a>;

            unsafe fn mark(&self) {
                if !$crate::Heap::get_mark_bit(self) {
                    $crate::Heap::set_mark_bit(self);
                    $(
                        $crate::traits::InHeap::mark(&self.$field_name);
                    )*
                }
            }

            unsafe fn from_heap(&self) -> $fields_type<'a> {
                $fields_type {
                    $( $field_name: $crate::traits::InHeap::from_heap(&self.$field_name) ),*
                }
            }
        }

        // === $fields_type: A safe version of the struct
        gc_ref_type! {
            @as_item
            #[derive(Clone, Debug)]
            $($maybe_pub)* struct $fields_type<'a> {
                $( pub $field_name: $field_type ),*
            }
        }

        unsafe impl<'a> $crate::traits::IntoHeap<'a> for $fields_type<'a> {
            type In = $storage_type<'a>;

            fn into_heap(self) -> $storage_type<'a> {
                $storage_type {
                    $( $field_name: $crate::traits::IntoHeap::into_heap(self.$field_name) ),*
                }
            }
        }

        impl<'a> $crate::traits::IntoHeapAllocation<'a> for $fields_type<'a> {
            type Ref = $ref_type<'a>;

            fn wrap_gcref(gcref: $crate::GCRef<'a, $storage_type<'a>>) -> $ref_type<'a> {
                $ref_type(gcref)
            }
        }

        // === $ref_storage_type: The InHeap representation of a reference to the struct
        gc_ref_type! {
            @as_item
            #[derive(Clone, Copy, Debug, PartialEq, Eq)]
            $($maybe_pub)* struct $ref_storage_type<'a>(*mut $storage_type<'a>);
        }

        unsafe impl<'a> $crate::traits::InHeap<'a> for $ref_storage_type<'a> {
            type Out = $ref_type<'a>;

            unsafe fn mark(&self) {
                let ptr = self.0;
                if !ptr.is_null() {
                    $crate::traits::InHeap::mark(&*ptr);
                }
            }

            unsafe fn from_heap(&self) -> $ref_type<'a> {
                $ref_type($crate::GCRef::new(self.0))
            }
        }

        // === $ref_type: A safe reference to the struct
        gc_ref_type! {
            @as_item
            #[derive(Clone, Debug, PartialEq, Eq)]
            $($maybe_pub)* struct $ref_type<'a>($crate::GCRef<'a, $storage_type<'a>>);
        }

        unsafe impl<'a> $crate::traits::IntoHeap<'a> for $ref_type<'a> {
            type In = $ref_storage_type<'a>;

            fn into_heap(self) -> $ref_storage_type<'a> {
                $ref_storage_type(self.0.as_mut_ptr())
            }
        }

        impl<'a> $ref_type<'a> {
            // Field accessors.
            $(
                pub fn $field_name(&self) -> $field_type {
                    let ptr = self.0.as_ptr();
                    unsafe {
                        $crate::traits::InHeap::from_heap(&(*ptr).$field_name)
                    }
                }

                pub fn $field_setter_name(&self, v: $field_type) {
                    let ptr = self.0.as_mut_ptr();
                    let u = $crate::traits::IntoHeap::into_heap(v);
                    unsafe {
                        (*ptr).$field_name = u;
                    }
                }
            )*

            pub fn as_mut_ptr(&self) -> *mut $storage_type<'a> {
                self.0.as_mut_ptr()
            }
        }
    }
}

#[macro_export]
macro_rules! gc_inline_enum {
    { @as_item $x:item } => { $x };
    { @as_expr $x:expr } => { $x };

    {
        @parse_variants $helper_name:ident
        {}
        $( $etc:tt )*
    } => {
        gc_inline_enum! {
            $helper_name DONE
            $($etc)*
        }
    };

    {
        @parse_variants $helper_name:ident
        { $variant_name:ident }
        $( $etc:tt )*
    } => {
        gc_inline_enum! {
            $helper_name VARIANT $variant_name NO_FIELDS
            {}
            $($etc)*
        }
    };

    {
        @parse_variants $helper_name:ident
        { $variant_name:ident , $($more_variants:tt)* }
        $( $etc:tt )*
    } => {
        gc_inline_enum! {
            $helper_name VARIANT $variant_name NO_FIELDS
            { $($more_variants)* }
            $($etc)*
        }
    };

    {
        @parse_variants $helper_name:ident
        { $variant_name:ident ( $($field_types:tt)* ) }
        $( $etc:tt )*
    } => {
        gc_inline_enum! {
            $helper_name VARIANT $variant_name ( $($field_types)* )
            { }
            $($etc)*
        }
    };

    {
        @parse_variants $helper_name:ident
        { $variant_name:ident ( $($field_types:tt)* ), $($more_variants:tt)* }
        $( $etc:tt )*
    } => {
        gc_inline_enum! {
            $helper_name VARIANT $variant_name ( $($field_types)* )
            { $($more_variants)* }
            $($etc)*
        }
    };

    {
        @for_each_variant $_helper:tt {} $all_results:tt ($($ctn:tt)*)
    } => {
        gc_inline_enum! { $($ctn)* $all_results }
    };

    {
        @for_each_variant ($($helper:tt)*)
        { $variant_name:ident } $acc:tt $ctn:tt
    } => {
        gc_inline_enum! {
            $($helper)* $variant_name NO_FIELDS
                (@next_variant ($($helper)*) {} $acc $ctn)
        }
    };

    {
        @for_each_variant ($($helper:tt)*)
        { $variant_name:ident , $($more_variants:tt)* }
        $acc:tt $ctn:tt
    } => {
        gc_inline_enum! {
            $($helper)* $variant_name NO_FIELDS
                (@next_variant ($($helper)*) { $($more_variants)* } $acc $ctn)
        }
    };

    {
        @for_each_variant ($($helper:tt)*)
        { $variant_name:ident ( $($field_types:tt)* ) }
        $acc:tt $ctn:tt
    } => {
        gc_inline_enum! {
            $($helper)* $variant_name ( $($field_types)* )
                (@next_variant ($($helper)*) {} $acc $ctn)
        }
    };

    {
        @for_each_variant ($($helper:tt)*)
        { $variant_name:ident ( $($field_types:tt)* ), $($more_variants:tt)*  }
        $acc:tt $ctn:tt
    } => {
        gc_inline_enum! {
            $($helper)* $variant_name ( $($field_types)* )
                (@next_variant ($($helper)*) { $($more_variants)* } $acc $ctn)
        }
    };

    {
        @next_variant $helper:tt $more_variants:tt { $($acc:tt)* } $ctn:tt { $($rv:tt)* }
    } => {
        gc_inline_enum! {
            @for_each_variant $helper $more_variants { $($acc)* $($rv)* } $ctn
        }
    };

    {
        @declare_storage_type ( $($maybe_pub:tt)* ) $storage_type:ident
            { $($variants:tt)* }
    } => {
        gc_inline_enum! {
            @as_item
            $($maybe_pub)*
            enum $storage_type<'a> {
                $($variants)*
            }
        }
    };

    {
        @storage_type_variant $variant_name:ident NO_FIELDS ($($ctn:tt)*)
    } => {
        gc_inline_enum! {
            $($ctn)* { $variant_name, }
        }
    };

    {
        @storage_type_variant $variant_name:ident ( $($field_type:ty),* ) ($($ctn:tt)*)
    } => {
        gc_inline_enum! {
            $($ctn)* {
                $variant_name($(<$field_type as $crate::traits::IntoHeap<'a>>::In),*),
            }
        }
    };

    {
        @mark_expr ($self_ref:expr) { $($arms:tt)* }
    } => {
        gc_inline_enum! {
            @as_expr
            match *$self_ref {
                $($arms)*
            }
        }
    };

    {
        @mark_variant $storage_type:ident
            $name:ident NO_FIELDS ($($ctn:tt)*)
    } => {
        gc_inline_enum! {
            $($ctn)* { $storage_type::$name => (), }
        }
    };

    {
        @mark_variant $storage_type:ident
            $name:ident ( $($field_type:ty),* ) $ctn:tt
    } => {
        gc_inline_enum! {
            @zip_idents_with_types (a b c d e f g h i j k l m n o p q r s t u v w x y z)
                ( $($field_type),*, ) ()
                (@mark_variant_continued $storage_type $name $ctn)
        }
    };

    {
        @mark_variant_continued $storage_type:ident $name:ident ($($ctn:tt)*)
            ( $(($binding:ident : $field_type:ty))* )
    } => {
        gc_inline_enum! {
            $($ctn)* {
                $storage_type::$name ( $(ref $binding),* ) => {
                    $( $crate::traits::InHeap::mark($binding); )*
                },
            }
        }
    };

    {
        @into_heap_expr ($self_:expr)
        { $($accumulated_output:tt)* }
    } => {
        gc_inline_enum! {
            @as_expr
            match $self_ {
                $($accumulated_output)*
            }
        }
    };

    {
        @variant_into_heap $stack_type:ident $storage_type:ident
            $name:ident NO_FIELDS
            ($($ctn:tt)*)
    } => {
        gc_inline_enum! {
            $($ctn)* { $stack_type::$name => $storage_type::$name, }
        }
    };

    {
        @variant_into_heap $stack_type:ident $storage_type:ident
            $name:ident ( $($field_type:ty),* )
            $ctn:tt
    } => {
        gc_inline_enum! {
            @zip_idents_with_types (a b c d e f g h i j k l m n o p q r s t u v w x y z)
                ( $($field_type),*, ) ()
                (@variant_into_heap_continued $stack_type $storage_type $name $ctn)
        }
    };

    {
        @zip_idents_with_types $_leftovers:tt () ($(($binding:ident : $btype:ty))*) ($($ctn:tt)*)
    } => {
        gc_inline_enum! { $($ctn)* ($(($binding : $btype))*) }
    };
    {
        @zip_idents_with_types
        ($id:ident $($ids:tt)*)
        ($t:ty, $($ts:ty),*)
        ($($acc:tt)*)
        $ctn:tt
    } => {
        gc_inline_enum! {
            @zip_idents_with_types
            ($($ids)*)
            ($($ts),*)
            ($($acc)* ($id : $t))
            $ctn
        }
    };

    {
        @variant_into_heap_continued $stack_type:ident $storage_type:ident $name:ident ($($ctn:tt)*)
            ( $(($binding:ident : $field_type:ty))* )
    } => {
        gc_inline_enum! {
            $($ctn)* {
                $stack_type::$name ( $($binding),* ) =>
                    $storage_type::$name( $($crate::traits::IntoHeap::into_heap($binding)),* ),
            }
        }
    };

    {
        @from_heap_expr ($self_ref:expr) { $($arms:tt)* }
    } => {
        gc_inline_enum! {
            @as_expr
            match $self_ref {
                $($arms)*
            }
        }
    };

    {
        @from_heap_variant $stack_type:ident $storage_type:ident
            $name:ident NO_FIELDS ($($ctn:tt)*)
    } => {
        gc_inline_enum! {
            $($ctn)* { &$storage_type::$name => $stack_type::$name, }
        }
    };

    {
        @from_heap_variant $stack_type:ident $storage_type:ident
            $name:ident ( $($field_type:ty),* ) $ctn:tt
    } => {
        gc_inline_enum! {
            @zip_idents_with_types (a b c d e f g h i j k l m n o p q r s t u v w x y z)
                ( $($field_type),*, ) ()
                (@from_heap_variant_continued $stack_type $storage_type $name $ctn)
        }
    };

    {
        @from_heap_variant_continued $stack_type:ident $storage_type:ident $name:ident ($($ctn:tt)*)
            ( $(($binding:ident : $field_type:ty))* )
    } => {
        gc_inline_enum! {
            $($ctn)* {
                &$storage_type::$name ( ref $($binding),* ) =>
                    $stack_type::$name( $($crate::traits::InHeap::from_heap($binding)),* ),
            }
        }
    };

    {
        pub enum $($x:tt)*
    } => {
        gc_inline_enum! {
            @gc_heap_enum (pub) enum $($x)*
        }
    };

    {
        enum $($x:tt)*
    } => {
        gc_inline_enum! {
            @gc_heap_enum () enum $($x)*
        }
    };

    {
        @gc_heap_enum
        ($($maybe_pub:tt)*)
        enum $stack_type:ident / $storage_type:ident <'a>
        $variants:tt
    } => {
        gc_inline_enum! {
            @for_each_variant (@storage_type_variant) $variants {}
                (@declare_storage_type ( $($maybe_pub)* ) $storage_type)
        }

        gc_inline_enum! {
            @as_item
            #[derive(Debug, Clone, PartialEq)]
            $($maybe_pub)*
            enum $stack_type<'a>
                $variants
        }

        unsafe impl<'a> $crate::traits::InHeap<'a> for $storage_type<'a> {
            type Out = $stack_type<'a>;

            unsafe fn mark(&self) {
                gc_inline_enum! {
                    @for_each_variant (@mark_variant $storage_type) $variants {}
                    (@mark_expr (self))
                }
            }

            unsafe fn from_heap(&self) -> $stack_type<'a> {
                gc_inline_enum! {
                    @for_each_variant (@from_heap_variant $stack_type $storage_type) $variants {}
                    (@from_heap_expr (self))
                }
            }
        }

        unsafe impl<'a> $crate::traits::IntoHeap<'a> for $stack_type<'a> {
            type In = $storage_type<'a>;

            fn into_heap(self) -> $storage_type<'a> {
                gc_inline_enum! {
                    @for_each_variant (@variant_into_heap $stack_type $storage_type) $variants {}
                    (@into_heap_expr (self))
                }
            }
        }
    }
}
<commit_msg>Remove dead macro code.<commit_after>#[macro_export]
macro_rules! gc_ref_type {
    { @as_item $it:item } => { $it };

    {
        pub struct $($x:tt)*
    } => {
        gc_ref_type! {
            @gc_heap_struct (pub) struct $($x)*
        }
    };
    {
        struct $($x:tt)*
    } => {
        gc_ref_type! {
            @gc_heap_struct () struct $($x)*
        }
    };

    {
        @gc_heap_struct ( $($maybe_pub:tt)* )
        struct $fields_type:ident / $ref_type:ident / $storage_type:ident / $ref_storage_type:ident <'a> {
            $($field_name:ident / $field_setter_name:ident : $field_type: ty),*
        }
    } => {
        // === $storage_type: the InHeap representation of the struct
        gc_ref_type! {
            @as_item
            $($maybe_pub)* struct $storage_type<'a> {
                $( pub $field_name: <$field_type as $crate::traits::IntoHeap<'a>>::In ),*
            }
        }

        unsafe impl<'a> $crate::traits::InHeap<'a> for $storage_type<'a> {
            type Out = $fields_type<'a>;

            unsafe fn mark(&self) {
                if !$crate::Heap::get_mark_bit(self) {
                    $crate::Heap::set_mark_bit(self);
                    $(
                        $crate::traits::InHeap::mark(&self.$field_name);
                    )*
                }
            }

            unsafe fn from_heap(&self) -> $fields_type<'a> {
                $fields_type {
                    $( $field_name: $crate::traits::InHeap::from_heap(&self.$field_name) ),*
                }
            }
        }

        // === $fields_type: A safe version of the struct
        gc_ref_type! {
            @as_item
            #[derive(Clone, Debug)]
            $($maybe_pub)* struct $fields_type<'a> {
                $( pub $field_name: $field_type ),*
            }
        }

        unsafe impl<'a> $crate::traits::IntoHeap<'a> for $fields_type<'a> {
            type In = $storage_type<'a>;

            fn into_heap(self) -> $storage_type<'a> {
                $storage_type {
                    $( $field_name: $crate::traits::IntoHeap::into_heap(self.$field_name) ),*
                }
            }
        }

        impl<'a> $crate::traits::IntoHeapAllocation<'a> for $fields_type<'a> {
            type Ref = $ref_type<'a>;

            fn wrap_gcref(gcref: $crate::GCRef<'a, $storage_type<'a>>) -> $ref_type<'a> {
                $ref_type(gcref)
            }
        }

        // === $ref_storage_type: The InHeap representation of a reference to the struct
        gc_ref_type! {
            @as_item
            #[derive(Clone, Copy, Debug, PartialEq, Eq)]
            $($maybe_pub)* struct $ref_storage_type<'a>(*mut $storage_type<'a>);
        }

        unsafe impl<'a> $crate::traits::InHeap<'a> for $ref_storage_type<'a> {
            type Out = $ref_type<'a>;

            unsafe fn mark(&self) {
                let ptr = self.0;
                if !ptr.is_null() {
                    $crate::traits::InHeap::mark(&*ptr);
                }
            }

            unsafe fn from_heap(&self) -> $ref_type<'a> {
                $ref_type($crate::GCRef::new(self.0))
            }
        }

        // === $ref_type: A safe reference to the struct
        gc_ref_type! {
            @as_item
            #[derive(Clone, Debug, PartialEq, Eq)]
            $($maybe_pub)* struct $ref_type<'a>($crate::GCRef<'a, $storage_type<'a>>);
        }

        unsafe impl<'a> $crate::traits::IntoHeap<'a> for $ref_type<'a> {
            type In = $ref_storage_type<'a>;

            fn into_heap(self) -> $ref_storage_type<'a> {
                $ref_storage_type(self.0.as_mut_ptr())
            }
        }

        impl<'a> $ref_type<'a> {
            // Field accessors.
            $(
                pub fn $field_name(&self) -> $field_type {
                    let ptr = self.0.as_ptr();
                    unsafe {
                        $crate::traits::InHeap::from_heap(&(*ptr).$field_name)
                    }
                }

                pub fn $field_setter_name(&self, v: $field_type) {
                    let ptr = self.0.as_mut_ptr();
                    let u = $crate::traits::IntoHeap::into_heap(v);
                    unsafe {
                        (*ptr).$field_name = u;
                    }
                }
            )*

            pub fn as_mut_ptr(&self) -> *mut $storage_type<'a> {
                self.0.as_mut_ptr()
            }
        }
    }
}

#[macro_export]
macro_rules! gc_inline_enum {
    { @as_item $x:item } => { $x };
    { @as_expr $x:expr } => { $x };

    {
        @for_each_variant $_helper:tt {} $all_results:tt ($($ctn:tt)*)
    } => {
        gc_inline_enum! { $($ctn)* $all_results }
    };

    {
        @for_each_variant ($($helper:tt)*)
        { $variant_name:ident } $acc:tt $ctn:tt
    } => {
        gc_inline_enum! {
            $($helper)* $variant_name NO_FIELDS
                (@next_variant ($($helper)*) {} $acc $ctn)
        }
    };

    {
        @for_each_variant ($($helper:tt)*)
        { $variant_name:ident , $($more_variants:tt)* }
        $acc:tt $ctn:tt
    } => {
        gc_inline_enum! {
            $($helper)* $variant_name NO_FIELDS
                (@next_variant ($($helper)*) { $($more_variants)* } $acc $ctn)
        }
    };

    {
        @for_each_variant ($($helper:tt)*)
        { $variant_name:ident ( $($field_types:tt)* ) }
        $acc:tt $ctn:tt
    } => {
        gc_inline_enum! {
            $($helper)* $variant_name ( $($field_types)* )
                (@next_variant ($($helper)*) {} $acc $ctn)
        }
    };

    {
        @for_each_variant ($($helper:tt)*)
        { $variant_name:ident ( $($field_types:tt)* ), $($more_variants:tt)*  }
        $acc:tt $ctn:tt
    } => {
        gc_inline_enum! {
            $($helper)* $variant_name ( $($field_types)* )
                (@next_variant ($($helper)*) { $($more_variants)* } $acc $ctn)
        }
    };

    {
        @next_variant $helper:tt $more_variants:tt { $($acc:tt)* } $ctn:tt { $($rv:tt)* }
    } => {
        gc_inline_enum! {
            @for_each_variant $helper $more_variants { $($acc)* $($rv)* } $ctn
        }
    };

    {
        @declare_storage_type ( $($maybe_pub:tt)* ) $storage_type:ident
            { $($variants:tt)* }
    } => {
        gc_inline_enum! {
            @as_item
            $($maybe_pub)*
            enum $storage_type<'a> {
                $($variants)*
            }
        }
    };

    {
        @storage_type_variant $variant_name:ident NO_FIELDS ($($ctn:tt)*)
    } => {
        gc_inline_enum! {
            $($ctn)* { $variant_name, }
        }
    };

    {
        @storage_type_variant $variant_name:ident ( $($field_type:ty),* ) ($($ctn:tt)*)
    } => {
        gc_inline_enum! {
            $($ctn)* {
                $variant_name($(<$field_type as $crate::traits::IntoHeap<'a>>::In),*),
            }
        }
    };

    {
        @mark_expr ($self_ref:expr) { $($arms:tt)* }
    } => {
        gc_inline_enum! {
            @as_expr
            match *$self_ref {
                $($arms)*
            }
        }
    };

    {
        @mark_variant $storage_type:ident
            $name:ident NO_FIELDS ($($ctn:tt)*)
    } => {
        gc_inline_enum! {
            $($ctn)* { $storage_type::$name => (), }
        }
    };

    {
        @mark_variant $storage_type:ident
            $name:ident ( $($field_type:ty),* ) $ctn:tt
    } => {
        gc_inline_enum! {
            @zip_idents_with_types (a b c d e f g h i j k l m n o p q r s t u v w x y z)
                ( $($field_type),*, ) ()
                (@mark_variant_continued $storage_type $name $ctn)
        }
    };

    {
        @mark_variant_continued $storage_type:ident $name:ident ($($ctn:tt)*)
            ( $(($binding:ident : $field_type:ty))* )
    } => {
        gc_inline_enum! {
            $($ctn)* {
                $storage_type::$name ( $(ref $binding),* ) => {
                    $( $crate::traits::InHeap::mark($binding); )*
                },
            }
        }
    };

    {
        @into_heap_expr ($self_:expr)
        { $($accumulated_output:tt)* }
    } => {
        gc_inline_enum! {
            @as_expr
            match $self_ {
                $($accumulated_output)*
            }
        }
    };

    {
        @variant_into_heap $stack_type:ident $storage_type:ident
            $name:ident NO_FIELDS
            ($($ctn:tt)*)
    } => {
        gc_inline_enum! {
            $($ctn)* { $stack_type::$name => $storage_type::$name, }
        }
    };

    {
        @variant_into_heap $stack_type:ident $storage_type:ident
            $name:ident ( $($field_type:ty),* )
            $ctn:tt
    } => {
        gc_inline_enum! {
            @zip_idents_with_types (a b c d e f g h i j k l m n o p q r s t u v w x y z)
                ( $($field_type),*, ) ()
                (@variant_into_heap_continued $stack_type $storage_type $name $ctn)
        }
    };

    {
        @zip_idents_with_types $_leftovers:tt () ($(($binding:ident : $btype:ty))*) ($($ctn:tt)*)
    } => {
        gc_inline_enum! { $($ctn)* ($(($binding : $btype))*) }
    };
    {
        @zip_idents_with_types
        ($id:ident $($ids:tt)*)
        ($t:ty, $($ts:ty),*)
        ($($acc:tt)*)
        $ctn:tt
    } => {
        gc_inline_enum! {
            @zip_idents_with_types
            ($($ids)*)
            ($($ts),*)
            ($($acc)* ($id : $t))
            $ctn
        }
    };

    {
        @variant_into_heap_continued $stack_type:ident $storage_type:ident $name:ident ($($ctn:tt)*)
            ( $(($binding:ident : $field_type:ty))* )
    } => {
        gc_inline_enum! {
            $($ctn)* {
                $stack_type::$name ( $($binding),* ) =>
                    $storage_type::$name( $($crate::traits::IntoHeap::into_heap($binding)),* ),
            }
        }
    };

    {
        @from_heap_expr ($self_ref:expr) { $($arms:tt)* }
    } => {
        gc_inline_enum! {
            @as_expr
            match $self_ref {
                $($arms)*
            }
        }
    };

    {
        @from_heap_variant $stack_type:ident $storage_type:ident
            $name:ident NO_FIELDS ($($ctn:tt)*)
    } => {
        gc_inline_enum! {
            $($ctn)* { &$storage_type::$name => $stack_type::$name, }
        }
    };

    {
        @from_heap_variant $stack_type:ident $storage_type:ident
            $name:ident ( $($field_type:ty),* ) $ctn:tt
    } => {
        gc_inline_enum! {
            @zip_idents_with_types (a b c d e f g h i j k l m n o p q r s t u v w x y z)
                ( $($field_type),*, ) ()
                (@from_heap_variant_continued $stack_type $storage_type $name $ctn)
        }
    };

    {
        @from_heap_variant_continued $stack_type:ident $storage_type:ident $name:ident ($($ctn:tt)*)
            ( $(($binding:ident : $field_type:ty))* )
    } => {
        gc_inline_enum! {
            $($ctn)* {
                &$storage_type::$name ( ref $($binding),* ) =>
                    $stack_type::$name( $($crate::traits::InHeap::from_heap($binding)),* ),
            }
        }
    };

    {
        pub enum $($x:tt)*
    } => {
        gc_inline_enum! {
            @gc_heap_enum (pub) enum $($x)*
        }
    };

    {
        enum $($x:tt)*
    } => {
        gc_inline_enum! {
            @gc_heap_enum () enum $($x)*
        }
    };

    {
        @gc_heap_enum
        ($($maybe_pub:tt)*)
        enum $stack_type:ident / $storage_type:ident <'a>
        $variants:tt
    } => {
        gc_inline_enum! {
            @for_each_variant (@storage_type_variant) $variants {}
                (@declare_storage_type ( $($maybe_pub)* ) $storage_type)
        }

        gc_inline_enum! {
            @as_item
            #[derive(Debug, Clone, PartialEq)]
            $($maybe_pub)*
            enum $stack_type<'a>
                $variants
        }

        unsafe impl<'a> $crate::traits::InHeap<'a> for $storage_type<'a> {
            type Out = $stack_type<'a>;

            unsafe fn mark(&self) {
                gc_inline_enum! {
                    @for_each_variant (@mark_variant $storage_type) $variants {}
                    (@mark_expr (self))
                }
            }

            unsafe fn from_heap(&self) -> $stack_type<'a> {
                gc_inline_enum! {
                    @for_each_variant (@from_heap_variant $stack_type $storage_type) $variants {}
                    (@from_heap_expr (self))
                }
            }
        }

        unsafe impl<'a> $crate::traits::IntoHeap<'a> for $stack_type<'a> {
            type In = $storage_type<'a>;

            fn into_heap(self) -> $storage_type<'a> {
                gc_inline_enum! {
                    @for_each_variant (@variant_into_heap $stack_type $storage_type) $variants {}
                    (@into_heap_expr (self))
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>macro_rules! unwrap {
	($expr:expr, $fail_body:block) => (
		match $expr {
			::std::option::Option::Some(val) => val,
			::std::option::Option::None => $fail_body
		}
	);
}

macro_rules! is_none {
	($expr:expr) => (
		match $expr {
			::std::option::Option::None => true,
			_ => false,
		}
	);
}

macro_rules! is_some {
	($expr:expr) => (
		match $expr {
			::std::option::Option::None => false,
			_ => true,
		}
	);
}

macro_rules! matches {
	($expr:expr, $($pattern:tt)+) => (
		match $expr {
			$($pattern)+ => true,
			_ => false,
		}
	);
}

#[cfg(feature="trace")]
macro_rules! trace {
	($fmt:expr) => (println!($fmt));
	($fmt:expr, $($arg:tt)*) => (println!($fmt, $($arg)*));
}

#[cfg(not(feature="trace"))]
macro_rules! trace {
	($fmt:expr) => ();
	($fmt:expr, $($arg:tt)*) => ();
}
<commit_msg>Fix warning 'unused macro definition'<commit_after>macro_rules! unwrap {
	($expr:expr, $fail_body:block) => (
		match $expr {
			::std::option::Option::Some(val) => val,
			::std::option::Option::None => $fail_body
		}
	);
}

macro_rules! matches {
	($expr:expr, $($pattern:tt)+) => (
		match $expr {
			$($pattern)+ => true,
			_ => false,
		}
	);
}

#[cfg(feature="trace")]
macro_rules! trace {
	($fmt:expr) => (println!($fmt));
	($fmt:expr, $($arg:tt)*) => (println!($fmt, $($arg)*));
}

#[cfg(not(feature="trace"))]
macro_rules! trace {
	($fmt:expr) => ();
	($fmt:expr, $($arg:tt)*) => ();
}
<|endoftext|>


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

use std::io;
use std::rc::Rc;
use std::cell::RefCell;

use uuid::Uuid;
use devicemapper::DM;

use froyo::FroyoSave;
use types::{Sectors, SectorOffset, FroyoResult, FroyoError, InternalError};
use consts::*;
use blockdev::{LinearSegment, BlockDev, BlockDevs};
use dmdevice::DmDevice;
use raid::{RaidDev, RaidLinearDev};

#[derive(Debug, Clone)]
pub struct MirrorDev {
    pub mirror: DmDevice,
    pub src: Rc<RefCell<TempDev>>,
    pub dest: Rc<RefCell<TempDev>>,
    // info on raidlineardev in thinpool so we can restore table when done
    pub linear_dev: Rc<RefCell<RaidLinearDev>>,
    pub linear_dev_idxs: Vec<usize>,
}

impl MirrorDev {
    pub fn new(
        dm: &DM,
        name: &str,
        src: Rc<RefCell<TempDev>>,
        dest: Rc<RefCell<TempDev>>,
        length: Sectors,
        linear_dev: Rc<RefCell<RaidLinearDev>>,
        linear_dev_idxs: &[usize])
               -> FroyoResult<MirrorDev> {
        let table = (0, *length, "raid1",
                     format!("1 {} - {} - {}",
                             *STRIPE_SECTORS,
                             src.borrow().dmdev.dstr(),
                             dest.borrow().dmdev.dstr()));
        let dm_name = format!("froyo-copymirror-{}", name);
        let mirror_dev = try!(DmDevice::new(dm, &dm_name, &[table]));

        Ok(MirrorDev {
            mirror: mirror_dev,
            src: src,
            dest: dest,
            linear_dev: linear_dev,
            linear_dev_idxs: linear_dev_idxs.to_vec(),
        })
    }

    pub fn teardown(&self, dm: &DM) -> FroyoResult<()> {
        try!(self.mirror.teardown(dm));
        try!(self.src.borrow().teardown(dm));
        try!(self.dest.borrow().teardown(dm));
        Ok(())
    }

    pub fn is_syncing(&self, dm: &DM) -> FroyoResult<bool> {
        let mut status = try!(self.mirror.table_status(dm));

        // See kernel's dm-raid.txt "Status Output"
        let status_line = status.pop().unwrap().3;
        let status_vals = status_line.split(' ').collect::<Vec<_>>();
        if status_vals.len() < 5 {
            return Err(FroyoError::Io(io::Error::new(
                io::ErrorKind::InvalidData,
                "Kernel returned too few values from raid status")))
        }

        dbgp!("status line {}", status_line);
        dbgp!("status {}", status_vals[2]);
        dbgp!("action {}", status_vals[4]);

         match status_vals[4] {
             "idle" => Ok(false),
             "resync" => Ok(true),
             action => Err(FroyoError::Froyo(InternalError(
                 format!("Unexpected action: {}", action).into()))),
         }
    }
}

// Our TempDev's segments may either be on top of a RaidDev (e.g. if
// we're using the MirrorDev to copy to/from two raids) or it may be
// on top of a BlockDev, if we've resorted to using non-redundant
// scratch space.
#[derive(Debug, Clone)]
pub enum TempLayer {
    Block(Rc<RefCell<BlockDev>>),
    Raid(Rc<RefCell<RaidDev>>),
}

impl TempLayer {
    pub fn dstr(&self) -> String {
        match *self {
            TempLayer::Block(ref bd) => bd.borrow().dev.dstr(),
            TempLayer::Raid(ref rd) => rd.borrow().dev.dstr(),
        }
    }

    pub fn block(&self) -> Rc<RefCell<BlockDev>> {
        match *self {
            TempLayer::Block(ref bd) => bd.clone(),
            _ => panic!("should never happen"),
        }
    }

    pub fn raid(&self) -> Rc<RefCell<RaidDev>> {
        match *self {
            TempLayer::Raid(ref rd) => rd.clone(),
            _ => panic!("should never happen"),
        }
    }

    pub fn id(&self) -> String {
        match *self {
            TempLayer::Block(ref bd) => bd.borrow().id.to_owned(),
            TempLayer::Raid(ref rd) => rd.borrow().id.to_owned(),
        }
    }
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TempDevSegmentSave {
    pub parent: String,
    pub start: SectorOffset,
    pub length: Sectors,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TempDevSave {
    pub id: String,
    pub segments: Vec<TempDevSegmentSave>,
}

#[derive(Debug, Clone)]
pub struct TempDev {
    pub id: String,
    pub dmdev: DmDevice,
    pub segments: Vec<(TempLayer, LinearSegment)>,
}

// A linear device that can span multiple blockdevs.

impl TempDev {
    pub fn new(
        dm: &DM,
        name: &str,
        segments: &[(TempLayer, LinearSegment)])
        -> FroyoResult<TempDev> {

        let mut table = Vec::new();
        let mut offset = SectorOffset(0);
        for &(ref dev, seg) in segments {
            let line = (*offset, *seg.length, "linear",
                        format!("{} {}", dev.dstr(), *seg.start));
            table.push(line);
            offset = offset + SectorOffset(*seg.length);
        }

        let id = Uuid::new_v4().to_simple_string();
        let dm_name = format!("froyo-linear-temp-{}-{}", name, id);
        let dmdev = try!(DmDevice::new(dm, &dm_name, &table));

        Ok(TempDev {
            id: id,
            dmdev: dmdev,
            segments: segments.to_vec(),
        })
    }

    pub fn setup(
        dm: &DM,
        froyo_save: &FroyoSave,
        block_devs: &BlockDevs)
        -> FroyoResult<Option<TempDev>> {

        match froyo_save.temp_dev {
            None => Ok(None),
            Some(ref td) => {
                let mut td_segs = Vec::new();
                for seg in &td.segments {
                    if let Some(bd) = block_devs.0.get(&seg.parent)
                        .and_then(|bm| bm.present()) {
                        td_segs.push((TempLayer::Block(bd.clone()),
                                      LinearSegment::new(seg.start, seg.length)));
                    }
                }

                let td = try!(TempDev::new(dm, &froyo_save.id, &td_segs));
                Ok(Some(td))
            }
        }
    }

    pub fn dstr(&self) -> String {
        self.dmdev.dstr()
    }

    pub fn teardown(&self, dm: &DM) -> FroyoResult<()> {
        self.dmdev.teardown(dm)
    }

    pub fn length(&self) -> Sectors {
        self.segments.iter().map(|&(_, x)| x.length).sum()
    }

    pub fn to_save(&self) -> TempDevSave {
        TempDevSave {
            id: self.id.to_owned(),
            segments: self.segments.iter()
                .map(|&(ref tl, ls)| TempDevSegmentSave {
                    parent: tl.id(),
                    start: ls.start,
                    length: ls.length,
                })
                .collect(),
        }
    }
}
<commit_msg>Fix raid1 dm string<commit_after>// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

use std::io;
use std::rc::Rc;
use std::cell::RefCell;

use uuid::Uuid;
use devicemapper::DM;

use froyo::FroyoSave;
use types::{Sectors, SectorOffset, FroyoResult, FroyoError, InternalError};
use consts::*;
use blockdev::{LinearSegment, BlockDev, BlockDevs};
use dmdevice::DmDevice;
use raid::{RaidDev, RaidLinearDev};

#[derive(Debug, Clone)]
pub struct MirrorDev {
    pub mirror: DmDevice,
    pub src: Rc<RefCell<TempDev>>,
    pub dest: Rc<RefCell<TempDev>>,
    // info on raidlineardev in thinpool so we can restore table when done
    pub linear_dev: Rc<RefCell<RaidLinearDev>>,
    pub linear_dev_idxs: Vec<usize>,
}

impl MirrorDev {
    pub fn new(
        dm: &DM,
        name: &str,
        src: Rc<RefCell<TempDev>>,
        dest: Rc<RefCell<TempDev>>,
        length: Sectors,
        linear_dev: Rc<RefCell<RaidLinearDev>>,
        linear_dev_idxs: &[usize])
               -> FroyoResult<MirrorDev> {
        let table = (0, *length, "raid",
                     format!("raid1 1 {} 2 - {} - {}",
                             *STRIPE_SECTORS,
                             src.borrow().dmdev.dstr(),
                             dest.borrow().dmdev.dstr()));
        let dm_name = format!("froyo-copymirror-{}", name);
        let mirror_dev = try!(DmDevice::new(dm, &dm_name, &[table]));

        Ok(MirrorDev {
            mirror: mirror_dev,
            src: src,
            dest: dest,
            linear_dev: linear_dev,
            linear_dev_idxs: linear_dev_idxs.to_vec(),
        })
    }

    pub fn teardown(&self, dm: &DM) -> FroyoResult<()> {
        try!(self.mirror.teardown(dm));
        try!(self.src.borrow().teardown(dm));
        try!(self.dest.borrow().teardown(dm));
        Ok(())
    }

    pub fn is_syncing(&self, dm: &DM) -> FroyoResult<bool> {
        let mut status = try!(self.mirror.table_status(dm));

        // See kernel's dm-raid.txt "Status Output"
        let status_line = status.pop().unwrap().3;
        let status_vals = status_line.split(' ').collect::<Vec<_>>();
        if status_vals.len() < 5 {
            return Err(FroyoError::Io(io::Error::new(
                io::ErrorKind::InvalidData,
                "Kernel returned too few values from raid status")))
        }

        dbgp!("status line {}", status_line);
        dbgp!("status {}", status_vals[2]);
        dbgp!("action {}", status_vals[4]);

         match status_vals[4] {
             "idle" => Ok(false),
             "resync" => Ok(true),
             action => Err(FroyoError::Froyo(InternalError(
                 format!("Unexpected action: {}", action).into()))),
         }
    }
}

// Our TempDev's segments may either be on top of a RaidDev (e.g. if
// we're using the MirrorDev to copy to/from two raids) or it may be
// on top of a BlockDev, if we've resorted to using non-redundant
// scratch space.
#[derive(Debug, Clone)]
pub enum TempLayer {
    Block(Rc<RefCell<BlockDev>>),
    Raid(Rc<RefCell<RaidDev>>),
}

impl TempLayer {
    pub fn dstr(&self) -> String {
        match *self {
            TempLayer::Block(ref bd) => bd.borrow().dev.dstr(),
            TempLayer::Raid(ref rd) => rd.borrow().dev.dstr(),
        }
    }

    pub fn block(&self) -> Rc<RefCell<BlockDev>> {
        match *self {
            TempLayer::Block(ref bd) => bd.clone(),
            _ => panic!("should never happen"),
        }
    }

    pub fn raid(&self) -> Rc<RefCell<RaidDev>> {
        match *self {
            TempLayer::Raid(ref rd) => rd.clone(),
            _ => panic!("should never happen"),
        }
    }

    pub fn id(&self) -> String {
        match *self {
            TempLayer::Block(ref bd) => bd.borrow().id.to_owned(),
            TempLayer::Raid(ref rd) => rd.borrow().id.to_owned(),
        }
    }
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TempDevSegmentSave {
    pub parent: String,
    pub start: SectorOffset,
    pub length: Sectors,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TempDevSave {
    pub id: String,
    pub segments: Vec<TempDevSegmentSave>,
}

#[derive(Debug, Clone)]
pub struct TempDev {
    pub id: String,
    pub dmdev: DmDevice,
    pub segments: Vec<(TempLayer, LinearSegment)>,
}

// A linear device that can span multiple blockdevs.

impl TempDev {
    pub fn new(
        dm: &DM,
        name: &str,
        segments: &[(TempLayer, LinearSegment)])
        -> FroyoResult<TempDev> {

        let mut table = Vec::new();
        let mut offset = SectorOffset(0);
        for &(ref dev, seg) in segments {
            let line = (*offset, *seg.length, "linear",
                        format!("{} {}", dev.dstr(), *seg.start));
            table.push(line);
            offset = offset + SectorOffset(*seg.length);
        }

        let id = Uuid::new_v4().to_simple_string();
        let dm_name = format!("froyo-linear-temp-{}-{}", name, id);
        let dmdev = try!(DmDevice::new(dm, &dm_name, &table));

        Ok(TempDev {
            id: id,
            dmdev: dmdev,
            segments: segments.to_vec(),
        })
    }

    pub fn setup(
        dm: &DM,
        froyo_save: &FroyoSave,
        block_devs: &BlockDevs)
        -> FroyoResult<Option<TempDev>> {

        match froyo_save.temp_dev {
            None => Ok(None),
            Some(ref td) => {
                let mut td_segs = Vec::new();
                for seg in &td.segments {
                    if let Some(bd) = block_devs.0.get(&seg.parent)
                        .and_then(|bm| bm.present()) {
                        td_segs.push((TempLayer::Block(bd.clone()),
                                      LinearSegment::new(seg.start, seg.length)));
                    }
                }

                let td = try!(TempDev::new(dm, &froyo_save.id, &td_segs));
                Ok(Some(td))
            }
        }
    }

    pub fn dstr(&self) -> String {
        self.dmdev.dstr()
    }

    pub fn teardown(&self, dm: &DM) -> FroyoResult<()> {
        self.dmdev.teardown(dm)
    }

    pub fn length(&self) -> Sectors {
        self.segments.iter().map(|&(_, x)| x.length).sum()
    }

    pub fn to_save(&self) -> TempDevSave {
        TempDevSave {
            id: self.id.to_owned(),
            segments: self.segments.iter()
                .map(|&(ref tl, ls)| TempDevSegmentSave {
                    parent: tl.id(),
                    start: ls.start,
                    length: ls.length,
                })
                .collect(),
        }
    }
}
<|endoftext|>


<commit_before>use std::error::Error;
use std::collections::BTreeMap;
use std::collections::HashMap;

use rustc_serialize::json;
use rustc_serialize::json::{ToJson, Json};

#[derive(Debug, RustcEncodable)]
pub struct Notice<'a> {
    errors: Vec<Json>,
    context: HashMap<&'a str, HashMap<&'a str, &'a str>>,
}

#[derive(Debug)]
struct AirbrakeError {
    type_: String,
    message: String,
}

impl ToJson for AirbrakeError {
    fn to_json(&self) -> Json {
        let mut d = BTreeMap::new();
        d.insert("type".to_owned(), self.type_.to_json());
        d.insert("message".to_owned(), self.message.to_json());
        Json::Object(d)
    }
}

impl<'a> Notice<'a> {
    pub fn new<E: Error>(error: E) -> Notice<'a> {
        let mut context = HashMap::new();
        let mut notifier = HashMap::new();
        notifier.insert("name", "airbrake-rust");
        notifier.insert("version", "0.0.1");
        notifier.insert("url", "https://github.com/airbrake/airbrake-rust");

        context.insert("notifier", notifier);

        Notice {
            errors: vec![
                AirbrakeError {
                    type_: format!("{:?}", error).split_whitespace().next().unwrap().to_owned(),
                    message: format!("{}", error),
                }.to_json()
            ],
            context: context,
        }
    }

    pub fn to_json(&self) -> String {
        json::encode(&self).unwrap()
    }
}
<commit_msg>notice: simplify context creation<commit_after>use std::error::Error;
use std::collections::BTreeMap;

use rustc_serialize::json;
use rustc_serialize::json::{ToJson, Json};

#[derive(Debug, RustcEncodable)]
pub struct Notice {
    errors: Vec<Json>,
    context: Context,
}

#[derive(Debug, RustcEncodable)]
struct Context {
    notifier: NotifierPayload
}

#[derive(Debug, RustcEncodable)]
struct NotifierPayload {
    name: String,
    version: String,
    url: String,
}

#[derive(Debug)]
struct AirbrakeError {
    type_: String,
    message: String,
}

impl ToJson for AirbrakeError {
    fn to_json(&self) -> Json {
        let mut d = BTreeMap::new();
        d.insert("type".to_owned(), self.type_.to_json());
        d.insert("message".to_owned(), self.message.to_json());
        Json::Object(d)
    }
}

impl Notice {
    pub fn new<E: Error>(error: E) -> Notice {
        Notice {
            errors: vec![
                AirbrakeError {
                    type_: format!("{:?}", error).split_whitespace().next().unwrap().to_owned(),
                    message: format!("{}", error),
                }.to_json()
            ],
            context: Context {
                notifier: NotifierPayload {
                    name: "airbrake-rust".to_owned(),
                    version: env!("CARGO_PKG_VERSION").to_owned(),
                    url: "https://github.com/airbrake/airbrake-rust".to_owned(),
                }
            },
        }
    }

    pub fn to_json(&self) -> String {
        json::encode(&self).unwrap()
    }
}
<|endoftext|>


<commit_before>// Copyright 2015, The Gtk-rs Project Developers.
// See the COPYRIGHT file at the top-level directory of this distribution.
// Licensed under the MIT license, see the LICENSE file or <http://opensource.org/licenses/MIT>

use std::marker::PhantomData;
use glib::object::{Ref, Wrapper};

pub use glib::object::{Downcast, Upcast};

/// The generic type for `GObject` descendants in GDK.
pub struct Object<T>(Ref, PhantomData<T>);

impl<T: 'static> Wrapper for Object<T>
where Object<T>: StaticType {
    type GlibType = T;
    #[inline]
    unsafe fn wrap(r: Ref) -> Object<T> { Object(r, PhantomData) }
    #[inline]
    fn as_ref(&self) -> &Ref { &self.0 }
    #[inline]
    fn unwrap(self) -> Ref { self.0 }
}

impl<T> Clone for Object<T> {
    fn clone(&self) -> Object<T> {
        Object(self.0.clone(), PhantomData)
    }
}

unsafe impl<T: 'static> Upcast<::glib::object::Object> for Object<T> where Object<T>: StaticType { }
<commit_msg>Remove obsolete mod object<commit_after><|endoftext|>


<commit_before>// A pass that annotates for each loops and functions with the free
// variables that they contain.

import int;
import std::map::*;
import option::*;
import syntax::{ast, ast_util, visit};
import middle::resolve;
import syntax::codemap::span;

export annotate_freevars;
export freevar_map;
export freevar_info;
export get_freevars;
export has_freevars;

// A vector of defs representing the free variables referred to in a function.
// (The def_upvar will already have been stripped).
type freevar_entry = {
    def: ast::def, //< The variable being accessed free.
    span: span     //< First span where it is accessed (there can be multiple)
};
type freevar_info = @[@freevar_entry];
type freevar_map = hashmap<ast::node_id, freevar_info>;

// Searches through part of the AST for all references to locals or
// upvars in this frame and returns the list of definition IDs thus found.
// Since we want to be able to collect upvars in some arbitrary piece
// of the AST, we take a walker function that we invoke with a visitor
// in order to start the search.
fn collect_freevars(def_map: resolve::def_map, blk: ast::blk)
    -> freevar_info {
    let seen = new_int_hash();
    let refs = @mutable [];

    fn ignore_item(_i: @ast::item, &&_depth: int, _v: visit::vt<int>) { }

    let walk_expr =
        lambda (expr: @ast::expr, &&depth: int, v: visit::vt<int>) {
            alt expr.node {
              ast::expr_fn(proto, decl, _, captures) {
                if proto != ast::proto_bare {
                    visit::visit_expr(expr, depth + 1, v);
                }
              }
              ast::expr_fn_block(_, _) {
                visit::visit_expr(expr, depth + 1, v);
              }
              ast::expr_path(path) {
                let def = def_map.get(expr.id), i = 0;
                while i < depth {
                    alt copy def {
                      ast::def_upvar(_, inner, _) { def = *inner; }
                      _ { break; }
                    }
                    i += 1;
                }
                if i == depth { // Made it to end of loop
                    let dnum = ast_util::def_id_of_def(def).node;
                    if !seen.contains_key(dnum) {
                        *refs += [@{def:def, span:expr.span}];
                        seen.insert(dnum, ());
                    }
                }
              }
              _ { visit::visit_expr(expr, depth, v); }
            }
        };

    let v = visit::mk_vt(@{visit_item: ignore_item, visit_expr: walk_expr
                           with *visit::default_visitor()});
    v.visit_block(blk, 1, v);
    ret @*refs;
}

// Build a map from every function and for-each body to a set of the
// freevars contained in it. The implementation is not particularly
// efficient as it fully recomputes the free variables at every
// node of interest rather than building up the free variables in
// one pass. This could be improved upon if it turns out to matter.
fn annotate_freevars(def_map: resolve::def_map, crate: @ast::crate) ->
   freevar_map {
    let freevars = new_int_hash();

    let walk_fn = lambda (_fk: visit::fn_kind, _decl: ast::fn_decl,
                          blk: ast::blk, _sp: span, nid: ast::node_id) {
        let vars = collect_freevars(def_map, blk);
        freevars.insert(nid, vars);
    };

    let visitor =
        visit::mk_simple_visitor(@{visit_fn: walk_fn
                                   with *visit::default_simple_visitor()});
    visit::visit_crate(*crate, (), visitor);

    ret freevars;
}

fn get_freevars(tcx: ty::ctxt, fid: ast::node_id) -> freevar_info {
    alt tcx.freevars.find(fid) {
      none. { fail "get_freevars: " + int::str(fid) + " has no freevars"; }
      some(d) { ret d; }
    }
}
fn has_freevars(tcx: ty::ctxt, fid: ast::node_id) -> bool {
    ret vec::len(*get_freevars(tcx, fid)) != 0u;
}

// Local Variables:
// mode: rust
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// End:
<commit_msg>Eliminate a use of map::get in freevars<commit_after>// A pass that annotates for each loops and functions with the free
// variables that they contain.

import syntax::print::pprust::path_to_str;
import int;
import std::map::*;
import option::*;
import syntax::{ast, ast_util, visit};
import middle::resolve;
import syntax::codemap::span;

export annotate_freevars;
export freevar_map;
export freevar_info;
export get_freevars;
export has_freevars;

// A vector of defs representing the free variables referred to in a function.
// (The def_upvar will already have been stripped).
type freevar_entry = {
    def: ast::def, //< The variable being accessed free.
    span: span     //< First span where it is accessed (there can be multiple)
};
type freevar_info = @[@freevar_entry];
type freevar_map = hashmap<ast::node_id, freevar_info>;

// Searches through part of the AST for all references to locals or
// upvars in this frame and returns the list of definition IDs thus found.
// Since we want to be able to collect upvars in some arbitrary piece
// of the AST, we take a walker function that we invoke with a visitor
// in order to start the search.
fn collect_freevars(def_map: resolve::def_map, blk: ast::blk)
    -> freevar_info {
    let seen = new_int_hash();
    let refs = @mutable [];

    fn ignore_item(_i: @ast::item, &&_depth: int, _v: visit::vt<int>) { }

    let walk_expr =
        lambda (expr: @ast::expr, &&depth: int, v: visit::vt<int>) {
            alt expr.node {
              ast::expr_fn(proto, decl, _, captures) {
                if proto != ast::proto_bare {
                    visit::visit_expr(expr, depth + 1, v);
                }
              }
              ast::expr_fn_block(_, _) {
                visit::visit_expr(expr, depth + 1, v);
              }
              ast::expr_path(path) {
                  let i = 0;
                  alt def_map.find(expr.id) {
                    none. { fail ("Not found: " + path_to_str(path)) }
                    some(df) {
                      let def = df;
                      while i < depth {
                        alt copy def {
                          ast::def_upvar(_, inner, _) { def = *inner; }
                          _ { break; }
                        }
                        i += 1;
                      }
                      if i == depth { // Made it to end of loop
                        let dnum = ast_util::def_id_of_def(def).node;
                        if !seen.contains_key(dnum) {
                           *refs += [@{def:def, span:expr.span}];
                           seen.insert(dnum, ());
                        }
                      }
                    }
                  }
              }
              _ { visit::visit_expr(expr, depth, v); }
            }
        };

    let v = visit::mk_vt(@{visit_item: ignore_item, visit_expr: walk_expr
                           with *visit::default_visitor()});
    v.visit_block(blk, 1, v);
    ret @*refs;
}

// Build a map from every function and for-each body to a set of the
// freevars contained in it. The implementation is not particularly
// efficient as it fully recomputes the free variables at every
// node of interest rather than building up the free variables in
// one pass. This could be improved upon if it turns out to matter.
fn annotate_freevars(def_map: resolve::def_map, crate: @ast::crate) ->
   freevar_map {
    let freevars = new_int_hash();

    let walk_fn = lambda (_fk: visit::fn_kind, _decl: ast::fn_decl,
                          blk: ast::blk, _sp: span, nid: ast::node_id) {
        let vars = collect_freevars(def_map, blk);
        freevars.insert(nid, vars);
    };

    let visitor =
        visit::mk_simple_visitor(@{visit_fn: walk_fn
                                   with *visit::default_simple_visitor()});
    visit::visit_crate(*crate, (), visitor);

    ret freevars;
}

fn get_freevars(tcx: ty::ctxt, fid: ast::node_id) -> freevar_info {
    alt tcx.freevars.find(fid) {
      none. { fail "get_freevars: " + int::str(fid) + " has no freevars"; }
      some(d) { ret d; }
    }
}
fn has_freevars(tcx: ty::ctxt, fid: ast::node_id) -> bool {
    ret vec::len(*get_freevars(tcx, fid)) != 0u;
}

// Local Variables:
// mode: rust
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// End:
<|endoftext|>


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

// Timing functions.
use extra::time::precise_time_ns;
use std::cell::Cell;
use std::comm::{Port, SharedChan};
use extra::sort::tim_sort;
use std::iterator::AdditiveIterator;

// front-end representation of the profiler used to communicate with the profiler
#[deriving(Clone)]
pub struct ProfilerChan {
    chan: SharedChan<ProfilerMsg>,
}

impl ProfilerChan {
    pub fn new(chan: Chan<ProfilerMsg>) -> ProfilerChan {
        ProfilerChan {
            chan: SharedChan::new(chan),
        }
    }
    pub fn send(&self, msg: ProfilerMsg) {
        self.chan.send(msg);
    }
}

#[deriving(Eq, Clone)]
pub enum ProfilerCategory {
    CompositingCategory,
    LayoutQueryCategory,
    LayoutPerformCategory,
    LayoutAuxInitCategory,
    LayoutSelectorMatchCategory,
    LayoutTreeBuilderCategory,
    LayoutMainCategory,
    LayoutShapingCategory,
    LayoutDispListBuildCategory,
    GfxRegenAvailableFontsCategory,
    RenderingDrawingCategory,
    RenderingPrepBuffCategory,
    RenderingCategory,
    // hackish but helps prevent errors when adding new categories
    NumBuckets,
}
struct ProfilerBucket {
    category: ProfilerCategory,
    data: ~[float],
}
impl ProfilerBucket {
    fn new(category: ProfilerCategory) -> ProfilerBucket {
        ProfilerBucket {
            category: category,
            data: ~[],
        }
    }
}
// FIXME(rust#5873) this should be initialized by a NumBuckets cast,
type ProfilerBuckets = [ProfilerBucket, ..13];

pub enum ProfilerMsg {
    // Normal message used for reporting time
    TimeMsg(ProfilerCategory, float),
    // Message used to force print the profiling metrics
    PrintMsg,
}

// back end of the profiler that handles data aggregation and performance metrics
pub struct Profiler {
    port: Port<ProfilerMsg>,
    buckets: ProfilerBuckets,
    last_msg: Option<ProfilerMsg>,
}

impl ProfilerCategory {
    // convenience function to not have to cast every time
    pub fn num_buckets() -> uint {
        NumBuckets as uint
    }

    // enumeration of all ProfilerCategory types
    // TODO(tkuehn): is there a better way to ensure proper order of categories?
    fn empty_buckets() -> ProfilerBuckets {
        let buckets = [
            ProfilerBucket::new(CompositingCategory),
            ProfilerBucket::new(LayoutQueryCategory),
            ProfilerBucket::new(LayoutPerformCategory),
            ProfilerBucket::new(LayoutAuxInitCategory),
            ProfilerBucket::new(LayoutSelectorMatchCategory),
            ProfilerBucket::new(LayoutTreeBuilderCategory),
            ProfilerBucket::new(LayoutMainCategory),
            ProfilerBucket::new(LayoutShapingCategory),
            ProfilerBucket::new(LayoutDispListBuildCategory),
            ProfilerBucket::new(GfxRegenAvailableFontsCategory),
            ProfilerBucket::new(RenderingDrawingCategory),
            ProfilerBucket::new(RenderingPrepBuffCategory),
            ProfilerBucket::new(RenderingCategory),
        ];

        ProfilerCategory::check_order(&buckets);
        buckets
    }

    // ensure that the order of the buckets matches the order of the enum categories
    fn check_order(vec: &ProfilerBuckets) {
        for (i, bucket) in vec.iter().enumerate() {
            if bucket.category as uint != i {
                fail!("Enum category does not match bucket index. This is a bug.");
            }
        }
    }

    // some categories are subcategories of LayoutPerformCategory
    // and should be printed to indicate this
    pub fn format(self) -> ~str {
        let padding = match self {
            LayoutAuxInitCategory | LayoutSelectorMatchCategory | LayoutTreeBuilderCategory |
            LayoutMainCategory | LayoutDispListBuildCategory | LayoutShapingCategory=> " - ",
            _ => ""
        };
        fmt!("%s%?", padding, self)
    }
}

impl Profiler {
    pub fn create(port: Port<ProfilerMsg>) {
        let port = Cell::new(port);
        do spawn {
            let mut profiler = Profiler::new(port.take());
            profiler.start();
        }
    }

    pub fn new(port: Port<ProfilerMsg>) -> Profiler {
        Profiler {
            port: port,
            buckets: ProfilerCategory::empty_buckets(),
            last_msg: None,
        }
    }

    pub fn start(&mut self) {
        loop {
            let msg = self.port.try_recv();
            match msg {
               Some (msg) => self.handle_msg(msg),
               None => break
            }
        }
    }

    fn handle_msg(&mut self, msg: ProfilerMsg) {
        match msg {
            TimeMsg(category, t) => self.buckets[category as uint].data.push(t),
            PrintMsg => match self.last_msg {
                // only print if more data has arrived since the last printout
                Some(TimeMsg(*)) => self.print_buckets(),
                _ => ()
            },
        };
        self.last_msg = Some(msg);
    }

    fn print_buckets(&mut self) {
        println(fmt!("%31s %15s %15s %15s %15s %15s",
                         "_category_", "_mean (ms)_", "_median (ms)_",
                         "_min (ms)_", "_max (ms)_", "_bucket size_"));
        for &ProfilerBucket { category: ref category, data: ref mut data } in self.buckets.mut_iter() {
            tim_sort(*data);
            let data_len = data.len();
            if data_len > 0 {
                let (mean, median, &min, &max) =
                    (data.iter().map(|&x|x).sum() / (data_len as float),
                     data[data_len / 2],
                     data.iter().min().unwrap(),
                     data.iter().max().unwrap());
                println(fmt!("%-30s: %15.4f %15.4f %15.4f %15.4f %15u",
                             category.format(), mean, median, min, max, data_len));
            }
        }
        println("");
    }
}

pub fn profile<T>(category: ProfilerCategory,
                  profiler_chan: ProfilerChan,
                  callback: &fn() -> T)
                  -> T {
    let start_time = precise_time_ns();
    let val = callback();
    let end_time = precise_time_ns();
    let ms = ((end_time - start_time) as float / 1000000f);
    profiler_chan.send(TimeMsg(category, ms));
    return val;
}

pub fn time<T>(msg: &str, callback: &fn() -> T) -> T{
    let start_time = precise_time_ns();
    let val = callback();
    let end_time = precise_time_ns();
    let ms = ((end_time - start_time) as float / 1000000f);
    if ms >= 5f {
        debug!("%s took %? ms", msg, ms);
    }
    return val;
}

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

// Timing functions.
use extra::time::precise_time_ns;
use std::cell::Cell;
use std::comm::{Port, SharedChan};
use extra::sort::tim_sort;
use std::iterator::AdditiveIterator;

// front-end representation of the profiler used to communicate with the profiler
#[deriving(Clone)]
pub struct ProfilerChan {
    chan: SharedChan<ProfilerMsg>,
}

impl ProfilerChan {
    pub fn new(chan: Chan<ProfilerMsg>) -> ProfilerChan {
        ProfilerChan {
            chan: SharedChan::new(chan),
        }
    }
    pub fn send(&self, msg: ProfilerMsg) {
        self.chan.send(msg);
    }
}

#[deriving(Eq, Clone)]
pub enum ProfilerCategory {
    CompositingCategory,
    LayoutQueryCategory,
    LayoutPerformCategory,
    LayoutAuxInitCategory,
    LayoutSelectorMatchCategory,
    LayoutTreeBuilderCategory,
    LayoutMainCategory,
    LayoutShapingCategory,
    LayoutDispListBuildCategory,
    GfxRegenAvailableFontsCategory,
    RenderingDrawingCategory,
    RenderingPrepBuffCategory,
    RenderingCategory,
    // hackish but helps prevent errors when adding new categories
    NumBuckets,
}
struct ProfilerBucket {
    category: ProfilerCategory,
    data: ~[float],
}
impl ProfilerBucket {
    fn new(category: ProfilerCategory) -> ProfilerBucket {
        ProfilerBucket {
            category: category,
            data: ~[],
        }
    }
}
// FIXME(rust#5873) this should be initialized by a NumBuckets cast,
type ProfilerBuckets = [ProfilerBucket, ..13];

pub enum ProfilerMsg {
    // Normal message used for reporting time
    TimeMsg(ProfilerCategory, float),
    // Message used to force print the profiling metrics
    PrintMsg,
}

// back end of the profiler that handles data aggregation and performance metrics
pub struct Profiler {
    port: Port<ProfilerMsg>,
    buckets: ProfilerBuckets,
    last_msg: Option<ProfilerMsg>,
}

impl ProfilerCategory {
    // convenience function to not have to cast every time
    pub fn num_buckets() -> uint {
        NumBuckets as uint
    }

    // enumeration of all ProfilerCategory types
    fn empty_buckets() -> ProfilerBuckets {
        [
            ProfilerBucket::new(CompositingCategory),
            ProfilerBucket::new(LayoutQueryCategory),
            ProfilerBucket::new(LayoutPerformCategory),
            ProfilerBucket::new(LayoutAuxInitCategory),
            ProfilerBucket::new(LayoutSelectorMatchCategory),
            ProfilerBucket::new(LayoutTreeBuilderCategory),
            ProfilerBucket::new(LayoutMainCategory),
            ProfilerBucket::new(LayoutShapingCategory),
            ProfilerBucket::new(LayoutDispListBuildCategory),
            ProfilerBucket::new(GfxRegenAvailableFontsCategory),
            ProfilerBucket::new(RenderingDrawingCategory),
            ProfilerBucket::new(RenderingPrepBuffCategory),
            ProfilerBucket::new(RenderingCategory),
        ]
    }

    // some categories are subcategories of LayoutPerformCategory
    // and should be printed to indicate this
    pub fn format(self) -> ~str {
        let padding = match self {
            LayoutAuxInitCategory | LayoutSelectorMatchCategory | LayoutTreeBuilderCategory |
            LayoutMainCategory | LayoutDispListBuildCategory | LayoutShapingCategory=> " - ",
            _ => ""
        };
        fmt!("%s%?", padding, self)
    }
}

impl Profiler {
    pub fn create(port: Port<ProfilerMsg>) {
        let port = Cell::new(port);
        do spawn {
            let mut profiler = Profiler::new(port.take());
            profiler.start();
        }
    }

    pub fn new(port: Port<ProfilerMsg>) -> Profiler {
        Profiler {
            port: port,
            buckets: ProfilerCategory::empty_buckets(),
            last_msg: None,
        }
    }

    pub fn start(&mut self) {
        loop {
            let msg = self.port.try_recv();
            match msg {
               Some (msg) => self.handle_msg(msg),
               None => break
            }
        }
    }

    fn handle_msg(&mut self, msg: ProfilerMsg) {
        match msg {
            TimeMsg(category, t) => self.buckets[category as uint].data.push(t),
            PrintMsg => match self.last_msg {
                // only print if more data has arrived since the last printout
                Some(TimeMsg(*)) => self.print_buckets(),
                _ => ()
            },
        };
        self.last_msg = Some(msg);
    }

    fn print_buckets(&mut self) {
        println(fmt!("%31s %15s %15s %15s %15s %15s",
                         "_category_", "_mean (ms)_", "_median (ms)_",
                         "_min (ms)_", "_max (ms)_", "_bucket size_"));
        for &ProfilerBucket { category: ref category, data: ref mut data } in self.buckets.mut_iter() {
            tim_sort(*data);
            let data_len = data.len();
            if data_len > 0 {
                let (mean, median, &min, &max) =
                    (data.iter().map(|&x|x).sum() / (data_len as float),
                     data[data_len / 2],
                     data.iter().min().unwrap(),
                     data.iter().max().unwrap());
                println(fmt!("%-30s: %15.4f %15.4f %15.4f %15.4f %15u",
                             category.format(), mean, median, min, max, data_len));
            }
        }
        println("");
    }
}

pub fn profile<T>(category: ProfilerCategory,
                  profiler_chan: ProfilerChan,
                  callback: &fn() -> T)
                  -> T {
    let start_time = precise_time_ns();
    let val = callback();
    let end_time = precise_time_ns();
    let ms = ((end_time - start_time) as float / 1000000f);
    profiler_chan.send(TimeMsg(category, ms));
    return val;
}

pub fn time<T>(msg: &str, callback: &fn() -> T) -> T{
    let start_time = precise_time_ns();
    let val = callback();
    let end_time = precise_time_ns();
    let ms = ((end_time - start_time) as float / 1000000f);
    if ms >= 5f {
        debug!("%s took %? ms", msg, ms);
    }
    return val;
}

#[cfg(test)]
mod test {
    // ensure that the order of the buckets matches the order of the enum categories
    #[test]
    fn check_order() {
        let buckets = ProfilerCategory::empty_buckets();
        for (i, bucket) in buckets.iter().enumerate() {
            assert!(bucket.category as uint == i);
        }
    }
}
<|endoftext|>


<commit_before>use std::str::Chars;
use std::rc::Rc;
use dictionary::Dictionary;
use word::Word;
use branch::Branch;
use state::InterpState;

/// Takes a chars iterator and returns all characters up to the next whitespace,
/// excluding the whitespace character. Returns `None` the `chars` iterator is
/// exhausted.
fn next_word(chars: &mut Chars) -> Option<String> {
    let mut word = String::new();

    while let Some(c) = chars.next() {
        if c == ' ' || c == '\n' {
            if word.is_empty() {
                continue;
            }
            break;
        }
        word.push(c);
    }

    if word.is_empty() {
        // No input left
        None
    } else {
        Some(word)
    }
}

fn parse_word(word_str: &str, chars: &mut Chars, dict: &mut Dictionary, state: &mut InterpState) -> Option<Branch> {
    if let Some(word) = dict.get(word_str) {
        match word {
            Word::Custom(x) => Some(Branch::Custom(x)),
            Word::Builtin(x) => Some(Branch::Builtin(x)),
            Word::Int(x) => Some(Branch::Int(x)),
            Word::Float(x) => Some(Branch::Float(x)),
            Word::Dotquote => {
                let text = chars.take_while(|x| *x != '"').collect();
                Some(Branch::Dotquote(text))
            }
            Word::Paren => {
                // Consumes all characters up to next )
                chars.take_while(|x| *x != ')').count();
                None
            }
            Word::Colon => {
                let name = next_word(chars).unwrap();
                let mut inner_branches: Vec<Branch> = Vec::new();
                while let Some(inner_word_str) = next_word(chars) {
                    if dict.get(&inner_word_str) == Some(Word::Semicolon) {
                        break;
                    }
                    if let Some(branch) = parse_word(&inner_word_str, chars, dict, state) {
                        inner_branches.push(branch);
                    }
                }
                dict.set(&name, Word::Custom(Rc::new(inner_branches)));
                None
            }
            Word::If => {
                let mut ifbranches = Vec::new();
                let mut elsebranches = Vec::new();
                while let Some(inner_word_str) = next_word(chars) {
                    if dict.get(&inner_word_str) == Some(Word::Else) {
                        while let Some(inner_word_str) = next_word(chars) {
                            if dict.get(&inner_word_str) == Some(Word::Then) {
                                break;
                            }
                        }
                        if let Some(branch) = parse_word(&inner_word_str, chars, dict, state) {
                            elsebranches.push(branch);
                        }
                        break;
                    } else if dict.get(&inner_word_str) == Some(Word::Then) {
                        break;
                    }
                    if let Some(branch) = parse_word(&inner_word_str, chars, dict, state) {
                        ifbranches.push(branch);
                    }
                }
                Some(Branch::IfElse(ifbranches, elsebranches))
            }
            Word::Variable => {
                let name = next_word(chars).unwrap();
                let addr = state.memory.new(0);
                dict.set(&name, Word::Int(addr));
                None
            }
            Word::Create => {
                let name = next_word(chars).unwrap();
                let addr = state.memory.here() + 1;
                dict.set(&name, Word::Int(addr));
                None
            }
            Word::Semicolon | Word::Else | Word::Then => {
                panic!("Invalid here");
            }
        }
    } else {
        panic!("Word '{}' not in dictionary.", word_str);
    }
}

pub fn parse(code: &mut Chars, dict: &mut Dictionary, state: &mut InterpState) -> Vec<Branch> {
    let mut branches: Vec<Branch> = Vec::new();
    while let Some(word_str) = next_word(code) {
        if let Some(branch) = parse_word(&word_str, code, dict, state) {
            branches.push(branch);
        }
    }

    branches
}
<commit_msg>Make parser functions take generic char iterator<commit_after>use std::rc::Rc;
use dictionary::Dictionary;
use word::Word;
use branch::Branch;
use state::InterpState;

/// Takes a chars iterator and returns all characters up to the next whitespace,
/// excluding the whitespace character. Returns `None` the `chars` iterator is
/// exhausted.
fn next_word<T: Iterator<Item = char>>(chars: &mut T) -> Option<String> {
    let mut word = String::new();

    while let Some(c) = chars.next() {
        if c == ' ' || c == '\n' {
            if word.is_empty() {
                continue;
            }
            break;
        }
        word.push(c);
    }

    if word.is_empty() {
        // No input left
        None
    } else {
        Some(word)
    }
}

fn parse_word<T: Iterator<Item = char>>(word_str: &str, chars: &mut T, dict: &mut Dictionary, state: &mut InterpState) -> Option<Branch> {
    if let Some(word) = dict.get(word_str) {
        match word {
            Word::Custom(x) => Some(Branch::Custom(x)),
            Word::Builtin(x) => Some(Branch::Builtin(x)),
            Word::Int(x) => Some(Branch::Int(x)),
            Word::Float(x) => Some(Branch::Float(x)),
            Word::Dotquote => {
                let text = chars.take_while(|x| *x != '"').collect();
                Some(Branch::Dotquote(text))
            }
            Word::Paren => {
                // Consumes all characters up to next )
                chars.take_while(|x| *x != ')').count();
                None
            }
            Word::Colon => {
                let name = next_word(chars).unwrap();
                let mut inner_branches: Vec<Branch> = Vec::new();
                while let Some(inner_word_str) = next_word(chars) {
                    if dict.get(&inner_word_str) == Some(Word::Semicolon) {
                        break;
                    }
                    if let Some(branch) = parse_word(&inner_word_str, chars, dict, state) {
                        inner_branches.push(branch);
                    }
                }
                dict.set(&name, Word::Custom(Rc::new(inner_branches)));
                None
            }
            Word::If => {
                let mut ifbranches = Vec::new();
                let mut elsebranches = Vec::new();
                while let Some(inner_word_str) = next_word(chars) {
                    if dict.get(&inner_word_str) == Some(Word::Else) {
                        while let Some(inner_word_str) = next_word(chars) {
                            if dict.get(&inner_word_str) == Some(Word::Then) {
                                break;
                            }
                        }
                        if let Some(branch) = parse_word(&inner_word_str, chars, dict, state) {
                            elsebranches.push(branch);
                        }
                        break;
                    } else if dict.get(&inner_word_str) == Some(Word::Then) {
                        break;
                    }
                    if let Some(branch) = parse_word(&inner_word_str, chars, dict, state) {
                        ifbranches.push(branch);
                    }
                }
                Some(Branch::IfElse(ifbranches, elsebranches))
            }
            Word::Variable => {
                let name = next_word(chars).unwrap();
                let addr = state.memory.new(0);
                dict.set(&name, Word::Int(addr));
                None
            }
            Word::Create => {
                let name = next_word(chars).unwrap();
                let addr = state.memory.here() + 1;
                dict.set(&name, Word::Int(addr));
                None
            }
            Word::Semicolon | Word::Else | Word::Then => {
                panic!("Invalid here");
            }
        }
    } else {
        panic!("Word '{}' not in dictionary.", word_str);
    }
}

pub fn parse<T: Iterator<Item = char>>(code: &mut T, dict: &mut Dictionary, state: &mut InterpState) -> Vec<Branch> {
    let mut branches: Vec<Branch> = Vec::new();
    while let Some(word_str) = next_word(code) {
        if let Some(branch) = parse_word(&word_str, code, dict, state) {
            branches.push(branch);
        }
    }

    branches
}
<|endoftext|>