<commit_before>use std::any::Any;
use std::ffi::CString;
use std::fs::File;
use std::os::raw::{c_char, c_int};

use rustc::middle::cstore::EncodedMetadata;
use rustc::mir::mono::{Linkage as RLinkage, Visibility};
use rustc::session::config::{DebugInfo, OutputType};
use rustc_codegen_ssa::back::linker::LinkerInfo;
use rustc_codegen_ssa::CrateInfo;

use cranelift_faerie::*;

use crate::prelude::*;

pub fn codegen_crate(
    tcx: TyCtxt<'_>,
    metadata: EncodedMetadata,
    need_metadata_module: bool,
) -> Box<dyn Any> {
    tcx.sess.abort_if_errors();

    let mut log = if cfg!(debug_assertions) {
        Some(File::create(concat!(env!("CARGO_MANIFEST_DIR"), "/target/out/log.txt")).unwrap())
    } else {
        None
    };

    if std::env::var("SHOULD_RUN").is_ok()
        && tcx.sess.crate_types.get().contains(&CrateType::Executable)
    {
        #[cfg(not(target_arch = "wasm32"))]
        let _: ! = run_jit(tcx, &mut log);

        #[cfg(target_arch = "wasm32")]
        panic!("jit not supported on wasm");
    }

    run_aot(tcx, metadata, need_metadata_module, &mut log)
}

#[cfg(not(target_arch = "wasm32"))]
fn run_jit(tcx: TyCtxt<'_>, log: &mut Option<File>) -> ! {
    use cranelift_simplejit::{SimpleJITBackend, SimpleJITBuilder};

    let imported_symbols = load_imported_symbols_for_jit(tcx);

    let mut jit_builder = SimpleJITBuilder::with_isa(
        crate::build_isa(tcx.sess, false),
        cranelift_module::default_libcall_names(),
    );
    jit_builder.symbols(imported_symbols);
    let mut jit_module: Module<SimpleJITBackend> = Module::new(jit_builder);
    assert_eq!(pointer_ty(tcx), jit_module.target_config().pointer_type());

    let sig = Signature {
        params: vec![
            AbiParam::new(jit_module.target_config().pointer_type()),
            AbiParam::new(jit_module.target_config().pointer_type()),
        ],
        returns: vec![AbiParam::new(
            jit_module.target_config().pointer_type(), /*isize*/
        )],
        call_conv: CallConv::SystemV,
    };
    let main_func_id = jit_module
        .declare_function("main", Linkage::Import, &sig)
        .unwrap();

    codegen_cgus(tcx, &mut jit_module, &mut None, log);
    crate::allocator::codegen(tcx.sess, &mut jit_module);
    jit_module.finalize_definitions();

    tcx.sess.abort_if_errors();

    let finalized_main: *const u8 = jit_module.get_finalized_function(main_func_id);

    println!("Rustc codegen cranelift will JIT run the executable, because the SHOULD_RUN env var is set");

    let f: extern "C" fn(c_int, *const *const c_char) -> c_int =
        unsafe { ::std::mem::transmute(finalized_main) };

    let args = ::std::env::var("JIT_ARGS").unwrap_or_else(|_| String::new());
    let args = args
        .split(" ")
        .chain(Some(&*tcx.crate_name(LOCAL_CRATE).as_str().to_string()))
        .map(|arg| CString::new(arg).unwrap())
        .collect::<Vec<_>>();
    let argv = args.iter().map(|arg| arg.as_ptr()).collect::<Vec<_>>();
    // TODO: Rust doesn't care, but POSIX argv has a NULL sentinel at the end

    let ret = f(args.len() as c_int, argv.as_ptr());

    jit_module.finish();
    std::process::exit(ret);
}

fn load_imported_symbols_for_jit(tcx: TyCtxt<'_>) -> Vec<(String, *const u8)> {
    use rustc::middle::dependency_format::Linkage;

    let mut dylib_paths = Vec::new();

    let crate_info = CrateInfo::new(tcx);
    let formats = tcx.sess.dependency_formats.borrow();
    let data = formats.get(&CrateType::Executable).unwrap();
    for &(cnum, _) in &crate_info.used_crates_dynamic {
        let src = &crate_info.used_crate_source[&cnum];
        match data[cnum.as_usize() - 1] {
            Linkage::NotLinked | Linkage::IncludedFromDylib => {}
            Linkage::Static => {
                let name = tcx.crate_name(cnum);
                let mut err = tcx
                    .sess
                    .struct_err(&format!("Can't load static lib {}", name.as_str()));
                err.note("rustc_codegen_cranelift can only load dylibs in JIT mode.");
                err.emit();
            }
            Linkage::Dynamic => {
                dylib_paths.push(src.dylib.as_ref().unwrap().0.clone());
            }
        }
    }

    let mut imported_symbols = Vec::new();
    for path in dylib_paths {
        use object::Object;
        let lib = libloading::Library::new(&path).unwrap();
        let obj = std::fs::read(path).unwrap();
        let obj = object::File::parse(&obj).unwrap();
        imported_symbols.extend(obj.dynamic_symbols().filter_map(|(_idx, symbol)| {
            let name = symbol.name().unwrap().to_string();
            if name.is_empty() || !symbol.is_global() || symbol.is_undefined() {
                return None;
            }
            let symbol: libloading::Symbol<*const u8> =
                unsafe { lib.get(name.as_bytes()) }.unwrap();
            Some((name, *symbol))
        }));
        std::mem::forget(lib)
    }

    tcx.sess.abort_if_errors();

    imported_symbols
}

fn run_aot(
    tcx: TyCtxt<'_>,
    metadata: EncodedMetadata,
    need_metadata_module: bool,
    log: &mut Option<File>,
) -> Box<CodegenResults> {
    let new_module = |name: String| {
        let module: Module<FaerieBackend> = Module::new(
            FaerieBuilder::new(
                crate::build_isa(tcx.sess, true),
                name + ".o",
                FaerieTrapCollection::Disabled,
                cranelift_module::default_libcall_names(),
            )
            .unwrap(),
        );
        assert_eq!(pointer_ty(tcx), module.target_config().pointer_type());
        module
    };

    let emit_module = |kind: ModuleKind,
                       mut module: Module<FaerieBackend>,
                       debug: Option<DebugContext>| {
        module.finalize_definitions();
        let mut artifact = module.finish().artifact;

        if let Some(mut debug) = debug {
            debug.emit(&mut artifact);
        }

        let tmp_file = tcx
            .output_filenames(LOCAL_CRATE)
            .temp_path(OutputType::Object, Some(&artifact.name));
        let obj = artifact.emit().unwrap();
        std::fs::write(&tmp_file, obj).unwrap();
        CompiledModule {
            name: artifact.name,
            kind,
            object: Some(tmp_file),
            bytecode: None,
            bytecode_compressed: None,
        }
    };

    let mut faerie_module = new_module("some_file".to_string());

    let mut debug = if tcx.sess.opts.debuginfo != DebugInfo::None
        // macOS debuginfo doesn't work yet (see #303)
        && !tcx.sess.target.target.options.is_like_osx
    {
        let debug = DebugContext::new(
            tcx,
            faerie_module.target_config().pointer_type().bytes() as u8,
        );
        Some(debug)
    } else {
        None
    };

    codegen_cgus(tcx, &mut faerie_module, &mut debug, log);

    tcx.sess.abort_if_errors();

    let mut allocator_module = new_module("allocator_shim".to_string());
    let created_alloc_shim = crate::allocator::codegen(tcx.sess, &mut allocator_module);

    rustc_incremental::assert_dep_graph(tcx);
    rustc_incremental::save_dep_graph(tcx);
    rustc_incremental::finalize_session_directory(tcx.sess, tcx.crate_hash(LOCAL_CRATE));

    let metadata_module = if need_metadata_module {
        use rustc::mir::mono::CodegenUnitNameBuilder;

        let cgu_name_builder = &mut CodegenUnitNameBuilder::new(tcx);
        let metadata_cgu_name = cgu_name_builder
            .build_cgu_name(LOCAL_CRATE, &["crate"], Some("metadata"))
            .as_str()
            .to_string();

        let mut metadata_artifact = faerie::Artifact::new(
            crate::build_isa(tcx.sess, true).triple().clone(),
            metadata_cgu_name.clone(),
        );
        crate::metadata::write_metadata(tcx, &mut metadata_artifact);

        let tmp_file = tcx
            .output_filenames(LOCAL_CRATE)
            .temp_path(OutputType::Metadata, Some(&metadata_cgu_name));

        let obj = metadata_artifact.emit().unwrap();
        std::fs::write(&tmp_file, obj).unwrap();

        Some(CompiledModule {
            name: metadata_cgu_name,
            kind: ModuleKind::Metadata,
            object: Some(tmp_file),
            bytecode: None,
            bytecode_compressed: None,
        })
    } else {
        None
    };

    Box::new(CodegenResults {
        crate_name: tcx.crate_name(LOCAL_CRATE),
        modules: vec![emit_module(
            ModuleKind::Regular,
            faerie_module,
            debug,
        )],
        allocator_module: if created_alloc_shim {
            Some(emit_module(
                ModuleKind::Allocator,
                allocator_module,
                None,
            ))
        } else {
            None
        },
        metadata_module,
        crate_hash: tcx.crate_hash(LOCAL_CRATE),
        metadata,
        windows_subsystem: None, // Windows is not yet supported
        linker_info: LinkerInfo::new(tcx),
        crate_info: CrateInfo::new(tcx),
    })
}

fn codegen_cgus<'tcx>(
    tcx: TyCtxt<'tcx>,
    module: &mut Module<impl Backend + 'static>,
    debug: &mut Option<DebugContext<'tcx>>,
    log: &mut Option<File>,
) {
    let (_, cgus) = tcx.collect_and_partition_mono_items(LOCAL_CRATE);
    let mono_items = cgus
        .iter()
        .map(|cgu| cgu.items_in_deterministic_order(tcx).into_iter())
        .flatten()
        .collect::<FxHashMap<_, (_, _)>>();

    codegen_mono_items(tcx, module, debug.as_mut(), log, mono_items);

    crate::main_shim::maybe_create_entry_wrapper(tcx, module);
}

fn codegen_mono_items<'tcx>(
    tcx: TyCtxt<'tcx>,
    module: &mut Module<impl Backend + 'static>,
    debug_context: Option<&mut DebugContext<'tcx>>,
    log: &mut Option<File>,
    mono_items: FxHashMap<MonoItem<'tcx>, (RLinkage, Visibility)>,
) {
    let mut cx = CodegenCx::new(tcx, module, debug_context);
    time("codegen mono items", move || {
        for (mono_item, (linkage, visibility)) in mono_items {
            crate::unimpl::try_unimpl(tcx, log, || {
                let linkage = crate::linkage::get_clif_linkage(mono_item, linkage, visibility);
                trans_mono_item(&mut cx, mono_item, linkage);
            });
        }

        cx.finalize();
    });
}

