<commit_before>use std::any::Any;
use std::ffi::CString;
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 crate::prelude::*;

use crate::backend::{Emit, WriteDebugInfo};

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

    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);

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

    run_aot(tcx, metadata, need_metadata_module)
}

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

    // Rustc opens us without the RTLD_GLOBAL flag, so __cg_clif_global_atomic_mutex will not be
    // exported. We fix this by opening ourself again as global.
    // FIXME remove once atomic_shim is gone
    let cg_dylib = std::ffi::OsString::from(&tcx.sess.opts.debugging_opts.codegen_backend.as_ref().unwrap());
    std::mem::forget(libloading::os::unix::Library::open(Some(cg_dylib), libc::RTLD_NOW | libc::RTLD_GLOBAL).unwrap());

    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::triple_default(&crate::target_triple(tcx.sess)),
    };
    let main_func_id = jit_module
        .declare_function("main", Linkage::Import, &sig)
        .unwrap();

    codegen_cgus(tcx, &mut jit_module, &mut None);
    crate::allocator::codegen(tcx, &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.dependency_formats(LOCAL_CRATE);
    let data = &formats
        .iter()
        .find(|(crate_type, _data)| *crate_type == CrateType::Executable)
        .unwrap()
        .1;
    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 dlsym_name = if cfg!(target_os = "macos") {
                // On macOS `dlsym` expects the name without leading `_`.
                assert!(name.starts_with("_"), "{:?}", name);
                &name[1..]
            } else {
                &name
            };
            let symbol: libloading::Symbol<*const u8> =
                unsafe { lib.get(dlsym_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,
) -> Box<CodegenResults> {
    let new_module = |name: String| {
        let module = crate::backend::make_module(tcx.sess, name);
        assert_eq!(pointer_ty(tcx), module.target_config().pointer_type());
        module
    };

    fn emit_module<B: Backend>(
        tcx: TyCtxt<'_>,
        name: String,
        kind: ModuleKind,
        mut module: Module<B>,
        debug: Option<DebugContext>,
    ) -> CompiledModule
        where B::Product: Emit + WriteDebugInfo,
    {
            module.finalize_definitions();
            let mut product = module.finish();

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

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

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

    let mut debug = if tcx.sess.opts.debuginfo != DebugInfo::None {
        let debug = DebugContext::new(
            tcx,
            module.target_config().pointer_type().bytes() as u8,
        );
        Some(debug)
    } else {
        None
    };

    codegen_cgus(tcx, &mut module, &mut debug);

    tcx.sess.abort_if_errors();

    let mut allocator_module = new_module("allocator_shim".to_string());
    let created_alloc_shim = crate::allocator::codegen(tcx, &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 {
        let _timer = tcx.prof.generic_activity("codegen crate metadata");
        let (metadata_cgu_name, tmp_file) = tcx.sess.time("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 tmp_file = tcx
                .output_filenames(LOCAL_CRATE)
                .temp_path(OutputType::Metadata, Some(&metadata_cgu_name));

            let obj = crate::backend::with_object(tcx.sess, &metadata_cgu_name, |object| {
                crate::metadata::write_metadata(tcx, object);
            });

            std::fs::write(&tmp_file, obj).unwrap();

            (metadata_cgu_name, tmp_file)
        });

        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(
            tcx,
            "some_file".to_string(),
            ModuleKind::Regular,
            module,
            debug,
        )],
        allocator_module: if created_alloc_shim {
            Some(emit_module(
                tcx,
                "allocator_shim".to_string(),
                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>>,
) {
    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(), 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>>,
    mono_items: FxHashMap<MonoItem<'tcx>, (RLinkage, Visibility)>,
) {
    let mut cx = CodegenCx::new(tcx, module, debug_context);

    time(tcx.sess, "codegen mono items", move || {
        tcx.sess.time("predefine functions", || {
            for (&mono_item, &(linkage, visibility)) in &mono_items {
                match mono_item {
                    MonoItem::Fn(instance) => {
                        let (name, sig) =
                            get_function_name_and_sig(tcx, cx.module.isa().triple(), instance, false);
                        let linkage = crate::linkage::get_clif_linkage(mono_item, linkage, visibility);
                        cx.module.declare_function(&name, linkage, &sig).unwrap();
                    }
                    MonoItem::Static(_) | MonoItem::GlobalAsm(_) => {}
                }
            }
        });

        for (mono_item, (linkage, visibility)) in mono_items {
            crate::unimpl::try_unimpl(tcx, || {
                let linkage = crate::linkage::get_clif_linkage(mono_item, linkage, visibility);
                trans_mono_item(&mut cx, mono_item, linkage);
            });
        }

        tcx.sess.time("finalize CodegenCx", || 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))
                    }
                }
            });

            cx.tcx.sess.time("codegen fn", || crate::base::trans_fn(cx, inst, linkage));
        }
        MonoItem::Static(def_id) => {
            crate::constant::codegen_static(&mut cx.constants_cx, def_id);
        }
        MonoItem::GlobalAsm(hir_id) => {
            let item = tcx.hir().expect_item(hir_id);
            if let rustc_hir::ItemKind::GlobalAsm(rustc_hir::GlobalAsm { asm }) = item.kind {
                // FIXME implement global asm using an external assembler
                if asm.as_str().contains("__rust_probestack") {
                    return;
                } else {
                    tcx
                        .sess
                        .fatal(&format!("Unimplemented global asm mono item \"{}\"", asm));
                }
            } else {
                bug!("Expected GlobalAsm found {:?}", item);
            }
        }
    }
}

fn time<R>(sess: &Session, name: &'static str, f: impl FnOnce() -> R) -> R {
    println!("[{}] start", name);
    let before = std::time::Instant::now();
    let res = sess.time(name, f);
    let after = std::time::Instant::now();
    println!("[{}] end time: {:?}", name, after - before);
    res
}
<commit_msg>Inline codegen_cgus<commit_after>use std::any::Any;
use std::ffi::CString;
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 crate::prelude::*;

use crate::backend::{Emit, WriteDebugInfo};

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

    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);

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

    run_aot(tcx, metadata, need_metadata_module)
}

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

    // Rustc opens us without the RTLD_GLOBAL flag, so __cg_clif_global_atomic_mutex will not be
    // exported. We fix this by opening ourself again as global.
    // FIXME remove once atomic_shim is gone
    let cg_dylib = std::ffi::OsString::from(&tcx.sess.opts.debugging_opts.codegen_backend.as_ref().unwrap());
    std::mem::forget(libloading::os::unix::Library::open(Some(cg_dylib), libc::RTLD_NOW | libc::RTLD_GLOBAL).unwrap());

    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::triple_default(&crate::target_triple(tcx.sess)),
    };
    let main_func_id = jit_module
        .declare_function("main", Linkage::Import, &sig)
        .unwrap();

    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, &mut jit_module, None, mono_items);
    crate::main_shim::maybe_create_entry_wrapper(tcx, &mut jit_module);
    crate::allocator::codegen(tcx, &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.dependency_formats(LOCAL_CRATE);
    let data = &formats
        .iter()
        .find(|(crate_type, _data)| *crate_type == CrateType::Executable)
        .unwrap()
        .1;
    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 dlsym_name = if cfg!(target_os = "macos") {
                // On macOS `dlsym` expects the name without leading `_`.
                assert!(name.starts_with("_"), "{:?}", name);
                &name[1..]
            } else {
                &name
            };
            let symbol: libloading::Symbol<*const u8> =
                unsafe { lib.get(dlsym_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,
) -> Box<CodegenResults> {
    let new_module = |name: String| {
        let module = crate::backend::make_module(tcx.sess, name);
        assert_eq!(pointer_ty(tcx), module.target_config().pointer_type());
        module
    };

    fn emit_module<B: Backend>(
        tcx: TyCtxt<'_>,
        name: String,
        kind: ModuleKind,
        mut module: Module<B>,
        debug: Option<DebugContext>,
    ) -> CompiledModule
        where B::Product: Emit + WriteDebugInfo,
    {
            module.finalize_definitions();
            let mut product = module.finish();

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

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

    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<_, (_, _)>>();

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

    let mut debug = if tcx.sess.opts.debuginfo != DebugInfo::None {
        let debug = DebugContext::new(
            tcx,
            module.target_config().pointer_type().bytes() as u8,
        );
        Some(debug)
    } else {
        None
    };

    codegen_mono_items(tcx, &mut module, debug.as_mut(), mono_items);
    crate::main_shim::maybe_create_entry_wrapper(tcx, &mut module);

    tcx.sess.abort_if_errors();

    let mut allocator_module = new_module("allocator_shim".to_string());
    let created_alloc_shim = crate::allocator::codegen(tcx, &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 {
        let _timer = tcx.prof.generic_activity("codegen crate metadata");
        let (metadata_cgu_name, tmp_file) = tcx.sess.time("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 tmp_file = tcx
                .output_filenames(LOCAL_CRATE)
                .temp_path(OutputType::Metadata, Some(&metadata_cgu_name));

            let obj = crate::backend::with_object(tcx.sess, &metadata_cgu_name, |object| {
                crate::metadata::write_metadata(tcx, object);
            });

            std::fs::write(&tmp_file, obj).unwrap();

            (metadata_cgu_name, tmp_file)
        });

        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(
            tcx,
            "some_file".to_string(),
            ModuleKind::Regular,
            module,
            debug,
        )],
        allocator_module: if created_alloc_shim {
            Some(emit_module(
                tcx,
                "allocator_shim".to_string(),
                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_mono_items<'tcx>(
    tcx: TyCtxt<'tcx>,
    module: &mut Module<impl Backend + 'static>,
    debug_context: Option<&mut DebugContext<'tcx>>,
    mono_items: FxHashMap<MonoItem<'tcx>, (RLinkage, Visibility)>,
) {
    let mut cx = CodegenCx::new(tcx, module, debug_context);

    time(tcx.sess, "codegen mono items", move || {
        tcx.sess.time("predefine functions", || {
            for (&mono_item, &(linkage, visibility)) in &mono_items {
                match mono_item {
                    MonoItem::Fn(instance) => {
                        let (name, sig) =
                            get_function_name_and_sig(tcx, cx.module.isa().triple(), instance, false);
                        let linkage = crate::linkage::get_clif_linkage(mono_item, linkage, visibility);
                        cx.module.declare_function(&name, linkage, &sig).unwrap();
                    }
                    MonoItem::Static(_) | MonoItem::GlobalAsm(_) => {}
                }
            }
        });

        for (mono_item, (linkage, visibility)) in mono_items {
            crate::unimpl::try_unimpl(tcx, || {
                let linkage = crate::linkage::get_clif_linkage(mono_item, linkage, visibility);
                trans_mono_item(&mut cx, mono_item, linkage);
            });
        }

        tcx.sess.time("finalize CodegenCx", || 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))
                    }
                }
            });

            cx.tcx.sess.time("codegen fn", || crate::base::trans_fn(cx, inst, linkage));
        }
        MonoItem::Static(def_id) => {
            crate::constant::codegen_static(&mut cx.constants_cx, def_id);
        }
        MonoItem::GlobalAsm(hir_id) => {
            let item = tcx.hir().expect_item(hir_id);
            if let rustc_hir::ItemKind::GlobalAsm(rustc_hir::GlobalAsm { asm }) = item.kind {
                // FIXME implement global asm using an external assembler
                if asm.as_str().contains("__rust_probestack") {
                    return;
                } else {
                    tcx
                        .sess
                        .fatal(&format!("Unimplemented global asm mono item \"{}\"", asm));
                }
            } else {
                bug!("Expected GlobalAsm found {:?}", item);
            }
        }
    }
}

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


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

const COM1 : u16 = 0x3f8;

pub fn earlyinit () {
	super::x86asm::outb(COM1+2 , 0);
	super::x86asm::outb(COM1+3, 0x80);    // Unlock divisor
	super::x86asm::outb(COM1+0, 12);
	super::x86asm::outb(COM1+1, 0);
	super::x86asm::outb(COM1+3, 0x03);    // Lock divisor, 8 data bits.
	super::x86asm::outb(COM1+4, 0);
	super::x86asm::outb(COM1+1, 0x01);    // Enable receive interrupts.

	let r = super::x86asm::inb(COM1+5);

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

use super::x86asm::outb;
use super::x86asm::inb;

const COM1 : u16 = 0x3f8;

pub fn earlyinit () {
	outb(COM1+2 , 0);
	outb(COM1+3, 0x80);    // Unlock divisor
	outb(COM1+0, 12);
	outb(COM1+1, 0);
	outb(COM1+3, 0x03);    // Lock divisor, 8 data bits.
	outb(COM1+4, 0);
	outb(COM1+1, 0x01);    // Enable receive interrupts.

	inb(COM1+5);

	outb(COM1, 66);
}
<|endoftext|>


<commit_before>use std;
use std::ops::{BitAnd, BitOr, Shr, Shl};

// Emulate a 128 bit uint using two 64 bit uints. When the i128 feature
// is stable this can be removed.

#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub struct emu128 {
    pub hi: u64,
    pub lo: u64,
}

// TODO: Proper testing to make sure these functions work correctly.

impl emu128 {
    pub fn min_value() -> emu128 {
        emu128 { hi: 0, lo: 0 }
    }

    pub fn max_value() -> emu128 {
        emu128 { hi: std::u64::MAX, lo: std::u64::MAX }
    }

    pub fn saturating_add(self, other: emu128) -> emu128 {
        let (lo, ov) = self.lo.overflowing_add(other.lo);
        let res = self.hi.checked_add(other.hi).and_then(|x| x.checked_add(if ov { 1 } else { 0 }));
        match res {
            Some(hi) => emu128 { hi: hi, lo: lo },
            None => emu128::max_value(),
        }
    }

    pub fn saturating_sub(self, other: emu128) -> emu128 {
        let (lo, ov) = self.lo.overflowing_sub(other.lo);
        let res = self.hi.checked_sub(other.hi).and_then(|x| x.checked_sub(if ov { 1 } else { 0 }));
        match res {
            Some(hi) => emu128 { hi: hi, lo: lo },
            None => emu128::min_value(),
        }
    }

    pub fn leading_zeros(self) -> u32 {
        if self.hi > 0 { self.hi.leading_zeros() } else { self.lo.leading_zeros() + 64 }
    }

    pub fn trailing_zeros(self) -> u32 {
        if self.lo > 0 { self.lo.trailing_zeros() } else { self.hi.trailing_zeros() + 64 }
    }
}

// TODO: Convert to macro to implement for other RHS types.
impl Shl<u8> for emu128 {
    type Output = Self;

    fn shl(self, rhs: u8) -> emu128 {
        if rhs < 64 {
            emu128 {
                hi: self.hi << rhs | self.lo >> (64-rhs),
                lo: self.lo << rhs
            }
        }
        else {
            emu128 {
                hi: self.lo << (rhs-64),
                lo: 0
            }
        }
    }
}

impl Shr<u8> for emu128 {
    type Output = Self;

    fn shr(self, rhs: u8) -> emu128 {
        if rhs < 64 {
            emu128 {
                hi: self.hi >> rhs,
                lo: self.lo >> rhs | self.hi << (64-rhs),
            }
        }
        else {
            emu128 {
                hi: 0,
                lo: self.hi >> (rhs-64),
            }
        }
    }
}

impl BitAnd for emu128 {
    type Output = Self;

    fn bitand(self, rhs: emu128) -> emu128 {
        emu128 {
            hi: self.hi & rhs.hi,
            lo: self.lo & rhs.lo,
        }
    }
}

impl BitOr for emu128 {
    type Output = Self;

    fn bitor(self, rhs: emu128) -> emu128 {
        emu128 {
            hi: self.hi | rhs.hi,
            lo: self.lo | rhs.lo,
        }
    }
}
<commit_msg>Adding documentation.<commit_after>//! An emulated 128 bit unsigned integer.
//!
//! This module provides [`emu128`], a 128 bit unsigned integer emulated
//! from two standard `u64` types. This is useful for operations on IPv6
//! address, which are 128 bit unsigned integers at heart.
//!
//! `emu128` only implements operations that have been useful for
//! building the `Ipv6Net` type. It's not intended to be a full `u128`
//! implementation.
//!
//! # TODO:
//!
//! * Implement proper tests to ensure these methods work correctly.
//! * Convert implementations to macro's to reduce duplication and
//!   implement across all other potential RHS types.
//!
//! [`emu128`]: struct.emu128.html

use std;
use std::ops::{BitAnd, BitOr, Shr, Shl};

/// Emulate a 128 bit uint using two 64 bit uints. When the i128 feature
/// is stable this can be removed.
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub struct emu128 {
    pub hi: u64,
    pub lo: u64,
}

impl emu128 {
    pub fn min_value() -> emu128 {
        emu128 { hi: 0, lo: 0 }
    }

    pub fn max_value() -> emu128 {
        emu128 { hi: std::u64::MAX, lo: std::u64::MAX }
    }

    pub fn saturating_add(self, other: emu128) -> emu128 {
        let (lo, ov) = self.lo.overflowing_add(other.lo);
        let res = self.hi.checked_add(other.hi).and_then(|x| x.checked_add(if ov { 1 } else { 0 }));
        match res {
            Some(hi) => emu128 { hi: hi, lo: lo },
            None => emu128::max_value(),
        }
    }

    pub fn saturating_sub(self, other: emu128) -> emu128 {
        let (lo, ov) = self.lo.overflowing_sub(other.lo);
        let res = self.hi.checked_sub(other.hi).and_then(|x| x.checked_sub(if ov { 1 } else { 0 }));
        match res {
            Some(hi) => emu128 { hi: hi, lo: lo },
            None => emu128::min_value(),
        }
    }

    pub fn leading_zeros(self) -> u32 {
        if self.hi > 0 { self.hi.leading_zeros() } else { self.lo.leading_zeros() + 64 }
    }

    pub fn trailing_zeros(self) -> u32 {
        if self.lo > 0 { self.lo.trailing_zeros() } else { self.hi.trailing_zeros() + 64 }
    }
}

impl Shl<u8> for emu128 {
    type Output = Self;

    fn shl(self, rhs: u8) -> emu128 {
        if rhs < 64 {
            emu128 {
                hi: self.hi << rhs | self.lo >> (64-rhs),
                lo: self.lo << rhs
            }
        }
        else {
            emu128 {
                hi: self.lo << (rhs-64),
                lo: 0
            }
        }
    }
}

impl Shr<u8> for emu128 {
    type Output = Self;

    fn shr(self, rhs: u8) -> emu128 {
        if rhs < 64 {
            emu128 {
                hi: self.hi >> rhs,
                lo: self.lo >> rhs | self.hi << (64-rhs),
            }
        }
        else {
            emu128 {
                hi: 0,
                lo: self.hi >> (rhs-64),
            }
        }
    }
}

impl BitAnd for emu128 {
    type Output = Self;

    fn bitand(self, rhs: emu128) -> emu128 {
        emu128 {
            hi: self.hi & rhs.hi,
            lo: self.lo & rhs.lo,
        }
    }
}

impl BitOr for emu128 {
    type Output = Self;

    fn bitor(self, rhs: emu128) -> emu128 {
        emu128 {
            hi: self.hi | rhs.hi,
            lo: self.lo | rhs.lo,
        }
    }
}
<|endoftext|>


<commit_before>pub enum OscError {
    BadOscPacket(String),
    BadOscAddress(String),
    BadOscMessage(String),
    BadOscBundle,
}
<commit_msg>Add BadOscString error type<commit_after>pub enum OscError {
    BadOscPacket(String),
    BadOscAddress(String),
    BadOscMessage(String),
    BadOscString(String),
    BadOscBundle,
}
<|endoftext|>


<commit_before>#![cfg(feature = "parsing")]

use nom::{self, IResult};

pub fn escaped_string(input: &str) -> IResult<&str, String> {
    let mut s = String::new();
    let mut chars = input.char_indices().peekable();
    while let Some((byte_offset, ch)) = chars.next() {
        match ch {
            '"' => {
                return IResult::Done(&input[byte_offset..], s);
            }
            '\\' => {
                match chars.next() {
                    Some((_, 'x')) => unimplemented!(),
                    Some((_, 'n')) => s.push('\n'),
                    Some((_, 'r')) => s.push('\r'),
                    Some((_, 't')) => s.push('\t'),
                    Some((_, '\\')) => s.push('\\'),
                    Some((_, '0')) => s.push('\0'),
                    Some((_, 'u')) => unimplemented!(),
                    Some((_, '\'')) => s.push('\''),
                    Some((_, '"')) => s.push('"'),
                    Some((_, '\n')) => {
                        while let Some(&(_, ch)) = chars.peek() {
                            if ch.is_whitespace() {
                                chars.next();
                            } else {
                                break;
                            }
                        }
                    }
                    _ => break,
                }
            }
            ch => {
                s.push(ch);
            }
        }
    }
    IResult::Error(nom::Err::Position(nom::ErrorKind::Escaped, input))
}
<commit_msg>Implement \x and \u escape sequences<commit_after>#![cfg(feature = "parsing")]

use std::{char, str};
use nom::{self, IResult};

pub fn escaped_string(input: &str) -> IResult<&str, String> {
    let mut s = String::new();
    let mut chars = input.char_indices().peekable();
    while let Some((byte_offset, ch)) = chars.next() {
        match ch {
            '"' => {
                return IResult::Done(&input[byte_offset..], s);
            }
            '\\' => {
                match chars.next() {
                    Some((_, 'x')) => match backslash_x(&mut chars) {
                        Some(ch) => s.push(ch),
                        None => break,
                    },
                    Some((_, 'n')) => s.push('\n'),
                    Some((_, 'r')) => s.push('\r'),
                    Some((_, 't')) => s.push('\t'),
                    Some((_, '\\')) => s.push('\\'),
                    Some((_, '0')) => s.push('\0'),
                    Some((_, 'u')) => match backslash_u(&mut chars) {
                        Some(ch) => s.push(ch),
                        None => break,
                    },
                    Some((_, '\'')) => s.push('\''),
                    Some((_, '"')) => s.push('"'),
                    Some((_, '\n')) => {
                        while let Some(&(_, ch)) = chars.peek() {
                            if ch.is_whitespace() {
                                chars.next();
                            } else {
                                break;
                            }
                        }
                    }
                    _ => break,
                }
            }
            ch => {
                s.push(ch);
            }
        }
    }
    IResult::Error(nom::Err::Position(nom::ErrorKind::Escaped, input))
}

macro_rules! next_char {
    ($chars:ident @ $pat:pat $(| $rest:pat)*) => {
        match $chars.next() {
            Some((_, ch)) => match ch {
                $pat $(| $rest)*  => ch,
                _ => return None,
            },
            None => return None,
        }
    };
}

fn backslash_x<I>(chars: &mut I) -> Option<char> where I: Iterator<Item = (usize, char)> {
    let a = next_char!(chars @ '0'...'7');
    let b = next_char!(chars @ '0'...'9' | 'a'...'f' | 'A'...'F');
    char_from_hex_bytes(&[a as u8, b as u8])
}

fn backslash_u<I>(chars: &mut I) -> Option<char> where I: Iterator<Item = (usize, char)> {
    next_char!(chars @ '{');
    let a = next_char!(chars @ '0'...'9' | 'a'...'f' | 'A'...'F');
    let b = next_char!(chars @ '0'...'9' | 'a'...'f' | 'A'...'F' | '}');
    if b == '}' {
        return char_from_hex_bytes(&[a as u8]);
    }
    let c = next_char!(chars @ '0'...'9' | 'a'...'f' | 'A'...'F' | '}');
    if c == '}' {
        return char_from_hex_bytes(&[a as u8, b as u8]);
    }
    let d = next_char!(chars @ '0'...'9' | 'a'...'f' | 'A'...'F' | '}');
    if d == '}' {
        return char_from_hex_bytes(&[a as u8, b as u8, c as u8]);
    }
    let e = next_char!(chars @ '0'...'9' | 'a'...'f' | 'A'...'F' | '}');
    if e == '}' {
        return char_from_hex_bytes(&[a as u8, b as u8, c as u8, d as u8]);
    }
    let f = next_char!(chars @ '0'...'9' | 'a'...'f' | 'A'...'F' | '}');
    if f == '}' {
        return char_from_hex_bytes(&[a as u8, b as u8, c as u8, d as u8, e as u8]);
    }
    next_char!(chars @ '}');
    char_from_hex_bytes(&[a as u8, b as u8, c as u8, d as u8, e as u8, f as u8])
}

/// Assumes the bytes are all '0'...'9' | 'a'...'f' | 'A'...'F'.
fn char_from_hex_bytes(hex_bytes: &[u8]) -> Option<char> {
    let hex_str = unsafe { str::from_utf8_unchecked(hex_bytes) };
    char::from_u32(u32::from_str_radix(hex_str, 16).unwrap())
}

#[test]
fn test_escaped_string() {
    let input = r#"\x62 \u{7} \u{64} \u{bf5} \u{12ba} \u{1F395} \u{102345}""#;
    let expected = "\x62 \u{7} \u{64} \u{bf5} \u{12ba} \u{1F395} \u{102345}";
    assert_eq!(escaped_string(input), IResult::Done("\"", expected.to_string()));
}
<|endoftext|>


<commit_before>use std::convert::From;

use binding::class::{define_class, new_instance, define_method, define_singleton_method};
use binding::global::rb_cObject;
use binding::util::get_constant;
use types::{Callback, Value};
use util::create_arguments;

use super::any_object::AnyObject;
use super::traits::Object;

/// `Class`
#[derive(Debug, PartialEq)]
pub struct Class {
    value: Value
}

impl Class {
    // TODO: replace rb_cObject with optional superclass
    /// Creates a new `Class`.
    ///
    /// # Examples
    ///
    /// ```
    /// use ruru::{Class, VM};
    /// # VM::init();
    ///
    /// let class = Class::new("Hello");
    ///
    /// assert_eq!(class, Class::from_existing("Hello"));
    /// ```
    ///
    /// Ruby:
    ///
    /// ```ruby
    /// class Hello
    /// end
    ///
    /// # or
    ///
    /// Hello = Class.new
    /// ```
    pub fn new(name: &str) -> Self {
        Class {
            value: define_class(name, rb_cObject)
        }
    }

    // TODO: replace rb_cObject with optional class
    /// Retrieves an existing `Class` object.
    ///
    /// # Examples
    ///
    /// ```
    /// use ruru::{Class, VM};
    /// # VM::init();
    ///
    /// let class = Class::new("Hello");
    ///
    /// assert_eq!(class, Class::from_existing("Hello"));
    /// ```
    ///
    /// Ruby:
    ///
    /// ```ruby
    /// Hello
    ///
    /// # or
    ///
    /// Object.const_get('Hello')
    /// ```
    pub fn from_existing(name: &str) -> Self {
        Class {
            value: get_constant(name, rb_cObject)
        }
    }

    /// Creates a new instance of `Class`
    ///
    /// Arguments must be passed as a vector of `AnyObject` (see example).
    ///
    /// # Examples
    ///
    /// ```no_run
    /// use ruru::{Class, Fixnum};
    /// use ruru::traits::Object;
    ///
    /// // Without arguments
    /// Class::from_existing("Hello").new_instance(vec![]);
    ///
    /// // With arguments passing arguments to constructor
    /// let arguments = vec![
    ///     Fixnum::new(1).as_any_object(),
    ///     Fixnum::new(2).as_any_object()
    /// ];
    ///
    /// Class::from_existing("Worker").new_instance(arguments);
    /// ```
    ///
    /// Ruby:
    ///
    /// ```ruby
    /// Hello.new
    ///
    /// Worker.new(1, 2)
    /// ```
    pub fn new_instance(&self, arguments: Vec<AnyObject>) -> AnyObject {
        let (argc, argv) = create_arguments(arguments);
        let instance = new_instance(self.value(), argc, argv);

        AnyObject::from(instance)
    }

    /// Wraps calls to a class.
    ///
    /// Mostly used to have Ruby-like class definitions.
    ///
    /// # Examples
    ///
    /// ```no_run
    /// use ruru::types::Argc;
    /// use ruru::{AnyObject, Class, Fixnum, RString};
    ///
    /// #[no_mangle]
    /// pub extern fn greeting(_: Argc, _: *const AnyObject, _: AnyObject) -> RString {
    ///     RString::new("Greeting from class")
    /// }
    ///
    /// #[no_mangle]
    /// pub extern fn many_greetings(_: Argc, _: *const AnyObject, _: AnyObject) -> RString {
    ///     RString::new("Many greetings from instance")
    /// }
    ///
    /// fn main() {
    ///     Class::new("Hello").define(|itself| {
    ///         itself.def_self("greeting", many_greetings);
    ///         itself.def("many_greetings", greeting);
    ///     });
    /// }
    /// ```
    ///
    /// Ruby:
    ///
    /// ```ruby
    /// class Hello
    ///   def self.print_many_greetings
    ///     'Hello from class'
    ///   end
    ///
    ///   def print_greeting
    ///     'Hello from instance'
    ///   end
    /// end
    /// ```
    pub fn define<F: Fn(&mut Self)>(&mut self, f: F) -> &Self {
        f(self);

        self
    }

    /// Defines an instance method for given class.
    ///
    /// # Arguments
    ///
    /// - `name` is name of the Ruby method
    ///
    /// - `callback` is the function which will be called by MRI when the method is called inside
    ///    Ruby
    ///
    /// ## Callback
    ///
    /// `callback` must have the following signature:
    ///
    /// `pub type Callback<I: Object, O: Object> = extern fn(Argc, *const AnyObject, I) -> O;`
    ///
    /// The function must also have `#[no_mangle]` attribute.
    ///
    /// - First argument `argc: Argc` will receive the number of arguments passed to method
    ///
    /// - Second argument `argv: *const AnyObject` will receive the arguments passed to the method
    ///   as `AnyObject`s
    ///
    /// - Third value `itself: I` will receive the object which got the method call (Ruby `self`).
    ///   Can be any type which implements `Object` trait
    ///
    /// - Return type can be any type which implements `Object` trait
    ///
    /// If you need to receive and use arguments which are passed to the method, you can use
    /// `VM::parse_arguments()` function which processes a pointer to array (`*const AnyObject`)
    /// to a vector of `AnyObject`s (`Vec<AnyObject>`), see examples.
    ///
    /// # Examples
    ///
    /// ## Method receives no arguments
    ///
    /// In this case `argc` and `argv` can be ignored.
    ///
    /// Famous `String#blank?` example
    ///
    /// ```no_run
    /// use ruru::types::Argc;
    /// use ruru::{AnyObject, Boolean, Class, RString};
    ///
    /// use ruru::traits::Object;
    ///
    /// #[no_mangle]
    /// pub extern fn string_blank(_: Argc, _: *const AnyObject, itself: RString) -> Boolean {
    ///     Boolean::new(itself.to_string().chars().all(|c| c.is_whitespace()))
    /// }
    ///
    /// fn main() {
    ///     Class::from_existing("String").define_method("blank?", string_blank);
    /// }
    /// ```
    ///
    /// Ruby:
    ///
    /// ```ruby
    /// class String
    ///   def blank?
    ///     # simplified
    ///     self.chars.all? { |c| c == ' ' }
    ///   end
    /// end
    /// ```
    ///
    /// ## Method reveives arguments
    ///
    /// Arguments should be processed to vector using `VM::parse_arguments()`.
    ///
    /// ```no_run
    /// use ruru::types::Argc;
    /// use ruru::{AnyObject, Boolean, Class, RString, VM};
    ///
    /// #[no_mangle]
    /// pub extern fn string_eq(argc: Argc, argv: *const AnyObject, itself: RString) -> Boolean {
    ///     let argv = VM::parse_arguments(argc, argv);
    ///     let other_string = argv[0].as_string();
    ///
    ///     Boolean::new(itself.to_string() == other_string.to_string())
    /// }
    ///
    /// fn main() {
    ///     Class::from_existing("String").define_method("==", string_eq);
    /// }
    /// ```
    ///
    /// Ruby:
    ///
    /// ```ruby
    /// class String
    ///   def ==(other_string)
    ///     # simplified
    ///     self.chars == other_string.chars
    ///   end
    /// end
    /// ```
    pub fn define_method<I: Object, O: Object>(&mut self, name: &str, callback: Callback<I, O>) {
        define_method(self.value, name, callback);
    }

    /// Defines a class method for given class.
    ///
    /// Function has the same requirements as `define_method`.
    /// Also the same rules are applied for `callback` (see above).
    ///
    /// # Examples
    ///
    /// ```no_run
    /// use ruru::types::Argc;
    /// use ruru::{AnyObject, Class, Symbol, VM};
    ///
    /// #[no_mangle]
    /// pub extern fn symbol_from_string(argc: Argc, argv: *const AnyObject, itself: Class) -> Symbol {
    ///     let argv = VM::parse_arguments(argc, argv);
    ///     let string = argv[0].as_string();
    ///
    ///     Symbol::new(&string.to_string())
    /// }
    ///
    /// fn main() {
    ///     Class::from_existing("Symbol")
    ///         .define_singleton_method("from_string", symbol_from_string);
    /// }
    /// ```
    ///
    /// Ruby:
    ///
    /// ```ruby
    /// class Symbol
    ///   def self.from_string(string)
    ///     # simplified
    ///     string.to_sym
    ///   end
    /// end
    /// ```
    pub fn define_singleton_method<I: Object, O: Object>(&mut self, name: &str, callback: Callback<I, O>) {
        define_singleton_method(self.value, name, callback);
    }

    /// An alias for `define_method` (similar to Ruby syntax `def some_method`).
    pub fn def<I: Object, O: Object>(&mut self, name: &str, callback: Callback<I, O>) {
        self.define_method(name, callback);
    }

    /// An alias for `define_singleton_method` (similar to Ruby `def self.some_method`).
    pub fn def_self<I: Object, O: Object>(&mut self, name: &str, callback: Callback<I, O>) {
        self.define_singleton_method(name, callback);
    }
}

impl From<Value> for Class {
    fn from(value: Value) -> Self {
        Class {
            value: value
        }
    }
}

impl Object for Class {
    fn value(&self) -> Value {
        self.value
    }
}
<commit_msg>Fix typo in Class documentation<commit_after>use std::convert::From;

use binding::class::{define_class, new_instance, define_method, define_singleton_method};
use binding::global::rb_cObject;
use binding::util::get_constant;
use types::{Callback, Value};
use util::create_arguments;

use super::any_object::AnyObject;
use super::traits::Object;

/// `Class`
#[derive(Debug, PartialEq)]
pub struct Class {
    value: Value
}

impl Class {
    // TODO: replace rb_cObject with optional superclass
    /// Creates a new `Class`.
    ///
    /// # Examples
    ///
    /// ```
    /// use ruru::{Class, VM};
    /// # VM::init();
    ///
    /// let class = Class::new("Hello");
    ///
    /// assert_eq!(class, Class::from_existing("Hello"));
    /// ```
    ///
    /// Ruby:
    ///
    /// ```ruby
    /// class Hello
    /// end
    ///
    /// # or
    ///
    /// Hello = Class.new
    /// ```
    pub fn new(name: &str) -> Self {
        Class {
            value: define_class(name, rb_cObject)
        }
    }

    // TODO: replace rb_cObject with optional class
    /// Retrieves an existing `Class` object.
    ///
    /// # Examples
    ///
    /// ```
    /// use ruru::{Class, VM};
    /// # VM::init();
    ///
    /// let class = Class::new("Hello");
    ///
    /// assert_eq!(class, Class::from_existing("Hello"));
    /// ```
    ///
    /// Ruby:
    ///
    /// ```ruby
    /// Hello
    ///
    /// # or
    ///
    /// Object.const_get('Hello')
    /// ```
    pub fn from_existing(name: &str) -> Self {
        Class {
            value: get_constant(name, rb_cObject)
        }
    }

    /// Creates a new instance of `Class`
    ///
    /// Arguments must be passed as a vector of `AnyObject` (see example).
    ///
    /// # Examples
    ///
    /// ```no_run
    /// use ruru::{Class, Fixnum};
    /// use ruru::traits::Object;
    ///
    /// // Without arguments
    /// Class::from_existing("Hello").new_instance(vec![]);
    ///
    /// // With arguments passing arguments to constructor
    /// let arguments = vec![
    ///     Fixnum::new(1).as_any_object(),
    ///     Fixnum::new(2).as_any_object()
    /// ];
    ///
    /// Class::from_existing("Worker").new_instance(arguments);
    /// ```
    ///
    /// Ruby:
    ///
    /// ```ruby
    /// Hello.new
    ///
    /// Worker.new(1, 2)
    /// ```
    pub fn new_instance(&self, arguments: Vec<AnyObject>) -> AnyObject {
        let (argc, argv) = create_arguments(arguments);
        let instance = new_instance(self.value(), argc, argv);

        AnyObject::from(instance)
    }

    /// Wraps calls to a class.
    ///
    /// Mostly used to have Ruby-like class definitions.
    ///
    /// # Examples
    ///
    /// ```no_run
    /// use ruru::types::Argc;
    /// use ruru::{AnyObject, Class, Fixnum, RString};
    ///
    /// #[no_mangle]
    /// pub extern fn greeting(_: Argc, _: *const AnyObject, _: AnyObject) -> RString {
    ///     RString::new("Greeting from class")
    /// }
    ///
    /// #[no_mangle]
    /// pub extern fn many_greetings(_: Argc, _: *const AnyObject, _: AnyObject) -> RString {
    ///     RString::new("Many greetings from instance")
    /// }
    ///
    /// fn main() {
    ///     Class::new("Hello").define(|itself| {
    ///         itself.def_self("greeting", many_greetings);
    ///         itself.def("many_greetings", greeting);
    ///     });
    /// }
    /// ```
    ///
    /// Ruby:
    ///
    /// ```ruby
    /// class Hello
    ///   def self.print_many_greetings
    ///     'Hello from class'
    ///   end
    ///
    ///   def print_greeting
    ///     'Hello from instance'
    ///   end
    /// end
    /// ```
    pub fn define<F: Fn(&mut Self)>(&mut self, f: F) -> &Self {
        f(self);

        self
    }

    /// Defines an instance method for given class.
    ///
    /// # Arguments
    ///
    /// - `name` is name of the Ruby method
    ///
    /// - `callback` is the function which will be called by MRI when the method is called inside
    ///    Ruby
    ///
    /// ## Callback
    ///
    /// `callback` must have the following signature:
    ///
    /// `pub type Callback<I: Object, O: Object> = extern fn(Argc, *const AnyObject, I) -> O;`
    ///
    /// The function must also have `#[no_mangle]` attribute.
    ///
    /// - First argument `argc: Argc` will receive the number of arguments passed to method
    ///
    /// - Second argument `argv: *const AnyObject` will receive the arguments passed to the method
    ///   as `AnyObject`s
    ///
    /// - Third value `itself: I` will receive the object which got the method call (Ruby `self`).
    ///   Can be any type which implements `Object` trait
    ///
    /// - Return type can be any type which implements `Object` trait
    ///
    /// If you need to receive and use arguments which are passed to the method, you can use
    /// `VM::parse_arguments()` function which processes a pointer to array (`*const AnyObject`)
    /// to a vector of `AnyObject`s (`Vec<AnyObject>`), see examples.
    ///
    /// # Examples
    ///
    /// ## Method receives no arguments
    ///
    /// In this case `argc` and `argv` can be ignored.
    ///
    /// Famous `String#blank?` example
    ///
    /// ```no_run
    /// use ruru::types::Argc;
    /// use ruru::{AnyObject, Boolean, Class, RString};
    ///
    /// use ruru::traits::Object;
    ///
    /// #[no_mangle]
    /// pub extern fn string_blank(_: Argc, _: *const AnyObject, itself: RString) -> Boolean {
    ///     Boolean::new(itself.to_string().chars().all(|c| c.is_whitespace()))
    /// }
    ///
    /// fn main() {
    ///     Class::from_existing("String").define_method("blank?", string_blank);
    /// }
    /// ```
    ///
    /// Ruby:
    ///
    /// ```ruby
    /// class String
    ///   def blank?
    ///     # simplified
    ///     self.chars.all? { |c| c == ' ' }
    ///   end
    /// end
    /// ```
    ///
    /// ## Method receives arguments
    ///
    /// Arguments should be processed to vector using `VM::parse_arguments()`.
    ///
    /// ```no_run
    /// use ruru::types::Argc;
    /// use ruru::{AnyObject, Boolean, Class, RString, VM};
    ///
    /// #[no_mangle]
    /// pub extern fn string_eq(argc: Argc, argv: *const AnyObject, itself: RString) -> Boolean {
    ///     let argv = VM::parse_arguments(argc, argv);
    ///     let other_string = argv[0].as_string();
    ///
    ///     Boolean::new(itself.to_string() == other_string.to_string())
    /// }
    ///
    /// fn main() {
    ///     Class::from_existing("String").define_method("==", string_eq);
    /// }
    /// ```
    ///
    /// Ruby:
    ///
    /// ```ruby
    /// class String
    ///   def ==(other_string)
    ///     # simplified
    ///     self.chars == other_string.chars
    ///   end
    /// end
    /// ```
    pub fn define_method<I: Object, O: Object>(&mut self, name: &str, callback: Callback<I, O>) {
        define_method(self.value, name, callback);
    }

    /// Defines a class method for given class.
    ///
    /// Function has the same requirements as `define_method`.
    /// Also the same rules are applied for `callback` (see above).
    ///
    /// # Examples
    ///
    /// ```no_run
    /// use ruru::types::Argc;
    /// use ruru::{AnyObject, Class, Symbol, VM};
    ///
    /// #[no_mangle]
    /// pub extern fn symbol_from_string(argc: Argc, argv: *const AnyObject, itself: Class) -> Symbol {
    ///     let argv = VM::parse_arguments(argc, argv);
    ///     let string = argv[0].as_string();
    ///
    ///     Symbol::new(&string.to_string())
    /// }
    ///
    /// fn main() {
    ///     Class::from_existing("Symbol")
    ///         .define_singleton_method("from_string", symbol_from_string);
    /// }
    /// ```
    ///
    /// Ruby:
    ///
    /// ```ruby
    /// class Symbol
    ///   def self.from_string(string)
    ///     # simplified
    ///     string.to_sym
    ///   end
    /// end
    /// ```
    pub fn define_singleton_method<I: Object, O: Object>(&mut self, name: &str, callback: Callback<I, O>) {
        define_singleton_method(self.value, name, callback);
    }

    /// An alias for `define_method` (similar to Ruby syntax `def some_method`).
    pub fn def<I: Object, O: Object>(&mut self, name: &str, callback: Callback<I, O>) {
        self.define_method(name, callback);
    }

    /// An alias for `define_singleton_method` (similar to Ruby `def self.some_method`).
    pub fn def_self<I: Object, O: Object>(&mut self, name: &str, callback: Callback<I, O>) {
        self.define_singleton_method(name, callback);
    }
}

impl From<Value> for Class {
    fn from(value: Value) -> Self {
        Class {
            value: value
        }
    }
}

impl Object for Class {
    fn value(&self) -> Value {
        self.value
    }
}
<|endoftext|>


<commit_before>use crate::data::*;
use crate::view::View;
use clipboard::{ClipboardContext, ClipboardProvider};
use std::cmp;
use termion::event::{Event, Key, MouseButton, MouseEvent};

#[derive(Debug, Clone)]
pub enum State {
    Insert,
    Message,
    Prompt(String, String, PromptAction),
    Select(usize),
    Selected,
    Open(String),
    Exit,
}

#[derive(Debug, Clone)]
pub enum PromptAction {
    Save,
    ConfirmExit,
    Open,
    ConfirmOpen(String),
}

const SCROLL_FACTOR: usize = 2;

impl State {
    // Handles a Termion event, consuming the current state and returning the new state
    pub fn handle<T>(self, content: &mut T, view: &mut View, event: Event) -> Self
    where
        T: Editable + Saveable + Undoable + Selectable + Modifiable,
    {
        match self {
            State::Prompt(prompt, message, action) => {
                State::handle_prompt(content, view, event, prompt, message, action)
            }
            State::Select(origin) => State::handle_select(content, view, event, origin),
            State::Insert => State::handle_insert(content, view, event),
            State::Message => State::handle_message(content, view, event),
            State::Selected => State::handle_selected(content, view, event),
            State::Open(_) | State::Exit => panic!("Can't handle exit state"),
        }
    }

    fn handle_message<T>(content: &mut T, view: &mut View, event: Event) -> Self
    where
        T: Editable + Named + Undoable + Modifiable + Saveable,
    {
        view.quiet();
        Self::handle_insert(content, view, event)
    }

    fn handle_insert<T>(content: &mut T, view: &mut View, event: Event) -> Self
    where
        T: Editable + Named + Undoable + Modifiable + Saveable,
    {
        match event {
            Event::Key(Key::Ctrl('q')) | Event::Key(Key::Esc) => {
                if content.was_modified() {
                    let prompt = "Changes not saved do you really want to exit (y/N): ".to_string();
                    let message = "".to_string();
                    view.prompt(&prompt, &message);
                    return State::Prompt(prompt, message, PromptAction::ConfirmExit);
                } else {
                    return State::Exit;
                }
            }
            Event::Key(Key::Ctrl('s')) => {
                if content.name().is_empty() {
                    let prompt = "Save to: ".to_string();
                    view.prompt(&prompt, "");
                    return State::Prompt(prompt, "".to_string(), PromptAction::Save);
                } else {
                    let msg = match content.save() {
                        Err(e) => e.to_string(),
                        Ok(_) => format!("Saved file {}", content.name()),
                    };
                    view.message(&msg);
                    return State::Message;
                }
            }
            Event::Key(Key::Ctrl('o')) => {
                let prompt = "Open file: ".to_string();
                let message = "".to_string();
                view.prompt(&prompt, &message);
                return State::Prompt(prompt, message, PromptAction::Open);
            }
            Event::Mouse(MouseEvent::Press(MouseButton::Left, x, y)) => {
                let (line, col) = view.translate_coordinates(content, x, y);
                content.move_at(line, col);
                return State::Select(content.pos());
            }
            Event::Mouse(MouseEvent::Press(MouseButton::WheelDown, _, _)) => {
                view.scroll_view(SCROLL_FACTOR as isize, content);
            }
            Event::Mouse(MouseEvent::Press(MouseButton::WheelUp, _, _)) => {
                view.scroll_view(-(SCROLL_FACTOR as isize), content);
            }
            Event::Key(Key::Ctrl('z')) => {
                content.undo();
            }
            Event::Key(Key::Ctrl('y')) => {
                content.redo();
            }
            Event::Key(Key::Ctrl('v')) => {
                let mut ctx: ClipboardContext = ClipboardProvider::new().unwrap();
                for c in ctx
                    .get_contents()
                    .unwrap_or_else(|_| "".to_string())
                    .chars()
                {
                    content.insert(c);
                }
            }
            Event::Key(Key::Up) => {
                content.step(Movement::Up);
                view.adjust_view(content.line());
            }
            Event::Key(Key::Down) => {
                content.step(Movement::Down);
                view.adjust_view(content.line());
            }
            Event::Key(Key::Left) => {
                content.step(Movement::Left);
                view.adjust_view(content.line());
            }
            Event::Key(Key::Right) => {
                content.step(Movement::Right);
                view.adjust_view(content.line());
            }
            Event::Key(Key::PageUp) => {
                content.step(Movement::PageUp(view.lines_height() as usize));
                view.center_view(content.line());
            }
            Event::Key(Key::PageDown) => {
                content.step(Movement::PageDown(view.lines_height() as usize));
                view.center_view(content.line());
            }
            Event::Key(Key::Home) => {
                content.step(Movement::LineStart);
            }
            Event::Key(Key::End) => {
                content.step(Movement::LineEnd);
            }
            Event::Key(Key::Backspace) | Event::Key(Key::Ctrl('h')) => {
                content.delete();
                view.adjust_view(content.line());
            }
            Event::Key(Key::Delete) => {
                content.delete_forward();
                view.adjust_view(content.line());
            }
            Event::Key(Key::Char(c)) => {
                content.insert(c);
                view.adjust_view(content.line());
            }
            Event::Unsupported(u) => {
                view.message(&format!("Unsupported escape sequence {:?}", u));
            }
            _ => {}
        }
        State::Insert
    }

    fn handle_prompt<T>(
        content: &mut T,
        view: &mut View,
        event: Event,
        prompt: String,
        mut message: String,
        action: PromptAction,
    ) -> Self
    where
        T: Editable + Saveable + Modifiable,
    {
        match event {
            Event::Key(Key::Char('\n')) => match action {
                PromptAction::Save => {
                    let msg: String;
                    let old_name = content.name().clone();
                    content.set_name(message.clone());
                    msg = match content.save() {
                        Err(e) => {
                            content.set_name(old_name);
                            e.to_string()
                        }
                        Ok(_) => format!("Saved file {}", message),
                    };
                    view.message(&msg);
                    State::Message
                }
                PromptAction::ConfirmExit => {
                    if message.to_lowercase() == "y" {
                        State::Exit
                    } else {
                        view.message("");
                        State::Message
                    }
                }
                PromptAction::Open => {
                    let filename = message;
                    if content.was_modified() {
                        let prompt =
                            "Changes not saved do you really want to open a new file (y/N): "
                                .to_string();
                        let message = "".to_string();
                        view.prompt(&prompt, &message);
                        State::Prompt(prompt, message, PromptAction::ConfirmOpen(filename))
                    } else {
                        State::Open(filename)
                    }
                }
                PromptAction::ConfirmOpen(filename) => {
                    if message.to_lowercase() == "y" {
                        State::Open(filename)
                    } else {
                        view.message("");
                        State::Message
                    }
                }
            },
            Event::Key(Key::Char(c)) => {
                message.push(c);
                view.prompt(&prompt, &message);
                State::Prompt(prompt, message, action)
            }
            Event::Key(Key::Backspace) | Event::Key(Key::Delete) => {
                message.pop();
                view.prompt(&prompt, &message);
                State::Prompt(prompt, message, action)
            }
            Event::Key(Key::Ctrl('q')) => State::Exit,
            Event::Key(Key::Esc) => {
                view.quiet();
                State::Insert
            }
            _ => State::Prompt(prompt, message, action),
        }
    }

    fn handle_selected<T>(content: &mut T, view: &mut View, event: Event) -> Self
    where
        T: Selectable + Editable + Named + Undoable + Modifiable + Saveable,
    {
        match event {
            Event::Key(Key::Ctrl('c')) => {
                let (beg, end) = content.sel().unwrap();

                let selection: String = content.iter().skip(beg).take(end - beg + 1).collect();
                let mut ctx: ClipboardContext = ClipboardProvider::new().unwrap();
                ctx.set_contents(selection).unwrap();

                content.reset_sel();
                State::Insert
            }
            Event::Key(Key::Ctrl('x')) => {
                let (beg, end) = content.sel().unwrap();

                let selection: String = content.iter().skip(beg).take(end - beg + 1).collect();
                let mut ctx: ClipboardContext = ClipboardProvider::new().unwrap();
                ctx.set_contents(selection).unwrap();

                delete_sel(content);
                view.adjust_view(content.line());

                content.reset_sel();
                State::Insert
            }
            Event::Key(Key::Backspace) | Event::Key(Key::Delete) => {
                delete_sel(content);
                view.adjust_view(content.line());
                content.reset_sel();
                State::Insert
            }
            Event::Key(Key::Char(_)) => {
                delete_sel(content);
                view.adjust_view(content.line());
                content.reset_sel();
                Self::handle_insert(content, view, event)
            }
            _ => {
                content.reset_sel();
                Self::handle_insert(content, view, event)
            }
        }
    }

    fn handle_select<T>(content: &mut T, view: &mut View, event: Event, origin: usize) -> Self
    where
        T: Editable + Selectable,
    {
        match event {
            Event::Mouse(MouseEvent::Hold(x, y)) => {
                let (line, col) = view.translate_coordinates(content, x, y);
                content.move_at(line, col);
                let sel = (
                    cmp::min(origin, content.pos()),
                    cmp::max(origin, content.pos()),
                );
                content.set_sel(sel);
                State::Select(origin)
            }
            Event::Mouse(MouseEvent::Release(x, y)) => {
                let (line, col) = view.translate_coordinates(content, x, y);
                content.move_at(line, col);
                if origin != content.pos() {
                    let sel = (
                        cmp::min(origin, content.pos()),
                        cmp::max(origin, content.pos()),
                    );
                    content.set_sel(sel);
                    State::Selected
                } else {
                    State::Insert
                }
            }
            _ => State::Select(origin),
        }
    }
}

fn delete_sel<T>(content: &mut T)
where
    T: Selectable + Editable,
{
    let (beg, end) = content.sel().unwrap();
    assert!(beg < end);
    let end = cmp::min(end + 1, content.len() - 1);
    content.move_to(end);
    for _ in beg..end {
        content.delete();
    }
}
<commit_msg>Disable TAB in prompts<commit_after>use crate::data::*;
use crate::view::View;
use clipboard::{ClipboardContext, ClipboardProvider};
use std::cmp;
use termion::event::{Event, Key, MouseButton, MouseEvent};

#[derive(Debug, Clone)]
pub enum State {
    Insert,
    Message,
    Prompt(String, String, PromptAction),
    Select(usize),
    Selected,
    Open(String),
    Exit,
}

#[derive(Debug, Clone)]
pub enum PromptAction {
    Save,
    ConfirmExit,
    Open,
    ConfirmOpen(String),
}

const SCROLL_FACTOR: usize = 2;

impl State {
    // Handles a Termion event, consuming the current state and returning the new state
    pub fn handle<T>(self, content: &mut T, view: &mut View, event: Event) -> Self
    where
        T: Editable + Saveable + Undoable + Selectable + Modifiable,
    {
        match self {
            State::Prompt(prompt, message, action) => {
                State::handle_prompt(content, view, event, prompt, message, action)
            }
            State::Select(origin) => State::handle_select(content, view, event, origin),
            State::Insert => State::handle_insert(content, view, event),
            State::Message => State::handle_message(content, view, event),
            State::Selected => State::handle_selected(content, view, event),
            State::Open(_) | State::Exit => panic!("Can't handle exit state"),
        }
    }

    fn handle_message<T>(content: &mut T, view: &mut View, event: Event) -> Self
    where
        T: Editable + Named + Undoable + Modifiable + Saveable,
    {
        view.quiet();
        Self::handle_insert(content, view, event)
    }

    fn handle_insert<T>(content: &mut T, view: &mut View, event: Event) -> Self
    where
        T: Editable + Named + Undoable + Modifiable + Saveable,
    {
        match event {
            Event::Key(Key::Ctrl('q')) | Event::Key(Key::Esc) => {
                if content.was_modified() {
                    let prompt = "Changes not saved do you really want to exit (y/N): ".to_string();
                    let message = "".to_string();
                    view.prompt(&prompt, &message);
                    return State::Prompt(prompt, message, PromptAction::ConfirmExit);
                } else {
                    return State::Exit;
                }
            }
            Event::Key(Key::Ctrl('s')) => {
                if content.name().is_empty() {
                    let prompt = "Save to: ".to_string();
                    view.prompt(&prompt, "");
                    return State::Prompt(prompt, "".to_string(), PromptAction::Save);
                } else {
                    let msg = match content.save() {
                        Err(e) => e.to_string(),
                        Ok(_) => format!("Saved file {}", content.name()),
                    };
                    view.message(&msg);
                    return State::Message;
                }
            }
            Event::Key(Key::Ctrl('o')) => {
                let prompt = "Open file: ".to_string();
                let message = "".to_string();
                view.prompt(&prompt, &message);
                return State::Prompt(prompt, message, PromptAction::Open);
            }
            Event::Mouse(MouseEvent::Press(MouseButton::Left, x, y)) => {
                let (line, col) = view.translate_coordinates(content, x, y);
                content.move_at(line, col);
                return State::Select(content.pos());
            }
            Event::Mouse(MouseEvent::Press(MouseButton::WheelDown, _, _)) => {
                view.scroll_view(SCROLL_FACTOR as isize, content);
            }
            Event::Mouse(MouseEvent::Press(MouseButton::WheelUp, _, _)) => {
                view.scroll_view(-(SCROLL_FACTOR as isize), content);
            }
            Event::Key(Key::Ctrl('z')) => {
                content.undo();
            }
            Event::Key(Key::Ctrl('y')) => {
                content.redo();
            }
            Event::Key(Key::Ctrl('v')) => {
                let mut ctx: ClipboardContext = ClipboardProvider::new().unwrap();
                for c in ctx
                    .get_contents()
                    .unwrap_or_else(|_| "".to_string())
                    .chars()
                {
                    content.insert(c);
                }
            }
            Event::Key(Key::Up) => {
                content.step(Movement::Up);
                view.adjust_view(content.line());
            }
            Event::Key(Key::Down) => {
                content.step(Movement::Down);
                view.adjust_view(content.line());
            }
            Event::Key(Key::Left) => {
                content.step(Movement::Left);
                view.adjust_view(content.line());
            }
            Event::Key(Key::Right) => {
                content.step(Movement::Right);
                view.adjust_view(content.line());
            }
            Event::Key(Key::PageUp) => {
                content.step(Movement::PageUp(view.lines_height() as usize));
                view.center_view(content.line());
            }
            Event::Key(Key::PageDown) => {
                content.step(Movement::PageDown(view.lines_height() as usize));
                view.center_view(content.line());
            }
            Event::Key(Key::Home) => {
                content.step(Movement::LineStart);
            }
            Event::Key(Key::End) => {
                content.step(Movement::LineEnd);
            }
            Event::Key(Key::Backspace) | Event::Key(Key::Ctrl('h')) => {
                content.delete();
                view.adjust_view(content.line());
            }
            Event::Key(Key::Delete) => {
                content.delete_forward();
                view.adjust_view(content.line());
            }
            Event::Key(Key::Char(c)) => {
                content.insert(c);
                view.adjust_view(content.line());
            }
            Event::Unsupported(u) => {
                view.message(&format!("Unsupported escape sequence {:?}", u));
            }
            _ => {}
        }
        State::Insert
    }

    fn handle_prompt<T>(
        content: &mut T,
        view: &mut View,
        event: Event,
        prompt: String,
        mut message: String,
        action: PromptAction,
    ) -> Self
    where
        T: Editable + Saveable + Modifiable,
    {
        match event {
            Event::Key(Key::Char('\n')) => match action {
                PromptAction::Save => {
                    let msg: String;
                    let old_name = content.name().clone();
                    content.set_name(message.clone());
                    msg = match content.save() {
                        Err(e) => {
                            content.set_name(old_name);
                            e.to_string()
                        }
                        Ok(_) => format!("Saved file {}", message),
                    };
                    view.message(&msg);
                    State::Message
                }
                PromptAction::ConfirmExit => {
                    if message.to_lowercase() == "y" {
                        State::Exit
                    } else {
                        view.message("");
                        State::Message
                    }
                }
                PromptAction::Open => {
                    let filename = message;
                    if content.was_modified() {
                        let prompt =
                            "Changes not saved do you really want to open a new file (y/N): "
                                .to_string();
                        let message = "".to_string();
                        view.prompt(&prompt, &message);
                        State::Prompt(prompt, message, PromptAction::ConfirmOpen(filename))
                    } else {
                        State::Open(filename)
                    }
                }
                PromptAction::ConfirmOpen(filename) => {
                    if message.to_lowercase() == "y" {
                        State::Open(filename)
                    } else {
                        view.message("");
                        State::Message
                    }
                }
            },
            Event::Key(Key::Char('\t')) => State::Prompt(prompt, message, action), // TODO: autocompletion
            Event::Key(Key::Char(c)) => {
                message.push(c);
                view.prompt(&prompt, &message);
                State::Prompt(prompt, message, action)
            }
            Event::Key(Key::Backspace) | Event::Key(Key::Delete) => {
                message.pop();
                view.prompt(&prompt, &message);
                State::Prompt(prompt, message, action)
            }
            Event::Key(Key::Ctrl('q')) => State::Exit,
            Event::Key(Key::Esc) => {
                view.quiet();
                State::Insert
            }
            _ => State::Prompt(prompt, message, action),
        }
    }

    fn handle_selected<T>(content: &mut T, view: &mut View, event: Event) -> Self
    where
        T: Selectable + Editable + Named + Undoable + Modifiable + Saveable,
    {
        match event {
            Event::Key(Key::Ctrl('c')) => {
                let (beg, end) = content.sel().unwrap();

                let selection: String = content.iter().skip(beg).take(end - beg + 1).collect();
                let mut ctx: ClipboardContext = ClipboardProvider::new().unwrap();
                ctx.set_contents(selection).unwrap();

                content.reset_sel();
                State::Insert
            }
            Event::Key(Key::Ctrl('x')) => {
                let (beg, end) = content.sel().unwrap();

                let selection: String = content.iter().skip(beg).take(end - beg + 1).collect();
                let mut ctx: ClipboardContext = ClipboardProvider::new().unwrap();
                ctx.set_contents(selection).unwrap();

                delete_sel(content);
                view.adjust_view(content.line());

                content.reset_sel();
                State::Insert
            }
            Event::Key(Key::Backspace) | Event::Key(Key::Delete) => {
                delete_sel(content);
                view.adjust_view(content.line());
                content.reset_sel();
                State::Insert
            }
            Event::Key(Key::Char(_)) => {
                delete_sel(content);
                view.adjust_view(content.line());
                content.reset_sel();
                Self::handle_insert(content, view, event)
            }
            _ => {
                content.reset_sel();
                Self::handle_insert(content, view, event)
            }
        }
    }

    fn handle_select<T>(content: &mut T, view: &mut View, event: Event, origin: usize) -> Self
    where
        T: Editable + Selectable,
    {
        match event {
            Event::Mouse(MouseEvent::Hold(x, y)) => {
                let (line, col) = view.translate_coordinates(content, x, y);
                content.move_at(line, col);
                let sel = (
                    cmp::min(origin, content.pos()),
                    cmp::max(origin, content.pos()),
                );
                content.set_sel(sel);
                State::Select(origin)
            }
            Event::Mouse(MouseEvent::Release(x, y)) => {
                let (line, col) = view.translate_coordinates(content, x, y);
                content.move_at(line, col);
                if origin != content.pos() {
                    let sel = (
                        cmp::min(origin, content.pos()),
                        cmp::max(origin, content.pos()),
                    );
                    content.set_sel(sel);
                    State::Selected
                } else {
                    State::Insert
                }
            }
            _ => State::Select(origin),
        }
    }
}

fn delete_sel<T>(content: &mut T)
where
    T: Selectable + Editable,
{
    let (beg, end) = content.sel().unwrap();
    assert!(beg < end);
    let end = cmp::min(end + 1, content.len() - 1);
    content.move_to(end);
    for _ in beg..end {
        content.delete();
    }
}
<|endoftext|>


<commit_before>use crate::{BeaconChainError, BlockError};
use state_processing::BlockProcessingError;
use types::{Hash256, Slot};

/// This is a legacy object that is being kept around to reduce merge conflicts.
///
/// As soon as this is merged into master, it should be removed as soon as possible.
#[derive(Debug, PartialEq)]
pub enum BlockProcessingOutcome {
    /// Block was valid and imported into the block graph.
    Processed {
        block_root: Hash256,
    },
    InvalidSignature,
    /// The proposal signature in invalid.
    ProposalSignatureInvalid,
    /// The parent block was unknown.
    ParentUnknown(Hash256),
    /// The block slot is greater than the present slot.
    FutureSlot {
        present_slot: Slot,
        block_slot: Slot,
    },
    /// The block state_root does not match the generated state.
    StateRootMismatch {
        block: Hash256,
        local: Hash256,
    },
    /// The block was a genesis block, these blocks cannot be re-imported.
    GenesisBlock,
    /// The slot is finalized, no need to import.
    WouldRevertFinalizedSlot {
        block_slot: Slot,
        finalized_slot: Slot,
    },
    /// Block is already known, no need to re-import.
    BlockIsAlreadyKnown,
    /// The block slot exceeds the MAXIMUM_BLOCK_SLOT_NUMBER.
    BlockSlotLimitReached,
    /// The provided block is from an earlier slot than its parent.
    BlockIsNotLaterThanParent {
        block_slot: Slot,
        state_slot: Slot,
    },
    /// At least one block in the chain segement did not have it's parent root set to the root of
    /// the prior block.
    NonLinearParentRoots,
    /// The slots of the blocks in the chain segment were not strictly increasing. I.e., a child
    /// had lower slot than a parent.
    NonLinearSlots,
    /// The block could not be applied to the state, it is invalid.
    PerBlockProcessingError(BlockProcessingError),
}

impl BlockProcessingOutcome {
    pub fn shim(
        result: Result<Hash256, BlockError>,
    ) -> Result<BlockProcessingOutcome, BeaconChainError> {
        match result {
            Ok(block_root) => Ok(BlockProcessingOutcome::Processed { block_root }),
            Err(BlockError::ParentUnknown(root)) => Ok(BlockProcessingOutcome::ParentUnknown(root)),
            Err(BlockError::FutureSlot {
                present_slot,
                block_slot,
            }) => Ok(BlockProcessingOutcome::FutureSlot {
                present_slot,
                block_slot,
            }),
            Err(BlockError::StateRootMismatch { block, local }) => {
                Ok(BlockProcessingOutcome::StateRootMismatch { block, local })
            }
            Err(BlockError::GenesisBlock) => Ok(BlockProcessingOutcome::GenesisBlock),
            Err(BlockError::WouldRevertFinalizedSlot {
                block_slot,
                finalized_slot,
            }) => Ok(BlockProcessingOutcome::WouldRevertFinalizedSlot {
                block_slot,
                finalized_slot,
            }),
            Err(BlockError::BlockIsAlreadyKnown) => Ok(BlockProcessingOutcome::BlockIsAlreadyKnown),
            Err(BlockError::BlockSlotLimitReached) => {
                Ok(BlockProcessingOutcome::BlockSlotLimitReached)
            }
            Err(BlockError::ProposalSignatureInvalid) => {
                Ok(BlockProcessingOutcome::ProposalSignatureInvalid)
            }
            Err(BlockError::InvalidSignature) => Ok(BlockProcessingOutcome::InvalidSignature),
            Err(BlockError::BlockIsNotLaterThanParent {
                block_slot,
                state_slot,
            }) => Ok(BlockProcessingOutcome::BlockIsNotLaterThanParent {
                block_slot,
                state_slot,
            }),
            Err(BlockError::NonLinearParentRoots) => {
                Ok(BlockProcessingOutcome::NonLinearParentRoots)
            }
            Err(BlockError::NonLinearSlots) => Ok(BlockProcessingOutcome::NonLinearSlots),
            Err(BlockError::PerBlockProcessingError(e)) => {
                Ok(BlockProcessingOutcome::PerBlockProcessingError(e))
            }
            Err(BlockError::BeaconChainError(e)) => Err(e),
        }
    }
}
<commit_msg>Add missing TODO (#1079)<commit_after>use crate::{BeaconChainError, BlockError};
use state_processing::BlockProcessingError;
use types::{Hash256, Slot};

/// This is a legacy object that is being kept around to reduce merge conflicts.
///
/// TODO: As soon as this is merged into master, it should be removed as soon as possible.
#[derive(Debug, PartialEq)]
pub enum BlockProcessingOutcome {
    /// Block was valid and imported into the block graph.
    Processed {
        block_root: Hash256,
    },
    InvalidSignature,
    /// The proposal signature in invalid.
    ProposalSignatureInvalid,
    /// The parent block was unknown.
    ParentUnknown(Hash256),
    /// The block slot is greater than the present slot.
    FutureSlot {
        present_slot: Slot,
        block_slot: Slot,
    },
    /// The block state_root does not match the generated state.
    StateRootMismatch {
        block: Hash256,
        local: Hash256,
    },
    /// The block was a genesis block, these blocks cannot be re-imported.
    GenesisBlock,
    /// The slot is finalized, no need to import.
    WouldRevertFinalizedSlot {
        block_slot: Slot,
        finalized_slot: Slot,
    },
    /// Block is already known, no need to re-import.
    BlockIsAlreadyKnown,
    /// The block slot exceeds the MAXIMUM_BLOCK_SLOT_NUMBER.
    BlockSlotLimitReached,
    /// The provided block is from an earlier slot than its parent.
    BlockIsNotLaterThanParent {
        block_slot: Slot,
        state_slot: Slot,
    },
    /// At least one block in the chain segement did not have it's parent root set to the root of
    /// the prior block.
    NonLinearParentRoots,
    /// The slots of the blocks in the chain segment were not strictly increasing. I.e., a child
    /// had lower slot than a parent.
    NonLinearSlots,
    /// The block could not be applied to the state, it is invalid.
    PerBlockProcessingError(BlockProcessingError),
}

impl BlockProcessingOutcome {
    pub fn shim(
        result: Result<Hash256, BlockError>,
    ) -> Result<BlockProcessingOutcome, BeaconChainError> {
        match result {
            Ok(block_root) => Ok(BlockProcessingOutcome::Processed { block_root }),
            Err(BlockError::ParentUnknown(root)) => Ok(BlockProcessingOutcome::ParentUnknown(root)),
            Err(BlockError::FutureSlot {
                present_slot,
                block_slot,
            }) => Ok(BlockProcessingOutcome::FutureSlot {
                present_slot,
                block_slot,
            }),
            Err(BlockError::StateRootMismatch { block, local }) => {
                Ok(BlockProcessingOutcome::StateRootMismatch { block, local })
            }
            Err(BlockError::GenesisBlock) => Ok(BlockProcessingOutcome::GenesisBlock),
            Err(BlockError::WouldRevertFinalizedSlot {
                block_slot,
                finalized_slot,
            }) => Ok(BlockProcessingOutcome::WouldRevertFinalizedSlot {
                block_slot,
                finalized_slot,
            }),
            Err(BlockError::BlockIsAlreadyKnown) => Ok(BlockProcessingOutcome::BlockIsAlreadyKnown),
            Err(BlockError::BlockSlotLimitReached) => {
                Ok(BlockProcessingOutcome::BlockSlotLimitReached)
            }
            Err(BlockError::ProposalSignatureInvalid) => {
                Ok(BlockProcessingOutcome::ProposalSignatureInvalid)
            }
            Err(BlockError::InvalidSignature) => Ok(BlockProcessingOutcome::InvalidSignature),
            Err(BlockError::BlockIsNotLaterThanParent {
                block_slot,
                state_slot,
            }) => Ok(BlockProcessingOutcome::BlockIsNotLaterThanParent {
                block_slot,
                state_slot,
            }),
            Err(BlockError::NonLinearParentRoots) => {
                Ok(BlockProcessingOutcome::NonLinearParentRoots)
            }
            Err(BlockError::NonLinearSlots) => Ok(BlockProcessingOutcome::NonLinearSlots),
            Err(BlockError::PerBlockProcessingError(e)) => {
                Ok(BlockProcessingOutcome::PerBlockProcessingError(e))
            }
            Err(BlockError::BeaconChainError(e)) => Err(e),
        }
    }
}
<|endoftext|>