fn trans_mono_item<'clif, 'tcx, B: Backend + 'static>(
    cx: &mut crate::CodegenCx<'clif, 'tcx, B>,
    mono_item: MonoItem<'tcx>,
    linkage: Linkage,
) {
    let tcx = cx.tcx;
    match mono_item {
        MonoItem::Fn(inst) => {
            let _inst_guard =
                PrintOnPanic(|| format!("{:?} {}", inst, tcx.symbol_name(inst).name.as_str()));
            debug_assert!(!inst.substs.needs_infer());
            let _mir_guard = PrintOnPanic(|| {
                match inst.def {
                    InstanceDef::Item(_)
                    | InstanceDef::DropGlue(_, _)
                    | InstanceDef::Virtual(_, _) => {
                        let mut mir = ::std::io::Cursor::new(Vec::new());
                        crate::rustc_mir::util::write_mir_pretty(
                            tcx,
                            Some(inst.def_id()),
                            &mut mir,
                        )
                        .unwrap();
                        String::from_utf8(mir.into_inner()).unwrap()
                    }
                    _ => {
                        // FIXME fix write_mir_pretty for these instances
                        format!("{:#?}", tcx.instance_mir(inst.def))
                    }
                }
            });

            crate::base::trans_fn(cx, inst, linkage);
        }
        MonoItem::Static(def_id) => {
            crate::constant::codegen_static(&mut cx.constants_cx, def_id);
        }
        MonoItem::GlobalAsm(node_id) => tcx
            .sess
            .fatal(&format!("Unimplemented global asm mono item {:?}", node_id)),
    }
}

fn time<R>(name: &str, f: impl FnOnce() -> R) -> R {
    println!("[{}] start", name);
    let before = std::time::Instant::now();
    let res = f();
    let after = std::time::Instant::now();
    println!("[{}] end time: {:?}", name, after - before);
    res
}
<commit_msg>Add profile code around metadata object generation<commit_after>use std::any::Any;
use std::ffi::CString;
use std::fs::File;
use std::os::raw::{c_char, c_int};

use rustc::middle::cstore::EncodedMetadata;
use rustc::mir::mono::{Linkage as RLinkage, Visibility};
use rustc::session::config::{DebugInfo, OutputType};
use rustc_codegen_ssa::back::linker::LinkerInfo;
use rustc_codegen_ssa::CrateInfo;

use cranelift_faerie::*;

use crate::prelude::*;

pub fn codegen_crate(
    tcx: TyCtxt<'_>,
    metadata: EncodedMetadata,
    need_metadata_module: bool,
) -> Box<dyn Any> {
    tcx.sess.abort_if_errors();

    let mut log = if cfg!(debug_assertions) {
        Some(File::create(concat!(env!("CARGO_MANIFEST_DIR"), "/target/out/log.txt")).unwrap())
    } else {
        None
    };

    if std::env::var("SHOULD_RUN").is_ok()
        && tcx.sess.crate_types.get().contains(&CrateType::Executable)
    {
        #[cfg(not(target_arch = "wasm32"))]
        let _: ! = run_jit(tcx, &mut log);

        #[cfg(target_arch = "wasm32")]
        panic!("jit not supported on wasm");
    }

    run_aot(tcx, metadata, need_metadata_module, &mut log)
}

#[cfg(not(target_arch = "wasm32"))]
fn run_jit(tcx: TyCtxt<'_>, log: &mut Option<File>) -> ! {
    use cranelift_simplejit::{SimpleJITBackend, SimpleJITBuilder};

    let imported_symbols = load_imported_symbols_for_jit(tcx);

    let mut jit_builder = SimpleJITBuilder::with_isa(
        crate::build_isa(tcx.sess, false),
        cranelift_module::default_libcall_names(),
    );
    jit_builder.symbols(imported_symbols);
    let mut jit_module: Module<SimpleJITBackend> = Module::new(jit_builder);
    assert_eq!(pointer_ty(tcx), jit_module.target_config().pointer_type());

    let sig = Signature {
        params: vec![
            AbiParam::new(jit_module.target_config().pointer_type()),
            AbiParam::new(jit_module.target_config().pointer_type()),
        ],
        returns: vec![AbiParam::new(
            jit_module.target_config().pointer_type(), /*isize*/
        )],
        call_conv: CallConv::SystemV,
    };
    let main_func_id = jit_module
        .declare_function("main", Linkage::Import, &sig)
        .unwrap();

    codegen_cgus(tcx, &mut jit_module, &mut None, log);
    crate::allocator::codegen(tcx.sess, &mut jit_module);
    jit_module.finalize_definitions();

    tcx.sess.abort_if_errors();

    let finalized_main: *const u8 = jit_module.get_finalized_function(main_func_id);

    println!("Rustc codegen cranelift will JIT run the executable, because the SHOULD_RUN env var is set");

    let f: extern "C" fn(c_int, *const *const c_char) -> c_int =
        unsafe { ::std::mem::transmute(finalized_main) };

    let args = ::std::env::var("JIT_ARGS").unwrap_or_else(|_| String::new());
    let args = args
        .split(" ")
        .chain(Some(&*tcx.crate_name(LOCAL_CRATE).as_str().to_string()))
        .map(|arg| CString::new(arg).unwrap())
        .collect::<Vec<_>>();
    let argv = args.iter().map(|arg| arg.as_ptr()).collect::<Vec<_>>();
    // TODO: Rust doesn't care, but POSIX argv has a NULL sentinel at the end

    let ret = f(args.len() as c_int, argv.as_ptr());

    jit_module.finish();
    std::process::exit(ret);
}

fn load_imported_symbols_for_jit(tcx: TyCtxt<'_>) -> Vec<(String, *const u8)> {
    use rustc::middle::dependency_format::Linkage;

    let mut dylib_paths = Vec::new();

    let crate_info = CrateInfo::new(tcx);
    let formats = tcx.sess.dependency_formats.borrow();
    let data = formats.get(&CrateType::Executable).unwrap();
    for &(cnum, _) in &crate_info.used_crates_dynamic {
        let src = &crate_info.used_crate_source[&cnum];
        match data[cnum.as_usize() - 1] {
            Linkage::NotLinked | Linkage::IncludedFromDylib => {}
            Linkage::Static => {
                let name = tcx.crate_name(cnum);
                let mut err = tcx
                    .sess
                    .struct_err(&format!("Can't load static lib {}", name.as_str()));
                err.note("rustc_codegen_cranelift can only load dylibs in JIT mode.");
                err.emit();
            }
            Linkage::Dynamic => {
                dylib_paths.push(src.dylib.as_ref().unwrap().0.clone());
            }
        }
    }

    let mut imported_symbols = Vec::new();
    for path in dylib_paths {
        use object::Object;
        let lib = libloading::Library::new(&path).unwrap();
        let obj = std::fs::read(path).unwrap();
        let obj = object::File::parse(&obj).unwrap();
        imported_symbols.extend(obj.dynamic_symbols().filter_map(|(_idx, symbol)| {
            let name = symbol.name().unwrap().to_string();
            if name.is_empty() || !symbol.is_global() || symbol.is_undefined() {
                return None;
            }
            let symbol: libloading::Symbol<*const u8> =
                unsafe { lib.get(name.as_bytes()) }.unwrap();
            Some((name, *symbol))
        }));
        std::mem::forget(lib)
    }

    tcx.sess.abort_if_errors();

    imported_symbols
}

fn run_aot(
    tcx: TyCtxt<'_>,
    metadata: EncodedMetadata,
    need_metadata_module: bool,
    log: &mut Option<File>,
) -> Box<CodegenResults> {
    let new_module = |name: String| {
        let module: Module<FaerieBackend> = Module::new(
            FaerieBuilder::new(
                crate::build_isa(tcx.sess, true),
                name + ".o",
                FaerieTrapCollection::Disabled,
                cranelift_module::default_libcall_names(),
            )
            .unwrap(),
        );
        assert_eq!(pointer_ty(tcx), module.target_config().pointer_type());
        module
    };

    let emit_module = |kind: ModuleKind,
                       mut module: Module<FaerieBackend>,
                       debug: Option<DebugContext>| {
        module.finalize_definitions();
        let mut artifact = module.finish().artifact;

        if let Some(mut debug) = debug {
            debug.emit(&mut artifact);
        }

        let tmp_file = tcx
            .output_filenames(LOCAL_CRATE)
            .temp_path(OutputType::Object, Some(&artifact.name));
        let obj = artifact.emit().unwrap();
        std::fs::write(&tmp_file, obj).unwrap();
        CompiledModule {
            name: artifact.name,
            kind,
            object: Some(tmp_file),
            bytecode: None,
            bytecode_compressed: None,
        }
    };

    let mut faerie_module = new_module("some_file".to_string());

    let mut debug = if tcx.sess.opts.debuginfo != DebugInfo::None
        // macOS debuginfo doesn't work yet (see #303)
        && !tcx.sess.target.target.options.is_like_osx
    {
        let debug = DebugContext::new(
            tcx,
            faerie_module.target_config().pointer_type().bytes() as u8,
        );
        Some(debug)
    } else {
        None
    };

    codegen_cgus(tcx, &mut faerie_module, &mut debug, log);

    tcx.sess.abort_if_errors();

    let mut allocator_module = new_module("allocator_shim".to_string());
    let created_alloc_shim = crate::allocator::codegen(tcx.sess, &mut allocator_module);

    rustc_incremental::assert_dep_graph(tcx);
    rustc_incremental::save_dep_graph(tcx);
    rustc_incremental::finalize_session_directory(tcx.sess, tcx.crate_hash(LOCAL_CRATE));

    let metadata_module = if need_metadata_module {
        tcx.sess.profiler(|p| p.start_activity("codegen crate metadata"));
        let (metadata_cgu_name, tmp_file) = rustc::util::common::time(tcx.sess, "write compressed metadata", || {
            use rustc::mir::mono::CodegenUnitNameBuilder;

            let cgu_name_builder = &mut CodegenUnitNameBuilder::new(tcx);
            let metadata_cgu_name = cgu_name_builder
                .build_cgu_name(LOCAL_CRATE, &["crate"], Some("metadata"))
                .as_str()
                .to_string();

            let mut metadata_artifact = faerie::Artifact::new(
                crate::build_isa(tcx.sess, true).triple().clone(),
                metadata_cgu_name.clone(),
            );
            crate::metadata::write_metadata(tcx, &mut metadata_artifact);

            let tmp_file = tcx
                .output_filenames(LOCAL_CRATE)
                .temp_path(OutputType::Metadata, Some(&metadata_cgu_name));

            let obj = metadata_artifact.emit().unwrap();
            std::fs::write(&tmp_file, obj).unwrap();

            (metadata_cgu_name, tmp_file)
        });
        tcx.sess.profiler(|p| p.end_activity("codegen crate metadata"));

        Some(CompiledModule {
            name: metadata_cgu_name,
            kind: ModuleKind::Metadata,
            object: Some(tmp_file),
            bytecode: None,
            bytecode_compressed: None,
        })
    } else {
        None
    };

    Box::new(CodegenResults {
        crate_name: tcx.crate_name(LOCAL_CRATE),
        modules: vec![emit_module(
            ModuleKind::Regular,
            faerie_module,
            debug,
        )],
        allocator_module: if created_alloc_shim {
            Some(emit_module(
                ModuleKind::Allocator,
                allocator_module,
                None,
            ))
        } else {
            None
        },
        metadata_module,
        crate_hash: tcx.crate_hash(LOCAL_CRATE),
        metadata,
        windows_subsystem: None, // Windows is not yet supported
        linker_info: LinkerInfo::new(tcx),
        crate_info: CrateInfo::new(tcx),
    })
}

fn codegen_cgus<'tcx>(
    tcx: TyCtxt<'tcx>,
    module: &mut Module<impl Backend + 'static>,
    debug: &mut Option<DebugContext<'tcx>>,
    log: &mut Option<File>,
) {
    let (_, cgus) = tcx.collect_and_partition_mono_items(LOCAL_CRATE);
    let mono_items = cgus
        .iter()
        .map(|cgu| cgu.items_in_deterministic_order(tcx).into_iter())
        .flatten()
        .collect::<FxHashMap<_, (_, _)>>();

    codegen_mono_items(tcx, module, debug.as_mut(), log, mono_items);

    crate::main_shim::maybe_create_entry_wrapper(tcx, module);
}

fn codegen_mono_items<'tcx>(
    tcx: TyCtxt<'tcx>,
    module: &mut Module<impl Backend + 'static>,
    debug_context: Option<&mut DebugContext<'tcx>>,
    log: &mut Option<File>,
    mono_items: FxHashMap<MonoItem<'tcx>, (RLinkage, Visibility)>,
) {
    let mut cx = CodegenCx::new(tcx, module, debug_context);
    time("codegen mono items", move || {
        for (mono_item, (linkage, visibility)) in mono_items {
            crate::unimpl::try_unimpl(tcx, log, || {
                let linkage = crate::linkage::get_clif_linkage(mono_item, linkage, visibility);
                trans_mono_item(&mut cx, mono_item, linkage);
            });
        }

        cx.finalize();
    });
}

fn trans_mono_item<'clif, 'tcx, B: Backend + 'static>(
    cx: &mut crate::CodegenCx<'clif, 'tcx, B>,
    mono_item: MonoItem<'tcx>,
    linkage: Linkage,
) {
    let tcx = cx.tcx;
    match mono_item {
        MonoItem::Fn(inst) => {
            let _inst_guard =
                PrintOnPanic(|| format!("{:?} {}", inst, tcx.symbol_name(inst).name.as_str()));
            debug_assert!(!inst.substs.needs_infer());
            let _mir_guard = PrintOnPanic(|| {
                match inst.def {
                    InstanceDef::Item(_)
                    | InstanceDef::DropGlue(_, _)
                    | InstanceDef::Virtual(_, _) => {
                        let mut mir = ::std::io::Cursor::new(Vec::new());
                        crate::rustc_mir::util::write_mir_pretty(
                            tcx,
                            Some(inst.def_id()),
                            &mut mir,
                        )
                        .unwrap();
                        String::from_utf8(mir.into_inner()).unwrap()
                    }
                    _ => {
                        // FIXME fix write_mir_pretty for these instances
                        format!("{:#?}", tcx.instance_mir(inst.def))
                    }
                }
            });

            crate::base::trans_fn(cx, inst, linkage);
        }
        MonoItem::Static(def_id) => {
            crate::constant::codegen_static(&mut cx.constants_cx, def_id);
        }
        MonoItem::GlobalAsm(node_id) => tcx
            .sess
            .fatal(&format!("Unimplemented global asm mono item {:?}", node_id)),
    }
}

fn time<R>(name: &str, f: impl FnOnce() -> R) -> R {
    println!("[{}] start", name);
    let before = std::time::Instant::now();
    let res = f();
    let after = std::time::Instant::now();
    println!("[{}] end time: {:?}", name, after - before);
    res
}
<|endoftext|>


<commit_before>extern crate rsoundio;
extern crate rb;

use rb::{RB, SpscRb, RbProducer, RbConsumer};
use std::f32::consts::PI as PI32;
use std::thread;
use std::time::Duration;

fn main() {
    let rb = SpscRb::new(4096);
    let (producer, consumer) = (rb.producer(), rb.consumer());
    // create an audio context
    let mut sio = rsoundio::SoundIo::new();
    sio.set_name("rsoundio-example").unwrap();
    // connect to the default audio backend
    sio.connect().unwrap();
    let backend = sio.current_backend().unwrap();
    println!("Connected to backend: {}", backend);
    sio.flush_events();
    // get default output device
    let dev = sio.default_output_device().unwrap();
    assert!(dev.probe_error().is_none());
    println!("Using output device: {}", dev);
    // create output stream
    let mut out = dev.create_outstream().unwrap();
    assert!(out.set_name("sine").is_ok());
    out.set_format(rsoundio::SioFormat::Float32LE).unwrap();
    println!("Output format: {}", out.format().unwrap());

    thread::spawn(move || {
        const LEN: usize = 512;
        let mut pos = 0;
        loop {
            let f = 440f32;
            let w = 2.0 * f * PI32 / 48_000.0;
            let cycle =  (48_000f32 / f) as usize;

            let samples: Vec<f32> = (0..LEN)
                                    .map(|i| (w * (i+pos) as f32).sin())
                                    .collect();
            producer.write_blocking(&samples).unwrap();
            pos = (pos + LEN) % cycle;
        }
    });

    // register callbacks
    out.register_write_callback(|out: rsoundio::OutStream,
                                 min_frame_count: u32,
                                 max_frame_count: u32| {
        const BUF_SIZE: usize = 2048;
        let mut data = vec![0.0f32; BUF_SIZE];
        let len = if backend != rsoundio::SioBackend::PulseAudio {
            ::std::cmp::min(BUF_SIZE, max_frame_count as usize)
        } else {
            BUF_SIZE
        };
        consumer.read_blocking(&mut data[..len]);
        let frames = vec![data[..len].iter().cloned().collect(),
                          data[..len].iter().cloned().collect()];
        out.write_stream_f32(min_frame_count, &frames).unwrap();
    });
    out.register_underflow_callback(|out: rsoundio::OutStream| {
        println!("Underflow in {} occured!", out.name().unwrap())
    });
    out.register_error_callback(|out: rsoundio::OutStream, err: rsoundio::SioError| {
        println!("{} error: {}", out.name().unwrap(), err)
    });

    // open output stream
    out.open().unwrap();
    let sr = out.sample_rate();
    println!("Sample rate: {}", sr);

    let layout = out.layout();
    println!("Output channel layout: {}", layout);
    // start audio output (now the `write_callback` will be called periodically)
    out.start().unwrap();
    thread::sleep(Duration::new(3, 0));
    println!("Pause for 1s");
    out.pause();
    thread::sleep(Duration::new(1, 0));
    println!("Unpausing");
    out.unpause();
    thread::sleep(Duration::new(3, 0));
}
<commit_msg>Use constants and reduce signal volume<commit_after>extern crate rsoundio;
extern crate rb;

use rb::{RB, SpscRb, RbProducer, RbConsumer};
use std::f32::consts::PI as PI32;
use std::thread;
use std::time::Duration;

fn main() {
    let rb = SpscRb::new(4096);
    let (producer, consumer) = (rb.producer(), rb.consumer());
    // create an audio context
    let mut sio = rsoundio::SoundIo::new();
    sio.set_name("rsoundio-example").unwrap();
    // connect to the default audio backend
    sio.connect().unwrap();
    let backend = sio.current_backend().unwrap();
    println!("Connected to backend: {}", backend);
    sio.flush_events();
    // get default output device
    let dev = sio.default_output_device().unwrap();
    assert!(dev.probe_error().is_none());
    println!("Using output device: {}", dev);
    // create output stream
    let mut out = dev.create_outstream().unwrap();
    assert!(out.set_name("sine").is_ok());
    out.set_format(rsoundio::SioFormat::Float32LE).unwrap();
    println!("Output format: {}", out.format().unwrap());

    thread::spawn(move || {
        const LEN: usize = 1024;
        let mut pos = 0;
        loop {
            const f: f32 = 440.0;
            const w: f32 = 2.0 * f * PI32 / 48_000.0;
            const a: f32 = 0.6;
            const cycle: usize = (48_000f32 / f) as usize;

            let samples: Vec<f32> = (0..LEN)
                                        .map(|i| (w * (i + pos) as f32).sin() * a)
                                        .collect();
            producer.write_blocking(&samples).unwrap();
            pos = (pos + LEN) % cycle;
        }
    });

    // register callbacks
    out.register_write_callback(|out: rsoundio::OutStream,
                                 min_frame_count: u32,
                                 max_frame_count: u32| {
        const BUF_SIZE: usize = 2048;
        let mut data = vec![0.0f32; BUF_SIZE];
        let len = if backend != rsoundio::SioBackend::PulseAudio {
            ::std::cmp::min(BUF_SIZE, max_frame_count as usize)
        } else {
            BUF_SIZE
        };
        consumer.read_blocking(&mut data[..len]);
        let frames = vec![data[..len].iter().cloned().collect(),
                          data[..len].iter().cloned().collect()];
        out.write_stream_f32(min_frame_count, &frames).unwrap();
    });
    out.register_underflow_callback(|out: rsoundio::OutStream| {
        println!("Underflow in {} occured!", out.name().unwrap())
    });
    out.register_error_callback(|out: rsoundio::OutStream, err: rsoundio::SioError| {
        println!("{} error: {}", out.name().unwrap(), err)
    });

    // open output stream
    out.open().unwrap();
    let sr = out.sample_rate();
    println!("Sample rate: {}", sr);

    let layout = out.layout();
    println!("Output channel layout: {}", layout);
    // start audio output (now the `write_callback` will be called periodically)
    out.start().unwrap();
    thread::sleep(Duration::new(3, 0));
    println!("Pause for 1s");
    out.pause();
    thread::sleep(Duration::new(1, 0));
    println!("Unpausing");
    out.unpause();
    thread::sleep(Duration::new(3, 0));
}
<|endoftext|>


<commit_before>extern crate midir;

use std::thread::sleep_ms;

use midir::{MidiApi, MidiInApi};
use midir::alsa::MidiInAlsa;

fn main() {
	let mut midi = MidiInAlsa::new("My Test", 100).unwrap();
	let count = midi.get_port_count();
	println!("Device count: {}", count);
	for i in 0..count {
		println!("{}: {}", i, midi.get_port_name(i).unwrap());
	}
	println!("Opening port");
	midi.open_port(2, "RtMidi").unwrap();
	println!("Port open");

	let mut message = Vec::new();

  	for i in 0..500 {
	  	// switch to using a callback (and back)
		if i == 150 {
			midi.set_callback(|ts, vec| {
				println!("Callback: {} - {:?}", ts, vec);
			});
		} else if i == 350 {
			midi.cancel_callback();
		}
	    let stamp = midi.get_message(&mut message);
		if (message.len() > 0) {
			println!("{}: {:?}", stamp, message);
		}
	    // Sleep for 10 milliseconds ... platform-dependent.
	    sleep_ms(10);
  	}

	println!("Closing port");
	midi.close_port();
	println!("Port closed");
}<commit_msg>More indentation fixes<commit_after>extern crate midir;

use std::thread::sleep_ms;

use midir::{MidiApi, MidiInApi};
use midir::alsa::MidiInAlsa;

fn main() {
    let mut midi = MidiInAlsa::new("My Test", 100).unwrap();
    let count = midi.get_port_count();
    println!("Device count: {}", count);
    for i in 0..count {
        println!("{}: {}", i, midi.get_port_name(i).unwrap());
    }
    println!("Opening port");
    midi.open_port(2, "RtMidi").unwrap();
    println!("Port open");

    let mut message = Vec::new();

    for i in 0..500 {
          // switch to using a callback (and back)
        if i == 150 {
            midi.set_callback(|ts, vec| {
                println!("Callback: {} - {:?}", ts, vec);
            });
        } else if i == 350 {
            midi.cancel_callback();
        }
        let stamp = midi.get_message(&mut message);
        if (message.len() > 0) {
            println!("{}: {:?}", stamp, message);
        }
        // Sleep for 10 milliseconds ... platform-dependent.
        sleep_ms(10);
    }

    println!("Closing port");
    midi.close_port();
    println!("Port closed");
}<|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/. */

#[crate_id = "github.com/mozilla/servo"];
#[comment = "The Servo Parallel Browser Project"];
#[license = "MPL"];

#[feature(globs, macro_rules, phase, thread_local)];

#[feature(phase)];
#[phase(syntax, link)]
extern crate log;

extern crate alert;
extern crate azure;
extern crate geom;
extern crate gfx;
#[cfg(not(target_os="android"))]
extern crate glfw = "glfw-rs";
#[cfg(target_os="android")]
extern crate glut;
extern crate js;
extern crate layers;
extern crate opengles;
extern crate png;
extern crate rustuv;
extern crate script;
#[phase(syntax)]
extern crate servo_macros = "macros";
extern crate servo_net = "net";
extern crate servo_msg = "msg";
extern crate servo_util = "util";
extern crate style;
extern crate sharegl;
extern crate stb_image;

extern crate collections;
extern crate green;
extern crate native;
extern crate serialize;
extern crate sync;
extern crate time;
extern crate url;

#[cfg(target_os="macos")]
extern crate core_graphics;
#[cfg(target_os="macos")]
extern crate core_text;

#[cfg(not(test))]
use compositing::{CompositorChan, CompositorTask};
#[cfg(not(test))]
use constellation::Constellation;
#[cfg(not(test))]
use servo_msg::constellation_msg::{ConstellationChan, InitLoadUrlMsg};

#[cfg(not(test))]
use servo_net::image_cache_task::{ImageCacheTask, SyncImageCacheTask};
#[cfg(not(test))]
use servo_net::resource_task::ResourceTask;
#[cfg(not(test))]
use servo_util::time::Profiler;

#[cfg(not(test))]
use servo_util::opts;
#[cfg(not(test))]
use servo_util::url::parse_url;

#[cfg(not(test), not(target_os="android"))]
use std::os;
#[cfg(not(test), target_os="android")]
use std::str;
#[cfg(not(test))]
use std::task::TaskOpts;
#[cfg(not(test))]
use url::Url;

#[path="compositing/compositor_task.rs"]
pub mod compositing;

pub mod css {
    mod node_util;

    pub mod select;
    pub mod matching;
    pub mod node_style;
}

pub mod constellation;
pub mod pipeline;

pub mod layout {
    pub mod block;
    pub mod box_;
    pub mod construct;
    pub mod context;
    pub mod display_list_builder;
    pub mod floats;
    pub mod flow;
    pub mod flow_list;
    pub mod layout_task;
    pub mod inline;
    pub mod model;
    pub mod parallel;
    pub mod table_wrapper;
    pub mod table;
    pub mod table_caption;
    pub mod table_colgroup;
    pub mod table_rowgroup;
    pub mod table_row;
    pub mod table_cell;
    pub mod text;
    pub mod util;
    pub mod incremental;
    pub mod wrapper;
    pub mod extra;
}

pub mod windowing;

#[path="platform/mod.rs"]
pub mod platform;

#[cfg(not(test), target_os="linux")]
#[cfg(not(test), target_os="macos")]
#[start]
fn start(argc: int, argv: **u8) -> int {
    native::start(argc, argv, proc() {
        opts::from_cmdline_args(os::args()).map(run);
    })
}

#[cfg(not(test), target_os="android")]
#[no_mangle]
pub extern "C" fn android_start(argc: int, argv: **u8) -> int {
    native::start(argc, argv, proc() {
        let mut args:~[~str] = ~[];
        for i in range(0u, argc as uint) {
            unsafe {
                args.push(str::raw::from_c_str(*argv.offset(i as int) as *i8));
            }
        }
        opts::from_cmdline_args(args).map(run);
    })
}

#[cfg(not(test))]
fn run(opts: opts::Opts) {
    let mut pool = green::SchedPool::new(green::PoolConfig::new());

    let (compositor_port, compositor_chan) = CompositorChan::new();
    let profiler_chan = Profiler::create(opts.profiler_period);

    let opts_clone = opts.clone();
    let profiler_chan_clone = profiler_chan.clone();

    let (result_chan, result_port) = channel();
    pool.spawn(TaskOpts::new(), proc() {
        let opts = &opts_clone;
        // Create a Servo instance.
        let resource_task = ResourceTask();
        // If we are emitting an output file, then we need to block on
        // image load or we risk emitting an output file missing the
        // image.
        let image_cache_task = if opts.output_file.is_some() {
                SyncImageCacheTask(resource_task.clone())
            } else {
                ImageCacheTask(resource_task.clone())
            };
        let constellation_chan = Constellation::start(compositor_chan,
                                                      opts,
                                                      resource_task,
                                                      image_cache_task,
                                                      profiler_chan_clone);

        // Send the URL command to the constellation.
        for filename in opts.urls.iter() {
            let url = if filename.starts_with("data:") {
                // As a hack for easier command-line testing,
                // assume that data URLs are not URL-encoded.
                Url::new(~"data", None, ~"", None,
                    filename.slice_from(5).to_owned(), Vec::new(), None)
            } else {
                parse_url(*filename, None)
            };

            let ConstellationChan(ref chan) = constellation_chan;
            chan.send(InitLoadUrlMsg(url));
        }

        // Send the constallation Chan as the result
        result_chan.send(constellation_chan);
    });

    let constellation_chan = result_port.recv();

    debug!("preparing to enter main loop");
    CompositorTask::create(opts,
                           compositor_port,
                           constellation_chan,
                           profiler_chan);

    pool.shutdown();
}

<commit_msg>auto merge of #2148 : larsbergstrom/servo/android_201404c, r=metajack<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/. */

#[crate_id = "github.com/mozilla/servo"];
#[comment = "The Servo Parallel Browser Project"];
#[license = "MPL"];

#[feature(globs, macro_rules, phase, thread_local)];

#[feature(phase)];
#[phase(syntax, link)]
extern crate log;

extern crate alert;
extern crate azure;
extern crate geom;
extern crate gfx;
#[cfg(not(target_os="android"))]
extern crate glfw = "glfw-rs";
#[cfg(target_os="android")]
extern crate glut;
extern crate js;
extern crate layers;
extern crate opengles;
extern crate png;
extern crate rustuv;
extern crate script;
#[phase(syntax)]
extern crate servo_macros = "macros";
extern crate servo_net = "net";
extern crate servo_msg = "msg";
extern crate servo_util = "util";
extern crate style;
extern crate sharegl;
extern crate stb_image;

extern crate collections;
extern crate green;
extern crate native;
extern crate serialize;
extern crate sync;
extern crate time;
extern crate url;

#[cfg(target_os="macos")]
extern crate core_graphics;
#[cfg(target_os="macos")]
extern crate core_text;

#[cfg(not(test))]
use compositing::{CompositorChan, CompositorTask};
#[cfg(not(test))]
use constellation::Constellation;
#[cfg(not(test))]
use servo_msg::constellation_msg::{ConstellationChan, InitLoadUrlMsg};

#[cfg(not(test))]
use servo_net::image_cache_task::{ImageCacheTask, SyncImageCacheTask};
#[cfg(not(test))]
use servo_net::resource_task::ResourceTask;
#[cfg(not(test))]
use servo_util::time::Profiler;

#[cfg(not(test))]
use servo_util::opts;
#[cfg(not(test))]
use servo_util::url::parse_url;

#[cfg(not(test), not(target_os="android"))]
use std::os;
#[cfg(not(test), target_os="android")]
use std::str;
#[cfg(not(test))]
use std::task::TaskOpts;
#[cfg(not(test))]
use url::Url;

#[path="compositing/compositor_task.rs"]
pub mod compositing;

pub mod css {
    mod node_util;

    pub mod select;
    pub mod matching;
    pub mod node_style;
}

pub mod constellation;
pub mod pipeline;

pub mod layout {
    pub mod block;
    pub mod box_;
    pub mod construct;
    pub mod context;
    pub mod display_list_builder;
    pub mod floats;
    pub mod flow;
    pub mod flow_list;
    pub mod layout_task;
    pub mod inline;
    pub mod model;
    pub mod parallel;
    pub mod table_wrapper;
    pub mod table;
    pub mod table_caption;
    pub mod table_colgroup;
    pub mod table_rowgroup;
    pub mod table_row;
    pub mod table_cell;
    pub mod text;
    pub mod util;
    pub mod incremental;
    pub mod wrapper;
    pub mod extra;
}

pub mod windowing;

#[path="platform/mod.rs"]
pub mod platform;

#[cfg(not(test), target_os="linux")]
#[cfg(not(test), target_os="macos")]
#[start]
fn start(argc: int, argv: **u8) -> int {
    native::start(argc, argv, proc() {
        opts::from_cmdline_args(os::args()).map(run);
    })
}

#[cfg(not(test), target_os="android")]
#[no_mangle]
pub extern "C" fn android_start(argc: int, argv: **u8) -> int {
    native::start(argc, argv, proc() {
        let mut args:~[~str] = ~[];
        for i in range(0u, argc as uint) {
            unsafe {
                args.push(str::raw::from_c_str(*argv.offset(i as int) as *i8));
            }
        }

        let mut opts = opts::from_cmdline_args(args);
        match opts {
            Some(mut o) => {
                // Always use CPU rendering on android.
                o.cpu_painting = true;
                run(o);
            },
            None => {}
        }
    })
}

#[cfg(not(test))]
fn run(opts: opts::Opts) {
    let mut pool = green::SchedPool::new(green::PoolConfig::new());

    let (compositor_port, compositor_chan) = CompositorChan::new();
    let profiler_chan = Profiler::create(opts.profiler_period);

    let opts_clone = opts.clone();
    let profiler_chan_clone = profiler_chan.clone();

    let (result_chan, result_port) = channel();
    pool.spawn(TaskOpts::new(), proc() {
        let opts = &opts_clone;
        // Create a Servo instance.
        let resource_task = ResourceTask();
        // If we are emitting an output file, then we need to block on
        // image load or we risk emitting an output file missing the
        // image.
        let image_cache_task = if opts.output_file.is_some() {
                SyncImageCacheTask(resource_task.clone())
            } else {
                ImageCacheTask(resource_task.clone())
            };
        let constellation_chan = Constellation::start(compositor_chan,
                                                      opts,
                                                      resource_task,
                                                      image_cache_task,
                                                      profiler_chan_clone);

        // Send the URL command to the constellation.
        for filename in opts.urls.iter() {
            let url = if filename.starts_with("data:") {
                // As a hack for easier command-line testing,
                // assume that data URLs are not URL-encoded.
                Url::new(~"data", None, ~"", None,
                    filename.slice_from(5).to_owned(), Vec::new(), None)
            } else {
                parse_url(*filename, None)
            };

            let ConstellationChan(ref chan) = constellation_chan;
            chan.send(InitLoadUrlMsg(url));
        }

        // Send the constallation Chan as the result
        result_chan.send(constellation_chan);
    });

    let constellation_chan = result_port.recv();

    debug!("preparing to enter main loop");
    CompositorTask::create(opts,
                           compositor_port,
                           constellation_chan,
                           profiler_chan);

    pool.shutdown();
}

<|endoftext|>


<commit_before>#![doc(hidden)]

macro_rules! doc_comment {
    ($x:expr, $($tt:tt)*) => {
        #[doc = $x]
        $($tt)*
    };
}

macro_rules! int_module {
    ($T:ident) => (int_module!($T, #[stable(feature = "rust1", since = "1.0.0")]););
    ($T:ident, #[$attr:meta]) => (
        doc_comment! {
            concat!("The smallest value that can be represented by this integer type.
Use [`", stringify!($T), "::MIN", "`](../../std/primitive.", stringify!($T), ".html#associatedconstant.MIN) instead."),
            #[$attr]
            pub const MIN: $T = $T::MIN;
        }

        doc_comment! {
            concat!("The largest value that can be represented by this integer type.
Use [`", stringify!($T), "::MAX", "`](../../std/primitive.", stringify!($T), ".html#associatedconstant.MAX) instead."),
            #[$attr]
            pub const MAX: $T = $T::MAX;
        }
    )
}
<commit_msg>Add examples to int macros<commit_after>#![doc(hidden)]

macro_rules! doc_comment {
    ($x:expr, $($tt:tt)*) => {
        #[doc = $x]
        $($tt)*
    };
}

macro_rules! int_module {
    ($T:ident) => (int_module!($T, #[stable(feature = "rust1", since = "1.0.0")]););
    ($T:ident, #[$attr:meta]) => (
        doc_comment! {
            concat!("The smallest value that can be represented by this integer type.
Use [`", stringify!($T), "::MIN", "`](../../std/primitive.", stringify!($T), ".html#associatedconstant.MIN) instead.

# Examples

```rust
// deprecated way
let min = std::", stringify!($T), "::MIN;

// intended way
let min = ", stringify!($T), "::MIN;
```
"),
            #[$attr]
            pub const MIN: $T = $T::MIN;
        }

        doc_comment! {
            concat!("The largest value that can be represented by this integer type.
Use [`", stringify!($T), "::MAX", "`](../../std/primitive.", stringify!($T), ".html#associatedconstant.MAX) instead.

# Examples

```rust
// deprecated way
let max = std::", stringify!($T), "::MAX;

// intended way
let max = ", stringify!($T), "::MAX;
```
"),
            #[$attr]
            pub const MAX: $T = $T::MAX;
        }
    )
}
<|endoftext|>


<commit_before>use super::allocator::Allocator;

// Bunch of different heaps as the tests run concurrently
static mut TEST_HEAP_0: [u8; 1000] = [0; 1000];
static mut TEST_HEAP_1: [u8; 1000] = [0; 1000];
static mut TEST_HEAP_2: [u8; 1000] = [0; 1000];
static mut TEST_HEAP_3: [u8; 1000] = [0; 1000];
static mut TEST_HEAP_4: [u8; 1000] = [0; 1000];
static mut TEST_HEAP_5: [u8; 1000] = [0; 1000];

// Alloc tests

#[test]
fn alloc_0() {
    let mut allocator = unsafe { Allocator::new(&mut TEST_HEAP_0, 1000) };
    let _ = allocator.alloc(26, 0);
}

#[test]
fn alloc_1() {
    let mut allocator = unsafe { Allocator::new(&mut TEST_HEAP_1, 1000) };

    // Allocate the entire heap
    for _ in 0..10 {
        let _ = allocator.alloc(100 - ::core::mem::size_of::<::block::Block>(), 0);
    }
}

#[test]
#[should_panic(expected = "Out Of Memory")]
fn panics_on_oom_0() {
    let mut allocator = unsafe { Allocator::new(&mut TEST_HEAP_2, 1000) };
    let _ = allocator.alloc(1001, 0);
}

#[test]
#[should_panic(expected = "Out Of Memory")]
fn panics_on_oom_1() {
    let mut allocator = unsafe { Allocator::new(&mut TEST_HEAP_3, 1000) };

    // Allocate the entire heap
    for _ in 0..10 {
        let _ = allocator.alloc(100 - ::core::mem::size_of::<::block::Block>(), 0);
    }

    // And OOM it...
    let _ = allocator.alloc(1, 0);
}

// Dealloc tests

#[test]
fn dealloc_0() {
    let mut allocator = unsafe { Allocator::new(&mut TEST_HEAP_4, 1000) };
    let size = 100 - ::core::mem::size_of::<::block::Block>();

    // Allocate some memory
    let p1 = allocator.alloc(size, 0);

    // Deallocate it...
    allocator.dealloc(p1.unwrap(), size, 0);
}

#[test]
fn dealloc_1() {
    let mut allocator = unsafe { Allocator::new(&mut TEST_HEAP_5, 1000) };
    let size = 500 - ::core::mem::size_of::<::block::Block>();

    // Allocate the entire heap in two allocs
    let p1 = allocator.alloc(size, 0);
    let _ = allocator.alloc(size, 0);

    // Deallocate the first
    allocator.dealloc(p1.unwrap(), size, 0);

    // Try to reallocate the same memory freed from p1
    let _ = allocator.alloc(size, 0);
}
<commit_msg>Added tests for alloc_opsys::realloc and realloc_inplace<commit_after>use super::allocator::Allocator;

// Bunch of different heaps as the tests run concurrently
const HEAP_SIZE: usize = 1000;

// Alloc tests

#[test]
fn alloc_0() {
    let mut heap = [0; HEAP_SIZE];
    let mut allocator = Allocator::new(&mut heap, HEAP_SIZE);
    let _ = allocator.alloc(26, 0);
}

#[test]
fn alloc_1() {
    let mut heap = [0; HEAP_SIZE];
    let mut allocator = Allocator::new(&mut heap, HEAP_SIZE);

    // Allocate the entire heap
    for _ in 0..10 {
        let _ = allocator.alloc(100 - ::core::mem::size_of::<::block::Block>(), 0);
    }
}

#[test]
#[should_panic(expected = "Out Of Memory")]
fn panics_on_oom_0() {
    let mut heap = [0; HEAP_SIZE];
    let mut allocator = Allocator::new(&mut heap, HEAP_SIZE);
    let _ = allocator.alloc(1001, 0);
}

#[test]
#[should_panic(expected = "Out Of Memory")]
fn panics_on_oom_1() {
    let mut heap = [0; HEAP_SIZE];
    let mut allocator = Allocator::new(&mut heap, HEAP_SIZE);

    // Allocate the entire heap
    for _ in 0..10 {
        let _ = allocator.alloc(100 - ::core::mem::size_of::<::block::Block>(), 0);
    }

    // And OOM it...
    let _ = allocator.alloc(1, 0);
}

// Dealloc tests

#[test]
fn dealloc_0() {
    let mut heap = [0; HEAP_SIZE];
    let mut allocator = Allocator::new(&mut heap, HEAP_SIZE);

    let size = 100 - ::core::mem::size_of::<::block::Block>();

    // Allocate some memory
    let p1 = allocator.alloc(size, 0);

    // Deallocate it...
    allocator.dealloc(p1.unwrap(), size, 0);
}

#[test]
fn dealloc_1() {
    let mut heap = [0; HEAP_SIZE];
    let mut allocator = Allocator::new(&mut heap, HEAP_SIZE);

    let size = 500 - ::core::mem::size_of::<::block::Block>();

    // Allocate the entire heap in two allocs
    let p1 = allocator.alloc(size, 0);
    let _ = allocator.alloc(size, 0);

    // Deallocate the first
    allocator.dealloc(p1.unwrap(), size, 0);

    // Try to reallocate the same memory freed from p1
    let _ = allocator.alloc(size, 0);
}

#[test]
fn usable_size_0() {
    // This will change in the future but for now just test that it returns the size
    // we asked for
    let mut heap = [0; HEAP_SIZE];
    let mut allocator = Allocator::new(&mut heap, HEAP_SIZE);

    let size = 100;
    let align = 0;

    let _ = allocator.alloc(size, 0);
    assert!(allocator.usable_size(size, align) == size);
}

#[test]
fn realloc_0() {
    // Should be able to allocate one thing, then reallocate it an unlimited number of times
    let mut heap = [0; HEAP_SIZE];
    let mut allocator = Allocator::new(&mut heap, HEAP_SIZE);

    let size = 100;
    let mut ptr = allocator.alloc(size, 0).unwrap();

    for _ in 1..500 {
        let new_ptr = allocator.realloc(ptr, size, size, 0).unwrap();
        ptr = new_ptr;
    }
}

#[test]
#[should_panic(expected = "Out Of Memory")]
fn realloc_1() {
    // This test should currently panic because the memory will become fragmented into lots of
    // small blocks. When mereging is implemented this should be fixed.
    let mut heap = [0; HEAP_SIZE];
    let mut allocator = Allocator::new(&mut heap, HEAP_SIZE);

    let size = 100;
    let mut ptr = allocator.alloc(size, 0).unwrap();

    for i in 1..500 {
        let new_ptr = allocator.realloc(ptr, size + i - 1, size + i, 0).unwrap();
        ptr = new_ptr;
    }
}

#[test]
fn realloc_inplace_0() {
    // For now this do nothing...
    let mut heap = [0; HEAP_SIZE];
    let mut allocator = Allocator::new(&mut heap, HEAP_SIZE);

    let size = 10;
    let ptr = allocator.alloc(size, 0).unwrap();
    assert!(allocator.realloc_inplace(ptr, size, 100, 0) == size);
}
<|endoftext|>


<commit_before>use std::net::ToSocketAddrs;
use std::convert::AsRef;
use std::net;
use std::io::Write;
use rustc_serialize::Encodable;
use time;
use retry::retry;
use record::Record;
use record::FluentError;
use retry_conf::RetryConf;

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Fluent
    where A: ToSocketAddrs
{
    addr: A,
    tag: String,
    conf: RetryConf,
}

impl Fluent {
    /// Create Fluent type.
    ///
    /// ### Usage
    ///
    /// ```
    /// use fruently::fluent::Fluent;
    /// let fruently_with_str_tag = Fluent::new("0.0.0.0:24224", "test");
    /// let fruently_with_string_tag = Fluent::new("0.0.0.0:24224", "test".to_string());
    /// ```
    pub fn new<T>(addr: A, tag: T) -> Fluent
        where T: AsRef<str>
    {
        Fluent {
            addr: addr,
            tag: format!("{}", tag.as_ref()),
            conf: RetryConf::new(),
        }
    }

    pub fn new_with_conf<T>(addr: A, tag: T, conf: RetryConf) -> Fluent
        where T: AsRef<str>
    {
        Fluent {
            addr: addr,
            tag: format!("{}", tag.as_ref()),
            conf: conf,
        }
    }

    /// Post record into Fluentd. Without time version.
    pub fn post<T>(self, record: T) -> Result<(), FluentError>
        where T: Encodable
    {
        let time = time::now();
        return self.post_with_time(record, time);
    }

    /// Post record into Fluentd. With time version.
    pub fn post_with_time<T>(self, record: T, time: time::Tm) -> Result<(), FluentError>
        where T: Encodable
    {
        let record = Record::new(self.tag.clone(), time, record);
        let message = try!(record.make_forwardable_json());
        let addr = self.addr;
        let (max, timeout) = self.conf.build();
        match retry(max, timeout, || Fluent::closure_send_data(&addr, message.clone()), |response| response.is_ok()) {
            Ok(_) => Ok(()),
            Err(v) => Err(From::from(v)),
        }
    }

    fn closure_send_data(addr: &A, message: String) -> Result<(), FluentError> {
        let mut stream = try!(net::TcpStream::connect(addr));
        let result = stream.write(&message.into_bytes());
        drop(stream);

        match result {
            Ok(_) => Ok(()),
            Err(v) => Err(From::from(v)),
        }
    }
}

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

    #[test]
    fn create_fruently() {
        let fruently = Fluent::new("0.0.0.0:24224", "test");
        let expected = Fluent {
            addr: "0.0.0.0:24224",
            tag: "test".to_string(),
            conf: RetryConf::new(),
        };
        assert_eq!(expected, fruently);
    }

    #[test]
    #[cfg(feature="fluentd")]
    fn test_post() {
        use std::collections::HashMap;

        let fruently = Fluent::new("0.0.0.0:24224", "test");
        let mut obj: HashMap<String, String> = HashMap::new();
        obj.insert("hey".to_string(), "Rust!".to_string());
        let result = fruently.post(obj);
        let is_ok = match result {
            Ok(()) => true,
            _ => false,
        };
        assert_eq!(true, is_ok);
    }

    #[test]
    #[cfg(feature="fluentd")]
    fn test_post_with_time() {
        use std::collections::HashMap;

        let fruently = Fluent::new("0.0.0.0:24224", "test");
        let mut obj: HashMap<String, String> = HashMap::new();
        obj.insert("hey".to_string(), "Rust!".to_string());
        let time = time::now();
        let result = fruently.post_with_time(obj, time);
        let is_ok = match result {
            Ok(()) => true,
            _ => false,
        };
        assert_eq!(true, is_ok);
    }
}
<commit_msg>fluent test: Add a missing cfg attribute<commit_after>use std::net::ToSocketAddrs;
use std::convert::AsRef;
use std::net;
use std::io::Write;
use rustc_serialize::Encodable;
use time;
use retry::retry;
use record::Record;
use record::FluentError;
use retry_conf::RetryConf;

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Fluent
    where A: ToSocketAddrs
{
    addr: A,
    tag: String,
    conf: RetryConf,
}

impl Fluent {
    /// Create Fluent type.
    ///
    /// ### Usage
    ///
    /// ```
    /// use fruently::fluent::Fluent;
    /// let fruently_with_str_tag = Fluent::new("0.0.0.0:24224", "test");
    /// let fruently_with_string_tag = Fluent::new("0.0.0.0:24224", "test".to_string());
    /// ```
    pub fn new<T>(addr: A, tag: T) -> Fluent
        where T: AsRef<str>
    {
        Fluent {
            addr: addr,
            tag: format!("{}", tag.as_ref()),
            conf: RetryConf::new(),
        }
    }

    pub fn new_with_conf<T>(addr: A, tag: T, conf: RetryConf) -> Fluent
        where T: AsRef<str>
    {
        Fluent {
            addr: addr,
            tag: format!("{}", tag.as_ref()),
            conf: conf,
        }
    }

    /// Post record into Fluentd. Without time version.
    pub fn post<T>(self, record: T) -> Result<(), FluentError>
        where T: Encodable
    {
        let time = time::now();
        return self.post_with_time(record, time);
    }

    /// Post record into Fluentd. With time version.
    pub fn post_with_time<T>(self, record: T, time: time::Tm) -> Result<(), FluentError>
        where T: Encodable
    {
        let record = Record::new(self.tag.clone(), time, record);
        let message = try!(record.make_forwardable_json());
        let addr = self.addr;
        let (max, timeout) = self.conf.build();
        match retry(max, timeout, || Fluent::closure_send_data(&addr, message.clone()), |response| response.is_ok()) {
            Ok(_) => Ok(()),
            Err(v) => Err(From::from(v)),
        }
    }

    fn closure_send_data(addr: &A, message: String) -> Result<(), FluentError> {
        let mut stream = try!(net::TcpStream::connect(addr));
        let result = stream.write(&message.into_bytes());
        drop(stream);

        match result {
            Ok(_) => Ok(()),
            Err(v) => Err(From::from(v)),
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    #[cfg(feature="fluentd")]
    use time;
    use retry_conf::RetryConf;

    #[test]
    fn create_fruently() {
        let fruently = Fluent::new("0.0.0.0:24224", "test");
        let expected = Fluent {
            addr: "0.0.0.0:24224",
            tag: "test".to_string(),
            conf: RetryConf::new(),
        };
        assert_eq!(expected, fruently);
    }

    #[test]
    #[cfg(feature="fluentd")]
    fn test_post() {
        use std::collections::HashMap;

        let fruently = Fluent::new("0.0.0.0:24224", "test");
        let mut obj: HashMap<String, String> = HashMap::new();
        obj.insert("hey".to_string(), "Rust!".to_string());
        let result = fruently.post(obj);
        let is_ok = match result {
            Ok(()) => true,
            _ => false,
        };
        assert_eq!(true, is_ok);
    }

    #[test]
    #[cfg(feature="fluentd")]
    fn test_post_with_time() {
        use std::collections::HashMap;

        let fruently = Fluent::new("0.0.0.0:24224", "test");
        let mut obj: HashMap<String, String> = HashMap::new();
        obj.insert("hey".to_string(), "Rust!".to_string());
        let time = time::now();
        let result = fruently.post_with_time(obj, time);
        let is_ok = match result {
            Ok(()) => true,
            _ => false,
        };
        assert_eq!(true, is_ok);
    }
}
<|endoftext|>


<commit_before>use std::fmt;
use std::time::Duration;

use number_prefix::NumberPrefix;

const SECOND: Duration = Duration::from_secs(1);
const MINUTE: Duration = Duration::from_secs(60);
const HOUR: Duration = Duration::from_secs(60 * 60);
const DAY: Duration = Duration::from_secs(24 * 60 * 60);
const WEEK: Duration = Duration::from_secs(7 * 24 * 60 * 60);
const YEAR: Duration = Duration::from_secs(365 * 24 * 60 * 60);

/// Wraps an std duration for human basic formatting.
#[derive(Debug)]
pub struct FormattedDuration(pub Duration);

/// Wraps an std duration for human readable formatting.
#[derive(Debug)]
pub struct HumanDuration(pub Duration);

/// Formats bytes for human readability
#[derive(Debug)]
pub struct HumanBytes(pub u64);

/// Formats bytes for human readability using SI prefixes
#[derive(Debug)]
pub struct DecimalBytes(pub u64);

/// Formats bytes for human readability using ISO/IEC prefixes
#[derive(Debug)]
pub struct BinaryBytes(pub u64);

impl fmt::Display for FormattedDuration {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        let mut t = self.0.as_secs();
        let seconds = t % 60;
        t /= 60;
        let minutes = t % 60;
        t /= 60;
        let hours = t % 24;
        t /= 24;
        if t > 0 {
            let days = t;
            write!(f, "{}d {:02}:{:02}:{:02}", days, hours, minutes, seconds)
        } else {
            write!(f, "{:02}:{:02}:{:02}", hours, minutes, seconds)
        }
    }
}

// `HumanDuration` should be as intuitively understandable as possible.
// So we want to round, not truncate: otherwise 1 hour and 59 minutes
// would display an ETA of "1 hour" which underestimates the time
// remaining by a factor 2.
//
// To make the precision more uniform, we avoid displaying "1 unit"
// (except for seconds), because it would be displayed for a relatively
// long duration compared to the unit itself. Instead, when we arrive
// around 1.5 unit, we change from "2 units" to the next smaller unit
// (e.g. "89 seconds").
//
// Formally:
// * for n >= 2, we go from "n+1 units" to "n units" exactly at (n + 1/2) units
// * we switch from "2 units" to the next smaller unit at (1.5 unit minus half of the next smaller unit)

const UNITS_NAMES_ALTS: &[(Duration, &str, &str)] = &[
    (YEAR, "year", "y"),
    (WEEK, "week", "w"),
    (DAY, "day", "d"),
    (HOUR, "hour", "h"),
    (MINUTE, "minute", "m"),
    (SECOND, "second", "s"),
];

impl fmt::Display for HumanDuration {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        // FIXME when `div_duration_f64` is stable
        let t = self.0.as_secs_f64();
        for ((unit, name, alt), (nextunit, _, _)) in
            UNITS_NAMES_ALTS.iter().zip(UNITS_NAMES_ALTS[1..].iter())
        {
            if self.0 + *nextunit / 2 >= *unit + *unit / 2 {
                let x = (t / unit.as_secs_f64()).round() as usize;
                return if f.alternate() {
                    write!(f, "{}{}", x.max(2), alt)
                } else {
                    write!(f, "{} {}s", x.max(2), name)
                };
            }
        }
        // unwrap is safe because it doesn't make sense to call
        // this function with an empty table of units
        let (unit, name, alt) = UNITS_NAMES_ALTS.last().unwrap();
        let x = (t / unit.as_secs_f64()).round() as usize;
        if f.alternate() {
            write!(f, "{}{}", x, alt)
        } else {
            write!(f, "{} {}{}", x, name, if x == 1 { "" } else { "s" })
        }
    }
}

impl fmt::Display for HumanBytes {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match NumberPrefix::binary(self.0 as f64) {
            NumberPrefix::Standalone(number) => write!(f, "{:.0}B", number),
            NumberPrefix::Prefixed(prefix, number) => write!(f, "{:.2}{}B", number, prefix),
        }
    }
}

impl fmt::Display for DecimalBytes {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match NumberPrefix::decimal(self.0 as f64) {
            NumberPrefix::Standalone(number) => write!(f, "{:.0}B", number),
            NumberPrefix::Prefixed(prefix, number) => write!(f, "{:.2}{}B", number, prefix),
        }
    }
}

impl fmt::Display for BinaryBytes {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match NumberPrefix::binary(self.0 as f64) {
            NumberPrefix::Standalone(number) => write!(f, "{:.0}B", number),
            NumberPrefix::Prefixed(prefix, number) => write!(f, "{:.2}{}B", number, prefix),
        }
    }
}

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

    const MILLI: Duration = Duration::from_millis(1);

    #[test]
    fn human_duration_alternate() {
        for (unit, _, alt) in UNITS_NAMES_ALTS {
            assert_eq!(
                format!("2{}", alt),
                format!("{:#}", HumanDuration(2 * *unit))
            );
        }
    }

    #[test]
    fn human_duration_less_than_one_second() {
        assert_eq!("0 seconds", format!("{}", HumanDuration(Duration::ZERO)));
        assert_eq!("0 seconds", format!("{}", HumanDuration(MILLI)));
        assert_eq!("0 seconds", format!("{}", HumanDuration(499 * MILLI)));
        assert_eq!("1 second", format!("{}", HumanDuration(500 * MILLI)));
        assert_eq!("1 second", format!("{}", HumanDuration(999 * MILLI)));
    }

    #[test]
    fn human_duration_less_than_two_seconds() {
        assert_eq!("1 second", format!("{}", HumanDuration(1499 * MILLI)));
        assert_eq!("2 seconds", format!("{}", HumanDuration(1500 * MILLI)));
        assert_eq!("2 seconds", format!("{}", HumanDuration(1999 * MILLI)));
    }

    #[test]
    fn human_duration_one_unit() {
        assert_eq!("1 second", format!("{}", HumanDuration(SECOND)));
        assert_eq!("60 seconds", format!("{}", HumanDuration(MINUTE)));
        assert_eq!("60 minutes", format!("{}", HumanDuration(HOUR)));
        assert_eq!("24 hours", format!("{}", HumanDuration(DAY)));
        assert_eq!("7 days", format!("{}", HumanDuration(WEEK)));
        assert_eq!("52 weeks", format!("{}", HumanDuration(YEAR)));
    }

    #[test]
    fn human_duration_less_than_one_and_a_half_unit() {
        // this one is actually done at 1.5 unit - half of the next smaller unit - epsilon
        // and should display the next smaller unit
        let d = HumanDuration(MINUTE + MINUTE / 2 - SECOND / 2 - MILLI);
        assert_eq!("89 seconds", format!("{}", d));
        let d = HumanDuration(HOUR + HOUR / 2 - MINUTE / 2 - MILLI);
        assert_eq!("89 minutes", format!("{}", d));
        let d = HumanDuration(DAY + DAY / 2 - HOUR / 2 - MILLI);
        assert_eq!("35 hours", format!("{}", d));
        let d = HumanDuration(WEEK + WEEK / 2 - DAY / 2 - MILLI);
        assert_eq!("10 days", format!("{}", d));
        let d = HumanDuration(YEAR + YEAR / 2 - WEEK / 2 - MILLI);
        assert_eq!("78 weeks", format!("{}", d));
    }

    #[test]
    fn human_duration_one_and_a_half_unit() {
        // this one is actually done at 1.5 unit - half of the next smaller unit
        // and should still display "2 units"
        let d = HumanDuration(MINUTE + MINUTE / 2 - SECOND / 2);
        assert_eq!("2 minutes", format!("{}", d));
        let d = HumanDuration(HOUR + HOUR / 2 - MINUTE / 2);
        assert_eq!("2 hours", format!("{}", d));
        let d = HumanDuration(DAY + DAY / 2 - HOUR / 2);
        assert_eq!("2 days", format!("{}", d));
        let d = HumanDuration(WEEK + WEEK / 2 - DAY / 2);
        assert_eq!("2 weeks", format!("{}", d));
        let d = HumanDuration(YEAR + YEAR / 2 - WEEK / 2);
        assert_eq!("2 years", format!("{}", d));
    }

    #[test]
    fn human_duration_two_units() {
        assert_eq!("2 seconds", format!("{}", HumanDuration(2 * SECOND)));
        assert_eq!("2 minutes", format!("{}", HumanDuration(2 * MINUTE)));
        assert_eq!("2 hours", format!("{}", HumanDuration(2 * HOUR)));
        assert_eq!("2 days", format!("{}", HumanDuration(2 * DAY)));
        assert_eq!("2 weeks", format!("{}", HumanDuration(2 * WEEK)));
        assert_eq!("2 years", format!("{}", HumanDuration(2 * YEAR)));
    }

    #[test]
    fn human_duration_less_than_two_and_a_half_units() {
        let d = HumanDuration(2 * SECOND + SECOND / 2 - MILLI);
        assert_eq!("2 seconds", format!("{}", d));
        let d = HumanDuration(2 * MINUTE + MINUTE / 2 - MILLI);
        assert_eq!("2 minutes", format!("{}", d));
        let d = HumanDuration(2 * HOUR + HOUR / 2 - MILLI);
        assert_eq!("2 hours", format!("{}", d));
        let d = HumanDuration(2 * DAY + DAY / 2 - MILLI);
        assert_eq!("2 days", format!("{}", d));
        let d = HumanDuration(2 * WEEK + WEEK / 2 - MILLI);
        assert_eq!("2 weeks", format!("{}", d));
        let d = HumanDuration(2 * YEAR + YEAR / 2 - MILLI);
        assert_eq!("2 years", format!("{}", d));
    }

    #[test]
    fn human_duration_two_and_a_half_units() {
        let d = HumanDuration(2 * SECOND + SECOND / 2);
        assert_eq!("3 seconds", format!("{}", d));
        let d = HumanDuration(2 * MINUTE + MINUTE / 2);
        assert_eq!("3 minutes", format!("{}", d));
        let d = HumanDuration(2 * HOUR + HOUR / 2);
        assert_eq!("3 hours", format!("{}", d));
        let d = HumanDuration(2 * DAY + DAY / 2);
        assert_eq!("3 days", format!("{}", d));
        let d = HumanDuration(2 * WEEK + WEEK / 2);
        assert_eq!("3 weeks", format!("{}", d));
        let d = HumanDuration(2 * YEAR + YEAR / 2);
        assert_eq!("3 years", format!("{}", d));
    }

    #[test]
    fn human_duration_three_units() {
        assert_eq!("3 seconds", format!("{}", HumanDuration(3 * SECOND)));
        assert_eq!("3 minutes", format!("{}", HumanDuration(3 * MINUTE)));
        assert_eq!("3 hours", format!("{}", HumanDuration(3 * HOUR)));
        assert_eq!("3 days", format!("{}", HumanDuration(3 * DAY)));
        assert_eq!("3 weeks", format!("{}", HumanDuration(3 * WEEK)));
        assert_eq!("3 years", format!("{}", HumanDuration(3 * YEAR)));
    }
}
<commit_msg>Simplify HumanDuration calculation somewhat<commit_after>use std::fmt;
use std::time::Duration;

use number_prefix::NumberPrefix;

const SECOND: Duration = Duration::from_secs(1);
const MINUTE: Duration = Duration::from_secs(60);
const HOUR: Duration = Duration::from_secs(60 * 60);
const DAY: Duration = Duration::from_secs(24 * 60 * 60);
const WEEK: Duration = Duration::from_secs(7 * 24 * 60 * 60);
const YEAR: Duration = Duration::from_secs(365 * 24 * 60 * 60);

/// Wraps an std duration for human basic formatting.
#[derive(Debug)]
pub struct FormattedDuration(pub Duration);

/// Wraps an std duration for human readable formatting.
#[derive(Debug)]
pub struct HumanDuration(pub Duration);

/// Formats bytes for human readability
#[derive(Debug)]
pub struct HumanBytes(pub u64);

/// Formats bytes for human readability using SI prefixes
#[derive(Debug)]
pub struct DecimalBytes(pub u64);

/// Formats bytes for human readability using ISO/IEC prefixes
#[derive(Debug)]
pub struct BinaryBytes(pub u64);

impl fmt::Display for FormattedDuration {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        let mut t = self.0.as_secs();
        let seconds = t % 60;
        t /= 60;
        let minutes = t % 60;
        t /= 60;
        let hours = t % 24;
        t /= 24;
        if t > 0 {
            let days = t;
            write!(f, "{}d {:02}:{:02}:{:02}", days, hours, minutes, seconds)
        } else {
            write!(f, "{:02}:{:02}:{:02}", hours, minutes, seconds)
        }
    }
}

// `HumanDuration` should be as intuitively understandable as possible.
// So we want to round, not truncate: otherwise 1 hour and 59 minutes
// would display an ETA of "1 hour" which underestimates the time
// remaining by a factor 2.
//
// To make the precision more uniform, we avoid displaying "1 unit"
// (except for seconds), because it would be displayed for a relatively
// long duration compared to the unit itself. Instead, when we arrive
// around 1.5 unit, we change from "2 units" to the next smaller unit
// (e.g. "89 seconds").
//
// Formally:
// * for n >= 2, we go from "n+1 units" to "n units" exactly at (n + 1/2) units
// * we switch from "2 units" to the next smaller unit at (1.5 unit minus half of the next smaller unit)

impl fmt::Display for HumanDuration {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        let mut idx = 0;
        for (i, &(cur, _, _)) in UNITS.iter().enumerate() {
            idx = i;
            match UNITS.get(i + 1) {
                Some(&next) if self.0 + next.0 / 2 >= cur + cur / 2 => break,
                _ => continue,
            }
        }

        let (unit, name, alt) = UNITS[idx];
        // FIXME when `div_duration_f64` is stable
        let mut t = (self.0.as_secs_f64() / unit.as_secs_f64()).round() as usize;
        if idx < UNITS.len() - 1 {
            t = Ord::max(t, 2);
        }

        match (f.alternate(), t) {
            (true, _) => write!(f, "{}{}", t, alt),
            (false, 1) => write!(f, "{} {}", t, name),
            (false, _) => write!(f, "{} {}s", t, name),
        }
    }
}

const UNITS: &[(Duration, &str, &str)] = &[
    (YEAR, "year", "y"),
    (WEEK, "week", "w"),
    (DAY, "day", "d"),
    (HOUR, "hour", "h"),
    (MINUTE, "minute", "m"),
    (SECOND, "second", "s"),
];

impl fmt::Display for HumanBytes {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match NumberPrefix::binary(self.0 as f64) {
            NumberPrefix::Standalone(number) => write!(f, "{:.0}B", number),
            NumberPrefix::Prefixed(prefix, number) => write!(f, "{:.2}{}B", number, prefix),
        }
    }
}

impl fmt::Display for DecimalBytes {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match NumberPrefix::decimal(self.0 as f64) {
            NumberPrefix::Standalone(number) => write!(f, "{:.0}B", number),
            NumberPrefix::Prefixed(prefix, number) => write!(f, "{:.2}{}B", number, prefix),
        }
    }
}

impl fmt::Display for BinaryBytes {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match NumberPrefix::binary(self.0 as f64) {
            NumberPrefix::Standalone(number) => write!(f, "{:.0}B", number),
            NumberPrefix::Prefixed(prefix, number) => write!(f, "{:.2}{}B", number, prefix),
        }
    }
}

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

    const MILLI: Duration = Duration::from_millis(1);

    #[test]
    fn human_duration_alternate() {
        for (unit, _, alt) in UNITS {
            assert_eq!(
                format!("2{}", alt),
                format!("{:#}", HumanDuration(2 * *unit))
            );
        }
    }

    #[test]
    fn human_duration_less_than_one_second() {
        assert_eq!("0 seconds", format!("{}", HumanDuration(Duration::ZERO)));
        assert_eq!("0 seconds", format!("{}", HumanDuration(MILLI)));
        assert_eq!("0 seconds", format!("{}", HumanDuration(499 * MILLI)));
        assert_eq!("1 second", format!("{}", HumanDuration(500 * MILLI)));
        assert_eq!("1 second", format!("{}", HumanDuration(999 * MILLI)));
    }

    #[test]
    fn human_duration_less_than_two_seconds() {
        assert_eq!("1 second", format!("{}", HumanDuration(1499 * MILLI)));
        assert_eq!("2 seconds", format!("{}", HumanDuration(1500 * MILLI)));
        assert_eq!("2 seconds", format!("{}", HumanDuration(1999 * MILLI)));
    }

    #[test]
    fn human_duration_one_unit() {
        assert_eq!("1 second", format!("{}", HumanDuration(SECOND)));
        assert_eq!("60 seconds", format!("{}", HumanDuration(MINUTE)));
        assert_eq!("60 minutes", format!("{}", HumanDuration(HOUR)));
        assert_eq!("24 hours", format!("{}", HumanDuration(DAY)));
        assert_eq!("7 days", format!("{}", HumanDuration(WEEK)));
        assert_eq!("52 weeks", format!("{}", HumanDuration(YEAR)));
    }

    #[test]
    fn human_duration_less_than_one_and_a_half_unit() {
        // this one is actually done at 1.5 unit - half of the next smaller unit - epsilon
        // and should display the next smaller unit
        let d = HumanDuration(MINUTE + MINUTE / 2 - SECOND / 2 - MILLI);
        assert_eq!("89 seconds", format!("{}", d));
        let d = HumanDuration(HOUR + HOUR / 2 - MINUTE / 2 - MILLI);
        assert_eq!("89 minutes", format!("{}", d));
        let d = HumanDuration(DAY + DAY / 2 - HOUR / 2 - MILLI);
        assert_eq!("35 hours", format!("{}", d));
        let d = HumanDuration(WEEK + WEEK / 2 - DAY / 2 - MILLI);
        assert_eq!("10 days", format!("{}", d));
        let d = HumanDuration(YEAR + YEAR / 2 - WEEK / 2 - MILLI);
        assert_eq!("78 weeks", format!("{}", d));
    }

    #[test]
    fn human_duration_one_and_a_half_unit() {
        // this one is actually done at 1.5 unit - half of the next smaller unit
        // and should still display "2 units"
        let d = HumanDuration(MINUTE + MINUTE / 2 - SECOND / 2);
        assert_eq!("2 minutes", format!("{}", d));
        let d = HumanDuration(HOUR + HOUR / 2 - MINUTE / 2);
        assert_eq!("2 hours", format!("{}", d));
        let d = HumanDuration(DAY + DAY / 2 - HOUR / 2);
        assert_eq!("2 days", format!("{}", d));
        let d = HumanDuration(WEEK + WEEK / 2 - DAY / 2);
        assert_eq!("2 weeks", format!("{}", d));
        let d = HumanDuration(YEAR + YEAR / 2 - WEEK / 2);
        assert_eq!("2 years", format!("{}", d));
    }

    #[test]
    fn human_duration_two_units() {
        assert_eq!("2 seconds", format!("{}", HumanDuration(2 * SECOND)));
        assert_eq!("2 minutes", format!("{}", HumanDuration(2 * MINUTE)));
        assert_eq!("2 hours", format!("{}", HumanDuration(2 * HOUR)));
        assert_eq!("2 days", format!("{}", HumanDuration(2 * DAY)));
        assert_eq!("2 weeks", format!("{}", HumanDuration(2 * WEEK)));
        assert_eq!("2 years", format!("{}", HumanDuration(2 * YEAR)));
    }

    #[test]
    fn human_duration_less_than_two_and_a_half_units() {
        let d = HumanDuration(2 * SECOND + SECOND / 2 - MILLI);
        assert_eq!("2 seconds", format!("{}", d));
        let d = HumanDuration(2 * MINUTE + MINUTE / 2 - MILLI);
        assert_eq!("2 minutes", format!("{}", d));
        let d = HumanDuration(2 * HOUR + HOUR / 2 - MILLI);
        assert_eq!("2 hours", format!("{}", d));
        let d = HumanDuration(2 * DAY + DAY / 2 - MILLI);
        assert_eq!("2 days", format!("{}", d));
        let d = HumanDuration(2 * WEEK + WEEK / 2 - MILLI);
        assert_eq!("2 weeks", format!("{}", d));
        let d = HumanDuration(2 * YEAR + YEAR / 2 - MILLI);
        assert_eq!("2 years", format!("{}", d));
    }

    #[test]
    fn human_duration_two_and_a_half_units() {
        let d = HumanDuration(2 * SECOND + SECOND / 2);
        assert_eq!("3 seconds", format!("{}", d));
        let d = HumanDuration(2 * MINUTE + MINUTE / 2);
        assert_eq!("3 minutes", format!("{}", d));
        let d = HumanDuration(2 * HOUR + HOUR / 2);
        assert_eq!("3 hours", format!("{}", d));
        let d = HumanDuration(2 * DAY + DAY / 2);
        assert_eq!("3 days", format!("{}", d));
        let d = HumanDuration(2 * WEEK + WEEK / 2);
        assert_eq!("3 weeks", format!("{}", d));
        let d = HumanDuration(2 * YEAR + YEAR / 2);
        assert_eq!("3 years", format!("{}", d));
    }

    #[test]
    fn human_duration_three_units() {
        assert_eq!("3 seconds", format!("{}", HumanDuration(3 * SECOND)));
        assert_eq!("3 minutes", format!("{}", HumanDuration(3 * MINUTE)));
        assert_eq!("3 hours", format!("{}", HumanDuration(3 * HOUR)));
        assert_eq!("3 days", format!("{}", HumanDuration(3 * DAY)));
        assert_eq!("3 weeks", format!("{}", HumanDuration(3 * WEEK)));
        assert_eq!("3 years", format!("{}", HumanDuration(3 * YEAR)));
    }
}
<|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 devtools_traits::{ConsoleMessage, LogLevel, ScriptToDevtoolsControlMsg};
use dom::bindings::inheritance::Castable;
use dom::bindings::str::DOMString;
use dom::globalscope::GlobalScope;
use dom::workerglobalscope::WorkerGlobalScope;

// https://developer.mozilla.org/en-US/docs/Web/API/Console
pub struct Console(());

impl Console {
    fn send_to_devtools(global: &GlobalScope, level: LogLevel, message: DOMString) {
        if let Some(chan) = global.devtools_chan() {
            let console_message = prepare_message(level, message);
            let worker_id = global.downcast::<WorkerGlobalScope>().map(|worker| {
                worker.get_worker_id()
            });
            let devtools_message = ScriptToDevtoolsControlMsg::ConsoleAPI(
                global.pipeline_id(),
                console_message,
                worker_id);
            chan.send(devtools_message).unwrap();
        }
    }
}

impl Console {
    // https://developer.mozilla.org/en-US/docs/Web/API/Console/log
    pub fn Log(global: &GlobalScope, messages: Vec<DOMString>) {
        for message in messages {
            println!("{}", message);
            Self::send_to_devtools(global, LogLevel::Log, message);
        }
    }

    // https://developer.mozilla.org/en-US/docs/Web/API/Console
    pub fn Debug(global: &GlobalScope, messages: Vec<DOMString>) {
        for message in messages {
            println!("{}", message);
            Self::send_to_devtools(global, LogLevel::Debug, message);
        }
    }

    // https://developer.mozilla.org/en-US/docs/Web/API/Console/info
    pub fn Info(global: &GlobalScope, messages: Vec<DOMString>) {
        for message in messages {
            println!("{}", message);
            Self::send_to_devtools(global, LogLevel::Info, message);
        }
    }

    // https://developer.mozilla.org/en-US/docs/Web/API/Console/warn
    pub fn Warn(global: &GlobalScope, messages: Vec<DOMString>) {
        for message in messages {
            println!("{}", message);
            Self::send_to_devtools(global, LogLevel::Warn, message);
        }
    }

    // https://developer.mozilla.org/en-US/docs/Web/API/Console/error
    pub fn Error(global: &GlobalScope, messages: Vec<DOMString>) {
        for message in messages {
            println!("{}", message);
            Self::send_to_devtools(global, LogLevel::Error, message);
        }
    }

    // https://developer.mozilla.org/en-US/docs/Web/API/Console/assert
    pub fn Assert(global: &GlobalScope, condition: bool, message: Option<DOMString>) {
        if !condition {
            let message = message.unwrap_or_else(|| DOMString::from("no message"));
            println!("Assertion failed: {}", message);
            Self::send_to_devtools(global, LogLevel::Error, message);
        }
    }

    // https://developer.mozilla.org/en-US/docs/Web/API/Console/time
    pub fn Time(global: &GlobalScope, label: DOMString) {
        if let Ok(()) = global.time(label.clone()) {
            let message = DOMString::from(format!("{}: timer started", label));
            println!("{}", message);
            Self::send_to_devtools(global, LogLevel::Log, message);
        }
    }

    // https://developer.mozilla.org/en-US/docs/Web/API/Console/timeEnd
    pub fn TimeEnd(global: &GlobalScope, label: DOMString) {
        if let Ok(delta) = global.time_end(&label) {
            let message = DOMString::from(
                format!("{}: {}ms", label, delta)
            );
            println!("{}", message);
            Self::send_to_devtools(global, LogLevel::Log, message);
        };
    }
}

fn prepare_message(log_level: LogLevel, message: DOMString) -> ConsoleMessage {
    // TODO: Sending fake values for filename, lineNumber and columnNumber in LogMessage; adjust later
    ConsoleMessage {
        message: String::from(message),
        logLevel: log_level,
        filename: "test".to_owned(),
        lineNumber: 1,
        columnNumber: 1,
    }
}
<commit_msg>Auto merge of #17360 - servo:stderr, r=emilio<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 devtools_traits::{ConsoleMessage, LogLevel, ScriptToDevtoolsControlMsg};
use dom::bindings::inheritance::Castable;
use dom::bindings::str::DOMString;
use dom::globalscope::GlobalScope;
use dom::workerglobalscope::WorkerGlobalScope;
use std::io;

// https://developer.mozilla.org/en-US/docs/Web/API/Console
pub struct Console(());

impl Console {
    fn send_to_devtools(global: &GlobalScope, level: LogLevel, message: DOMString) {
        if let Some(chan) = global.devtools_chan() {
            let console_message = prepare_message(level, message);
            let worker_id = global.downcast::<WorkerGlobalScope>().map(|worker| {
                worker.get_worker_id()
            });
            let devtools_message = ScriptToDevtoolsControlMsg::ConsoleAPI(
                global.pipeline_id(),
                console_message,
                worker_id);
            chan.send(devtools_message).unwrap();
        }
    }
}

// In order to avoid interleaving the stdout output of the Console API methods
// with stderr that could be in use on other threads, we lock stderr until
// we're finished with stdout. Since the stderr lock is reentrant, there is
// no risk of deadlock if the callback ends up trying to write to stderr for
// any reason.
fn with_stderr_lock<F>(f: F) where F: FnOnce() {
    let stderr = io::stderr();
    let _handle = stderr.lock();
    f()
}

impl Console {
    // https://developer.mozilla.org/en-US/docs/Web/API/Console/log
    pub fn Log(global: &GlobalScope, messages: Vec<DOMString>) {
        with_stderr_lock(move || {
            for message in messages {
                println!("{}", message);
                Self::send_to_devtools(global, LogLevel::Log, message);
            }
        })
    }

    // https://developer.mozilla.org/en-US/docs/Web/API/Console
    pub fn Debug(global: &GlobalScope, messages: Vec<DOMString>) {
        with_stderr_lock(move || {
            for message in messages {
                println!("{}", message);
                Self::send_to_devtools(global, LogLevel::Debug, message);
            }
        })
    }

    // https://developer.mozilla.org/en-US/docs/Web/API/Console/info
    pub fn Info(global: &GlobalScope, messages: Vec<DOMString>) {
        with_stderr_lock(move || {
            for message in messages {
                println!("{}", message);
                Self::send_to_devtools(global, LogLevel::Info, message);
            }
        })
    }

    // https://developer.mozilla.org/en-US/docs/Web/API/Console/warn
    pub fn Warn(global: &GlobalScope, messages: Vec<DOMString>) {
        with_stderr_lock(move || {
            for message in messages {
                println!("{}", message);
                Self::send_to_devtools(global, LogLevel::Warn, message);
            }
        })
    }

    // https://developer.mozilla.org/en-US/docs/Web/API/Console/error
    pub fn Error(global: &GlobalScope, messages: Vec<DOMString>) {
        with_stderr_lock(move || {
            for message in messages {
                println!("{}", message);
                Self::send_to_devtools(global, LogLevel::Error, message);
            }
        })
    }

    // https://developer.mozilla.org/en-US/docs/Web/API/Console/assert
    pub fn Assert(global: &GlobalScope, condition: bool, message: Option<DOMString>) {
        with_stderr_lock(move || {
            if !condition {
                let message = message.unwrap_or_else(|| DOMString::from("no message"));
                println!("Assertion failed: {}", message);
                Self::send_to_devtools(global, LogLevel::Error, message);
            }
        })
    }

    // https://developer.mozilla.org/en-US/docs/Web/API/Console/time
    pub fn Time(global: &GlobalScope, label: DOMString) {
        with_stderr_lock(move || {
            if let Ok(()) = global.time(label.clone()) {
                let message = DOMString::from(format!("{}: timer started", label));
                println!("{}", message);
                Self::send_to_devtools(global, LogLevel::Log, message);
            }
        })
    }

    // https://developer.mozilla.org/en-US/docs/Web/API/Console/timeEnd
    pub fn TimeEnd(global: &GlobalScope, label: DOMString) {
        with_stderr_lock(move || {
            if let Ok(delta) = global.time_end(&label) {
                let message = DOMString::from(
                    format!("{}: {}ms", label, delta)
                );
                println!("{}", message);
                Self::send_to_devtools(global, LogLevel::Log, message);
            };
        })
    }
}

fn prepare_message(log_level: LogLevel, message: DOMString) -> ConsoleMessage {
    // TODO: Sending fake values for filename, lineNumber and columnNumber in LogMessage; adjust later
    ConsoleMessage {
        message: String::from(message),
        logLevel: log_level,
        filename: "test".to_owned(),
        lineNumber: 1,
        columnNumber: 1,
    }
}
<|endoftext|>