<commit_before>#![feature(rustc_private, macro_at_most_once_rep, never_type)]
#![allow(intra_doc_link_resolution_failure)]

extern crate byteorder;
extern crate syntax;
#[macro_use]
extern crate rustc;
extern crate rustc_codegen_utils;
extern crate rustc_incremental;
extern crate rustc_mir;
extern crate rustc_target;
#[macro_use]
extern crate rustc_data_structures;

extern crate ar;
#[macro_use]
extern crate bitflags;
extern crate faerie;
//extern crate goblin;
extern crate cranelift;
extern crate cranelift_faerie;
extern crate cranelift_module;
extern crate cranelift_simplejit;
extern crate target_lexicon;

use std::any::Any;
use std::fs::File;
use std::sync::{mpsc, Arc};

use crate::rustc::dep_graph::DepGraph;
use crate::rustc::middle::cstore::MetadataLoader;
use crate::rustc::session::{config::OutputFilenames, CompileIncomplete};
use crate::rustc::ty::query::Providers;
use crate::rustc_codegen_utils::codegen_backend::CodegenBackend;
use crate::rustc_codegen_utils::link::out_filename;
use crate::syntax::symbol::Symbol;

use cranelift::codegen::settings;
use cranelift_faerie::*;

struct NonFatal(pub String);

macro_rules! unimpl {
    ($($tt:tt)*) => {
        panic!(crate::NonFatal(format!($($tt)*)));
    };
}

mod abi;
mod analyze;
mod base;
mod common;
mod constant;
mod intrinsics;
mod main_shim;
mod metadata;
mod pretty_clif;
mod vtable;

mod prelude {
    pub use std::any::Any;
    pub use std::collections::{HashMap, HashSet};

    pub use crate::rustc::hir::def_id::{DefId, LOCAL_CRATE};
    pub use crate::rustc::mir;
    pub use crate::rustc::mir::interpret::AllocId;
    pub use crate::rustc::mir::*;
    pub use crate::rustc::session::{config::CrateType, Session};
    pub use crate::rustc::ty::layout::{self, Abi, LayoutOf, Scalar, Size, TyLayout};
    pub use crate::rustc::ty::{
        self, subst::Substs, FnSig, Instance, InstanceDef, ParamEnv, PolyFnSig, Ty, TyCtxt,
        TypeAndMut, TypeFoldable,
    };
    pub use crate::rustc_data_structures::{
        fx::{FxHashMap, FxHashSet},
        indexed_vec::Idx,
        sync::Lrc,
    };
    pub use crate::rustc_mir::monomorphize::{collector, MonoItem};
    pub use crate::syntax::ast::{FloatTy, IntTy, UintTy};
    pub use crate::syntax::source_map::DUMMY_SP;

    pub use cranelift::codegen::isa::CallConv;
    pub use cranelift::codegen::ir::{
        condcodes::IntCC, function::Function, ExternalName, FuncRef, Inst, StackSlot,
    };
    pub use cranelift::codegen::Context;
    pub use cranelift::prelude::*;
    pub use cranelift_module::{Backend, DataContext, DataId, FuncId, Linkage, Module};
    pub use cranelift_simplejit::{SimpleJITBackend, SimpleJITBuilder};

    pub use crate::abi::*;
    pub use crate::base::{trans_operand, trans_place};
    pub use crate::common::*;
    pub use crate::Caches;

    pub fn should_codegen(_sess: &Session) -> bool {
        true
        //::std::env::var("SHOULD_CODEGEN").is_ok()
        //    || sess.crate_types.get().contains(&CrateType::Executable)
    }
}

use crate::constant::ConstantCx;
use crate::prelude::*;

pub struct Caches<'tcx> {
    pub context: Context,
    pub vtables: HashMap<(Ty<'tcx>, ty::PolyExistentialTraitRef<'tcx>), DataId>,
}

impl<'tcx> Caches<'tcx> {
    fn new() -> Self {
        Caches {
            context: Context::new(),
            vtables: HashMap::new(),
        }
    }
}

struct CraneliftCodegenBackend;

struct OngoingCodegen {
    product: cranelift_faerie::FaerieProduct,
    metadata: Vec<u8>,
    crate_name: Symbol,
}

impl CodegenBackend for CraneliftCodegenBackend {
    fn init(&self, sess: &Session) {
        for cty in sess.opts.crate_types.iter() {
            match *cty {
                CrateType::Rlib | CrateType::Dylib | CrateType::Executable => {}
                _ => {
                    sess.err(&format!(
                        "Rustc codegen cranelift doesn't support output type {}",
                        cty
                    ));
                }
            }
        }
    }

    fn metadata_loader(&self) -> Box<MetadataLoader + Sync> {
        Box::new(crate::metadata::CraneliftMetadataLoader)
    }

    fn provide(&self, providers: &mut Providers) {
        rustc_codegen_utils::symbol_names::provide(providers);
        rustc_codegen_utils::symbol_export::provide(providers);

        providers.target_features_whitelist = |_tcx, _cnum| Lrc::new(Default::default());
    }
    fn provide_extern(&self, providers: &mut Providers) {
        rustc_codegen_utils::symbol_export::provide_extern(providers);
    }

    fn codegen_crate<'a, 'tcx>(
        &self,
        tcx: TyCtxt<'a, 'tcx, 'tcx>,
        _rx: mpsc::Receiver<Box<Any + Send>>,
    ) -> Box<Any> {
        if !tcx.sess.crate_types.get().contains(&CrateType::Executable)
            && std::env::var("SHOULD_RUN").is_ok()
        {
            tcx.sess
                .err("Can't JIT run non executable (SHOULD_RUN env var is set)");
        }

        tcx.sess.abort_if_errors();

        let metadata = tcx.encode_metadata();

        let mut flags_builder = settings::builder();
        flags_builder.enable("is_pic").unwrap();
        let flags = settings::Flags::new(flags_builder);
        let isa = cranelift::codegen::isa::lookup(tcx.sess.target.target.llvm_target.parse().unwrap())
            .unwrap()
            .finish(flags);

        let mono_items =
            collector::collect_crate_mono_items(tcx, collector::MonoItemCollectionMode::Lazy).0;

        // TODO: move to the end of this function when compiling libcore doesn't have unimplemented stuff anymore
        save_incremental(tcx);
        tcx.sess.warn("Saved incremental data");

        if std::env::var("SHOULD_RUN").is_ok() {
            let mut jit_module: Module<SimpleJITBackend> = Module::new(SimpleJITBuilder::new());
            assert_eq!(pointer_ty(tcx), jit_module.target_config().pointer_type());

            codegen_mono_items(tcx, &mut jit_module, mono_items);

            tcx.sess.abort_if_errors();
            println!("Compiled everything");
            println!("Rustc codegen cranelift will JIT run the executable, because the SHOULD_RUN env var is set");

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

            jit_module.finalize_definitions();
            let finalized_main: *const u8 = jit_module.get_finalized_function(main_func_id);
            println!("🎉 Finalized everything");

            let f: extern "C" fn(isize, *const *const u8) -> isize =
                unsafe { ::std::mem::transmute(finalized_main) };
            let res = f(0, 0 as *const _);
            tcx.sess.warn(&format!("🚀 main returned {}", res));

            jit_module.finish();
            ::std::process::exit(0);
        } else {
            let mut faerie_module: Module<FaerieBackend> = Module::new(
                FaerieBuilder::new(
                    isa,
                    "some_file.o".to_string(),
                    FaerieTrapCollection::Disabled,
                    FaerieBuilder::default_libcall_names(),
                )
                .unwrap(),
            );
            assert_eq!(pointer_ty(tcx), faerie_module.target_config().pointer_type());

            codegen_mono_items(tcx, &mut faerie_module, mono_items);

            tcx.sess.abort_if_errors();

            if should_codegen(tcx.sess) {
                faerie_module.finalize_definitions();
            }

            return Box::new(OngoingCodegen {
                product: faerie_module.finish(),
                metadata: metadata.raw_data,
                crate_name: tcx.crate_name(LOCAL_CRATE),
            });
        }
    }

    fn join_codegen_and_link(
        &self,
        ongoing_codegen: Box<Any>,
        sess: &Session,
        _dep_graph: &DepGraph,
        outputs: &OutputFilenames,
    ) -> Result<(), CompileIncomplete> {
        let ongoing_codegen = *ongoing_codegen
            .downcast::<OngoingCodegen>()
            .expect("Expected CraneliftCodegenBackend's OngoingCodegen, found Box<Any>");

        let artifact = ongoing_codegen.product.artifact;
        let metadata = ongoing_codegen.metadata;

        /*
        artifact
            .declare_with(
                &metadata_name,
                faerie::artifact::Decl::Data {
                    global: true,
                    writable: false,
                },
                metadata.clone(),
            )
            .unwrap();
        */

        for &crate_type in sess.opts.crate_types.iter() {
            match crate_type {
                // TODO: link executable
                CrateType::Executable | CrateType::Rlib => {
                    let output_name = out_filename(
                        sess,
                        crate_type,
                        &outputs,
                        &ongoing_codegen.crate_name.as_str(),
                    );
                    let file = File::create(&output_name).unwrap();
                    let mut builder = ar::Builder::new(file);

                    if should_codegen(sess) {
                        // Add main object file
                        let obj = artifact.emit().unwrap();
                        builder
                            .append(
                                &ar::Header::new(b"data.o".to_vec(), obj.len() as u64),
                                ::std::io::Cursor::new(obj),
                            )
                            .unwrap();
                    }

                    // Non object files need to be added after object files, because ranlib will
                    // try to read the native architecture from the first file, even if it isn't
                    // an object file
                    if crate_type != CrateType::Executable {
                        builder
                            .append(
                                &ar::Header::new(
                                    metadata::METADATA_FILE.to_vec(),
                                    metadata.len() as u64,
                                ),
                                ::std::io::Cursor::new(metadata.clone()),
                            )
                            .unwrap();
                    }

                    // Finalize archive
                    std::mem::drop(builder);

                    // Run ranlib to be able to link the archive
                    let status = std::process::Command::new("ranlib")
                        .arg(output_name)
                        .status()
                        .expect("Couldn't run ranlib");
                    if !status.success() {
                        sess.fatal(&format!("Ranlib exited with code {:?}", status.code()));
                    }
                }
                _ => sess.fatal(&format!("Unsupported crate type: {:?}", crate_type)),
            }
        }
        Ok(())
    }
}

fn codegen_mono_items<'a, 'tcx: 'a>(
    tcx: TyCtxt<'a, 'tcx, 'tcx>,
    module: &mut Module<impl Backend + 'static>,
    mono_items: FxHashSet<MonoItem<'tcx>>,
) {
    use std::io::Write;

    let mut caches = Caches::new();
    let mut ccx = ConstantCx::default();

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

    let before = ::std::time::Instant::now();
    println!("[codegen mono items] start");

    for mono_item in mono_items {
        let res = ::std::panic::catch_unwind(::std::panic::AssertUnwindSafe(|| {
            base::trans_mono_item(tcx, module, &mut caches, &mut ccx, mono_item);
        }));

        if let Err(err) = res {
            match err.downcast::<NonFatal>() {
                Ok(non_fatal) => {
                    if cfg!(debug_assertions) {
                        writeln!(log.as_mut().unwrap(), "{}", &non_fatal.0);
                    }
                    tcx.sess.err(&non_fatal.0)
                }
                Err(err) => ::std::panic::resume_unwind(err),
            }
        }
    }

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

    ccx.finalize(tcx, module);

    let after = ::std::time::Instant::now();
    println!("[codegen mono items] end time: {:?}", after - before);
}

fn save_incremental<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
    rustc_incremental::assert_dep_graph(tcx);
    rustc_incremental::save_dep_graph(tcx);
    rustc_incremental::finalize_session_directory(tcx.sess, tcx.crate_hash(LOCAL_CRATE));
}

/// This is the entrypoint for a hot plugged rustc_codegen_cranelift
#[no_mangle]
pub fn __rustc_codegen_backend() -> Box<CodegenBackend> {
    Box::new(CraneliftCodegenBackend)
}
<commit_msg>Use tcx.collect_and_partition_mono_items<commit_after>#![feature(rustc_private, macro_at_most_once_rep, never_type)]
#![allow(intra_doc_link_resolution_failure)]

extern crate byteorder;
extern crate syntax;
#[macro_use]
extern crate rustc;
extern crate rustc_codegen_utils;
extern crate rustc_incremental;
extern crate rustc_mir;
extern crate rustc_target;
#[macro_use]
extern crate rustc_data_structures;

extern crate ar;
#[macro_use]
extern crate bitflags;
extern crate faerie;
//extern crate goblin;
extern crate cranelift;
extern crate cranelift_faerie;
extern crate cranelift_module;
extern crate cranelift_simplejit;
extern crate target_lexicon;

use std::any::Any;
use std::fs::File;
use std::sync::{mpsc, Arc};

use crate::rustc::dep_graph::DepGraph;
use crate::rustc::middle::cstore::MetadataLoader;
use crate::rustc::session::{config::OutputFilenames, CompileIncomplete};
use crate::rustc::ty::query::Providers;
use crate::rustc_codegen_utils::codegen_backend::CodegenBackend;
use crate::rustc_codegen_utils::link::out_filename;
use crate::syntax::symbol::Symbol;

use cranelift::codegen::settings;
use cranelift_faerie::*;

struct NonFatal(pub String);

macro_rules! unimpl {
    ($($tt:tt)*) => {
        panic!(crate::NonFatal(format!($($tt)*)));
    };
}

mod abi;
mod analyze;
mod base;
mod common;
mod constant;
mod intrinsics;
mod main_shim;
mod metadata;
mod pretty_clif;
mod vtable;

mod prelude {
    pub use std::any::Any;
    pub use std::collections::{HashMap, HashSet};

    pub use crate::rustc::hir::def_id::{DefId, LOCAL_CRATE};
    pub use crate::rustc::mir;
    pub use crate::rustc::mir::interpret::AllocId;
    pub use crate::rustc::mir::*;
    pub use crate::rustc::session::{config::CrateType, Session};
    pub use crate::rustc::ty::layout::{self, Abi, LayoutOf, Scalar, Size, TyLayout};
    pub use crate::rustc::ty::{
        self, subst::Substs, FnSig, Instance, InstanceDef, ParamEnv, PolyFnSig, Ty, TyCtxt,
        TypeAndMut, TypeFoldable,
    };
    pub use crate::rustc_data_structures::{
        fx::{FxHashMap, FxHashSet},
        indexed_vec::Idx,
        sync::Lrc,
    };
    pub use crate::rustc_mir::monomorphize::{collector, MonoItem};
    pub use crate::syntax::ast::{FloatTy, IntTy, UintTy};
    pub use crate::syntax::source_map::DUMMY_SP;

    pub use cranelift::codegen::isa::CallConv;
    pub use cranelift::codegen::ir::{
        condcodes::IntCC, function::Function, ExternalName, FuncRef, Inst, StackSlot,
    };
    pub use cranelift::codegen::Context;
    pub use cranelift::prelude::*;
    pub use cranelift_module::{Backend, DataContext, DataId, FuncId, Linkage, Module};
    pub use cranelift_simplejit::{SimpleJITBackend, SimpleJITBuilder};

    pub use crate::abi::*;
    pub use crate::base::{trans_operand, trans_place};
    pub use crate::common::*;
    pub use crate::Caches;

    pub fn should_codegen(_sess: &Session) -> bool {
        true
        //::std::env::var("SHOULD_CODEGEN").is_ok()
        //    || sess.crate_types.get().contains(&CrateType::Executable)
    }
}

use crate::constant::ConstantCx;
use crate::prelude::*;

pub struct Caches<'tcx> {
    pub context: Context,
    pub vtables: HashMap<(Ty<'tcx>, ty::PolyExistentialTraitRef<'tcx>), DataId>,
}

impl<'tcx> Caches<'tcx> {
    fn new() -> Self {
        Caches {
            context: Context::new(),
            vtables: HashMap::new(),
        }
    }
}

struct CraneliftCodegenBackend;

struct OngoingCodegen {
    product: cranelift_faerie::FaerieProduct,
    metadata: Vec<u8>,
    crate_name: Symbol,
}

impl CodegenBackend for CraneliftCodegenBackend {
    fn init(&self, sess: &Session) {
        for cty in sess.opts.crate_types.iter() {
            match *cty {
                CrateType::Rlib | CrateType::Dylib | CrateType::Executable => {}
                _ => {
                    sess.err(&format!(
                        "Rustc codegen cranelift doesn't support output type {}",
                        cty
                    ));
                }
            }
        }
    }

    fn metadata_loader(&self) -> Box<MetadataLoader + Sync> {
        Box::new(crate::metadata::CraneliftMetadataLoader)
    }

    fn provide(&self, providers: &mut Providers) {
        rustc_codegen_utils::symbol_names::provide(providers);
        rustc_codegen_utils::symbol_export::provide(providers);

        providers.target_features_whitelist = |_tcx, _cnum| Lrc::new(Default::default());
    }
    fn provide_extern(&self, providers: &mut Providers) {
        rustc_codegen_utils::symbol_export::provide_extern(providers);
    }

    fn codegen_crate<'a, 'tcx>(
        &self,
        tcx: TyCtxt<'a, 'tcx, 'tcx>,
        _rx: mpsc::Receiver<Box<Any + Send>>,
    ) -> Box<Any> {
        if !tcx.sess.crate_types.get().contains(&CrateType::Executable)
            && std::env::var("SHOULD_RUN").is_ok()
        {
            tcx.sess
                .err("Can't JIT run non executable (SHOULD_RUN env var is set)");
        }

        tcx.sess.abort_if_errors();

        let metadata = tcx.encode_metadata();

        let mut flags_builder = settings::builder();
        flags_builder.enable("is_pic").unwrap();
        let flags = settings::Flags::new(flags_builder);
        let isa = cranelift::codegen::isa::lookup(tcx.sess.target.target.llvm_target.parse().unwrap())
            .unwrap()
            .finish(flags);

        // TODO: move to the end of this function when compiling libcore doesn't have unimplemented stuff anymore
        save_incremental(tcx);
        tcx.sess.warn("Saved incremental data");

        if std::env::var("SHOULD_RUN").is_ok() {
            let mut jit_module: Module<SimpleJITBackend> = Module::new(SimpleJITBuilder::new());
            assert_eq!(pointer_ty(tcx), jit_module.target_config().pointer_type());

            codegen_mono_items(tcx, &mut jit_module);

            tcx.sess.abort_if_errors();
            println!("Compiled everything");
            println!("Rustc codegen cranelift will JIT run the executable, because the SHOULD_RUN env var is set");

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

            jit_module.finalize_definitions();
            let finalized_main: *const u8 = jit_module.get_finalized_function(main_func_id);
            println!("🎉 Finalized everything");

            let f: extern "C" fn(isize, *const *const u8) -> isize =
                unsafe { ::std::mem::transmute(finalized_main) };
            let res = f(0, 0 as *const _);
            tcx.sess.warn(&format!("🚀 main returned {}", res));

            jit_module.finish();
            ::std::process::exit(0);
        } else {
            let mut faerie_module: Module<FaerieBackend> = Module::new(
                FaerieBuilder::new(
                    isa,
                    "some_file.o".to_string(),
                    FaerieTrapCollection::Disabled,
                    FaerieBuilder::default_libcall_names(),
                )
                .unwrap(),
            );
            assert_eq!(pointer_ty(tcx), faerie_module.target_config().pointer_type());

            codegen_mono_items(tcx, &mut faerie_module);

            tcx.sess.abort_if_errors();

            if should_codegen(tcx.sess) {
                faerie_module.finalize_definitions();
            }

            return Box::new(OngoingCodegen {
                product: faerie_module.finish(),
                metadata: metadata.raw_data,
                crate_name: tcx.crate_name(LOCAL_CRATE),
            });
        }
    }

    fn join_codegen_and_link(
        &self,
        ongoing_codegen: Box<Any>,
        sess: &Session,
        _dep_graph: &DepGraph,
        outputs: &OutputFilenames,
    ) -> Result<(), CompileIncomplete> {
        let ongoing_codegen = *ongoing_codegen
            .downcast::<OngoingCodegen>()
            .expect("Expected CraneliftCodegenBackend's OngoingCodegen, found Box<Any>");

        let artifact = ongoing_codegen.product.artifact;
        let metadata = ongoing_codegen.metadata;

        /*
        artifact
            .declare_with(
                &metadata_name,
                faerie::artifact::Decl::Data {
                    global: true,
                    writable: false,
                },
                metadata.clone(),
            )
            .unwrap();
        */

        for &crate_type in sess.opts.crate_types.iter() {
            match crate_type {
                // TODO: link executable
                CrateType::Executable | CrateType::Rlib => {
                    let output_name = out_filename(
                        sess,
                        crate_type,
                        &outputs,
                        &ongoing_codegen.crate_name.as_str(),
                    );
                    let file = File::create(&output_name).unwrap();
                    let mut builder = ar::Builder::new(file);

                    if should_codegen(sess) {
                        // Add main object file
                        let obj = artifact.emit().unwrap();
                        builder
                            .append(
                                &ar::Header::new(b"data.o".to_vec(), obj.len() as u64),
                                ::std::io::Cursor::new(obj),
                            )
                            .unwrap();
                    }

                    // Non object files need to be added after object files, because ranlib will
                    // try to read the native architecture from the first file, even if it isn't
                    // an object file
                    if crate_type != CrateType::Executable {
                        builder
                            .append(
                                &ar::Header::new(
                                    metadata::METADATA_FILE.to_vec(),
                                    metadata.len() as u64,
                                ),
                                ::std::io::Cursor::new(metadata.clone()),
                            )
                            .unwrap();
                    }

                    // Finalize archive
                    std::mem::drop(builder);

                    // Run ranlib to be able to link the archive
                    let status = std::process::Command::new("ranlib")
                        .arg(output_name)
                        .status()
                        .expect("Couldn't run ranlib");
                    if !status.success() {
                        sess.fatal(&format!("Ranlib exited with code {:?}", status.code()));
                    }
                }
                _ => sess.fatal(&format!("Unsupported crate type: {:?}", crate_type)),
            }
        }
        Ok(())
    }
}

fn codegen_mono_items<'a, 'tcx: 'a>(
    tcx: TyCtxt<'a, 'tcx, 'tcx>,
    module: &mut Module<impl Backend + 'static>,
) {
    use std::io::Write;

    let mut caches = Caches::new();
    let mut ccx = ConstantCx::default();

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

    let (_, cgus) = tcx.collect_and_partition_mono_items(LOCAL_CRATE);
    let mono_items = cgus.iter().map(|cgu| {
        cgu.items().iter()
    }).flatten().collect::<FxHashSet<(_, _)>>();

    let before = ::std::time::Instant::now();
    println!("[codegen mono items] start");

    for (&mono_item, &(_linkage, _vis)) in mono_items {
        let res = ::std::panic::catch_unwind(::std::panic::AssertUnwindSafe(|| {
            base::trans_mono_item(tcx, module, &mut caches, &mut ccx, mono_item);
        }));

        if let Err(err) = res {
            match err.downcast::<NonFatal>() {
                Ok(non_fatal) => {
                    if cfg!(debug_assertions) {
                        writeln!(log.as_mut().unwrap(), "{}", &non_fatal.0);
                    }
                    tcx.sess.err(&non_fatal.0)
                }
                Err(err) => ::std::panic::resume_unwind(err),
            }
        }
    }

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

    ccx.finalize(tcx, module);

    let after = ::std::time::Instant::now();
    println!("[codegen mono items] end time: {:?}", after - before);
}

fn save_incremental<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
    rustc_incremental::assert_dep_graph(tcx);
    rustc_incremental::save_dep_graph(tcx);
    rustc_incremental::finalize_session_directory(tcx.sess, tcx.crate_hash(LOCAL_CRATE));
}

/// This is the entrypoint for a hot plugged rustc_codegen_cranelift
#[no_mangle]
pub fn __rustc_codegen_backend() -> Box<CodegenBackend> {
    Box::new(CraneliftCodegenBackend)
}
<|endoftext|>


<commit_before>//! This library provides a toolkit for rapid protocol development and usage,
//! working with the rest of the Tokio stack.
//!
//! You can find extensive documentation and tutorials in addition to this
//! documentation at [https://tokio.rs](https://tokio.rs)
//!
//! # Protocols
//!
//! Here, a **protocol** is a way of providing or consuming a service. Protocols
//! are implemented via traits, which are arranged into a taxonomy:
//!
//! - `pipeline::{ClientProto, ServerProto}`
//! - `multiplex::{ClientProto, ServerProto}`
//! - `streaming::pipeline::{ClientProto, ServerProto}`
//! - `streaming::multiplex::{ClientProto, ServerProto}`
//!
//! ### Pipeline vs multiplex
//!
//! By default, protocols allow a client to transmit multiple requests without
//! waiting for the corresponding responses, which is commonly used to improve
//! the throughput of single connections.
//!
//! In a **pipelined protocol**, the server responds to client requests in the
//! order they were sent. Example pipelined protocols include HTTP/1.1 and Redis.
//! Pipelining with the max number of in-flight requests set to 1 implies that
//! for each request, the response must be received before sending another
//! request on the same connection.
//!
//! In a **multiplexed protocol**, the server responds to client requests in the
//! order of completion. Request IDs are used to match responses back to requests.
//!
//! In both cases, if multiple requests are sent, the service running on the
//! server *may* process them concurrently, although many services will impose
//! some restrictions depending on the request type.
//!
//! ### Streaming
//!
//! In a non-streaming protocols, the client sends a complete request in a
//! single message, and the server provides a complete response in a single
//! message. Protocol tools in this style are available in the top-level `pipeline`
//! and `multiplex` modules.
//!
//! In a **streaming protocol**, requests and responses can carry **body
//! streams**, which allows partial processing before the complete body has been
//! transferred. Streaming protocol tools are found within the `streaming`
//! submodule.
//!
//! # Transports
//!
//! A key part of any protocol is its **transport**, which is the way that it
//! sends and received *frames* on its connection. For simple protocols, these
//! frames correspond directly to complete requests and responses. For more
//! complicated protocols, they carry additional metadata, and may only be one
//! part of a request or response body.
//!
//! Transports are defined by implementing the `transport::Transport` trait. The
//! `transport::CodecTransport` type can be used to wrap a `Codec` (from
//! `tokio-core`), which is a simple way to build a transport.
//!
//! # An example server
//!
//! The following code shows how to implement a simple server that receives
//! newline-separated integer values, doubles them, and returns them. It
//! illustrates several aspects of the Tokio stack:
//!
//! - Implementing a codec `IntCodec` for reading and writing integers from a
//!   byte buffer.
//! - Implementing a server protocol `IntProto` using this codec as a transport.
//! - Implementing a service `Doubler` for doubling integers.
//! - Spinning up this service on a local port (in `main`).
//!
//! ```no_run
//! extern crate futures;
//! extern crate tokio_core;
//! extern crate tokio_proto;
//! extern crate tokio_service;
//!
//! use std::str;
//! use std::io::{self, ErrorKind, Write};
//!
//! use futures::{future, Future, BoxFuture};
//! use tokio_core::io::{Io, Codec, Framed, EasyBuf};
//! use tokio_proto::TcpServer;
//! use tokio_proto::pipeline::ServerProto;
//! use tokio_service::Service;
//!
//! // First, we implement a *codec*, which provides a way of encoding and
//! // decoding messages for the protocol. See the documentation for `Codec` in
//! // `tokio-core` for more details on how that works.
//!
//! #[derive(Default)]
//! pub struct IntCodec;
//!
//! fn parse_u64(from: &[u8]) -> Result<u64, io::Error> {
//!     Ok(str::from_utf8(from)
//!        .map_err(|e| io::Error::new(ErrorKind::InvalidData, e))?
//!        .parse()
//!        .map_err(|e| io::Error::new(ErrorKind::InvalidData, e))?)
//! }
//!
//! impl Codec for IntCodec {
//!     type In = u64;
//!     type Out = u64;
//!
//!     // Attempt to decode a message from the given buffer if a complete
//!     // message is available; returns `Ok(None)` if the buffer does not yet
//!     // hold a complete message.
//!     fn decode(&mut self, buf: &mut EasyBuf) -> Result<Option<u64>, io::Error> {
//!         if let Some(i) = buf.as_slice().iter().position(|&b| b == b'\n') {
//!             // remove the line, including the '\n', from the buffer
//!             let full_line = buf.drain_to(i + 1);
//!
//!             // strip the'`\n'
//!             let slice = &full_line.as_slice()[..i];
//!
//!             Ok(Some(parse_u64(slice)?))
//!         } else {
//!             Ok(None)
//!         }
//!     }
//!
//!     // Attempt to decode a message assuming that the given buffer contains
//!     // *all* remaining input data.
//!     fn decode_eof(&mut self, buf: &mut EasyBuf) -> io::Result<u64> {
//!         let amt = buf.len();
//!         Ok(parse_u64(buf.drain_to(amt).as_slice())?)
//!     }
//!
//!     fn encode(&mut self, item: u64, into: &mut Vec<u8>) -> io::Result<()> {
//!         writeln!(into, "{}", item);
//!         Ok(())
//!     }
//! }
//!
//! // Next, we implement the server protocol, which just hooks up the codec above.
//!
//! pub struct IntProto;
//!
//! impl<T: Io + 'static> ServerProto<T> for IntProto {
//!     type Request = u64;
//!     type Response = u64;
//!     type Transport = Framed<T, IntCodec>;
//!     type BindTransport = Result<Self::Transport, io::Error>;
//!
//!     fn bind_transport(&self, io: T) -> Self::BindTransport {
//!         Ok(io.framed(IntCodec))
//!     }
//! }
//!
//! // Now we implement a service we'd like to run on top of this protocol
//!
//! pub struct Doubler;
//!
//! impl Service for Doubler {
//!     type Request = u64;
//!     type Response = u64;
//!     type Error = io::Error;
//!     type Future = BoxFuture<u64, io::Error>;
//!
//!     fn call(&self, req: u64) -> Self::Future {
//!         // Just return the request, doubled
//!         future::finished(req * 2).boxed()
//!     }
//! }
//!
//! // Finally, we can actually host this service locally!
//! fn main() {
//!     let addr = "0.0.0.0:12345".parse().unwrap();
//!     TcpServer::new(IntProto, addr)
//!         .serve(|| Ok(Doubler));
//! }
//! ```

#![doc(html_root_url = "https://docs.rs/tokio-proto/0.1")]
#![deny(warnings, missing_docs)]
#![allow(deprecated)] // TODO remove this

extern crate net2;
extern crate rand;
extern crate slab;
extern crate smallvec;
extern crate take;
extern crate tokio_core;
extern crate tokio_service;

#[macro_use]
extern crate futures;

#[macro_use]
extern crate log;

mod simple;
pub use simple::{pipeline, multiplex};

pub mod streaming;
pub mod util;

mod tcp_client;
pub use tcp_client::{TcpClient, Connect};

mod tcp_server;
pub use tcp_server::TcpServer;

use tokio_core::reactor::Handle;
use tokio_service::Service;

// TODO: move this into futures-rs
mod buffer_one;

/// Binds a service to an I/O object.
///
/// This trait is not intended to be implemented directly; instead, implement
/// one of the server protocol traits:
///
/// - `pipeline::ServerProto`
/// - `multiplex::ServerProto`
/// - `streaming::pipeline::ServerProto`
/// - `streaming::multiplex::ServerProto`
///
/// See the crate documentation for more details on those traits.
///
/// The `Kind` parameter, in particular, is a zero-sized type used to allow
/// blanket implementation from the various protocol traits. Any additional
/// implementations of this trait should use their own zero-sized kind type to
/// distinguish them.
pub trait BindServer<Kind, T: 'static>: 'static {
    /// The request type for the service.
    type ServiceRequest;

    /// The response type for the service.
    type ServiceResponse;

    /// The error type for the service.
    type ServiceError;

    /// Bind the service.
    ///
    /// This method should spawn a new task on the given event loop handle which
    /// provides the given service on the given I/O object.
    fn bind_server<S>(&self, handle: &Handle, io: T, service: S)
        where S: Service<Request = Self::ServiceRequest,
                         Response = Self::ServiceResponse,
                         Error = Self::ServiceError> + 'static;
}

/// Binds an I/O object as a client of a service.
///
/// This trait is not intended to be implemented directly; instead, implement
/// one of the server protocol traits:
///
/// - `pipeline::ClientProto`
/// - `multiplex::ClientProto`
/// - `streaming::pipeline::ClientProto`
/// - `streaming::multiplex::ClientProto`
///
/// See the crate documentation for more details on those traits.
///
/// The `Kind` parameter, in particular, is a zero-sized type used to allow
/// blanket implementation from the various protocol traits. Any additional
/// implementations of this trait should use their own zero-sized kind type to
/// distinguish them.
pub trait BindClient<Kind, T: 'static>: 'static {
    /// The request type for the service.
    type ServiceRequest;

    /// The response type for the service.
    type ServiceResponse;

    /// The error type for the service.
    type ServiceError;

    /// The bound service.
    type BindClient: Service<Request = Self::ServiceRequest,
                             Response = Self::ServiceResponse,
                             Error = Self::ServiceError>;

    /// Bind an I/O object as a service.
    fn bind_client(&self, handle: &Handle, io: T) -> Self::BindClient;
}
<commit_msg>fix typo in lib.rs<commit_after>//! This library provides a toolkit for rapid protocol development and usage,
//! working with the rest of the Tokio stack.
//!
//! You can find extensive documentation and tutorials in addition to this
//! documentation at [https://tokio.rs](https://tokio.rs)
//!
//! # Protocols
//!
//! Here, a **protocol** is a way of providing or consuming a service. Protocols
//! are implemented via traits, which are arranged into a taxonomy:
//!
//! - `pipeline::{ClientProto, ServerProto}`
//! - `multiplex::{ClientProto, ServerProto}`
//! - `streaming::pipeline::{ClientProto, ServerProto}`
//! - `streaming::multiplex::{ClientProto, ServerProto}`
//!
//! ### Pipeline vs multiplex
//!
//! By default, protocols allow a client to transmit multiple requests without
//! waiting for the corresponding responses, which is commonly used to improve
//! the throughput of single connections.
//!
//! In a **pipelined protocol**, the server responds to client requests in the
//! order they were sent. Example pipelined protocols include HTTP/1.1 and Redis.
//! Pipelining with the max number of in-flight requests set to 1 implies that
//! for each request, the response must be received before sending another
//! request on the same connection.
//!
//! In a **multiplexed protocol**, the server responds to client requests in the
//! order of completion. Request IDs are used to match responses back to requests.
//!
//! In both cases, if multiple requests are sent, the service running on the
//! server *may* process them concurrently, although many services will impose
//! some restrictions depending on the request type.
//!
//! ### Streaming
//!
//! In a non-streaming protocols, the client sends a complete request in a
//! single message, and the server provides a complete response in a single
//! message. Protocol tools in this style are available in the top-level `pipeline`
//! and `multiplex` modules.
//!
//! In a **streaming protocol**, requests and responses can carry **body
//! streams**, which allows partial processing before the complete body has been
//! transferred. Streaming protocol tools are found within the `streaming`
//! submodule.
//!
//! # Transports
//!
//! A key part of any protocol is its **transport**, which is the way that it
//! sends and receives *frames* on its connection. For simple protocols, these
//! frames correspond directly to complete requests and responses. For more
//! complicated protocols, they carry additional metadata, and may only be one
//! part of a request or response body.
//!
//! Transports are defined by implementing the `transport::Transport` trait. The
//! `transport::CodecTransport` type can be used to wrap a `Codec` (from
//! `tokio-core`), which is a simple way to build a transport.
//!
//! # An example server
//!
//! The following code shows how to implement a simple server that receives
//! newline-separated integer values, doubles them, and returns them. It
//! illustrates several aspects of the Tokio stack:
//!
//! - Implementing a codec `IntCodec` for reading and writing integers from a
//!   byte buffer.
//! - Implementing a server protocol `IntProto` using this codec as a transport.
//! - Implementing a service `Doubler` for doubling integers.
//! - Spinning up this service on a local port (in `main`).
//!
//! ```no_run
//! extern crate futures;
//! extern crate tokio_core;
//! extern crate tokio_proto;
//! extern crate tokio_service;
//!
//! use std::str;
//! use std::io::{self, ErrorKind, Write};
//!
//! use futures::{future, Future, BoxFuture};
//! use tokio_core::io::{Io, Codec, Framed, EasyBuf};
//! use tokio_proto::TcpServer;
//! use tokio_proto::pipeline::ServerProto;
//! use tokio_service::Service;
//!
//! // First, we implement a *codec*, which provides a way of encoding and
//! // decoding messages for the protocol. See the documentation for `Codec` in
//! // `tokio-core` for more details on how that works.
//!
//! #[derive(Default)]
//! pub struct IntCodec;
//!
//! fn parse_u64(from: &[u8]) -> Result<u64, io::Error> {
//!     Ok(str::from_utf8(from)
//!        .map_err(|e| io::Error::new(ErrorKind::InvalidData, e))?
//!        .parse()
//!        .map_err(|e| io::Error::new(ErrorKind::InvalidData, e))?)
//! }
//!
//! impl Codec for IntCodec {
//!     type In = u64;
//!     type Out = u64;
//!
//!     // Attempt to decode a message from the given buffer if a complete
//!     // message is available; returns `Ok(None)` if the buffer does not yet
//!     // hold a complete message.
//!     fn decode(&mut self, buf: &mut EasyBuf) -> Result<Option<u64>, io::Error> {
//!         if let Some(i) = buf.as_slice().iter().position(|&b| b == b'\n') {
//!             // remove the line, including the '\n', from the buffer
//!             let full_line = buf.drain_to(i + 1);
//!
//!             // strip the'`\n'
//!             let slice = &full_line.as_slice()[..i];
//!
//!             Ok(Some(parse_u64(slice)?))
//!         } else {
//!             Ok(None)
//!         }
//!     }
//!
//!     // Attempt to decode a message assuming that the given buffer contains
//!     // *all* remaining input data.
//!     fn decode_eof(&mut self, buf: &mut EasyBuf) -> io::Result<u64> {
//!         let amt = buf.len();
//!         Ok(parse_u64(buf.drain_to(amt).as_slice())?)
//!     }
//!
//!     fn encode(&mut self, item: u64, into: &mut Vec<u8>) -> io::Result<()> {
//!         writeln!(into, "{}", item);
//!         Ok(())
//!     }
//! }
//!
//! // Next, we implement the server protocol, which just hooks up the codec above.
//!
//! pub struct IntProto;
//!
//! impl<T: Io + 'static> ServerProto<T> for IntProto {
//!     type Request = u64;
//!     type Response = u64;
//!     type Transport = Framed<T, IntCodec>;
//!     type BindTransport = Result<Self::Transport, io::Error>;
//!
//!     fn bind_transport(&self, io: T) -> Self::BindTransport {
//!         Ok(io.framed(IntCodec))
//!     }
//! }
//!
//! // Now we implement a service we'd like to run on top of this protocol
//!
//! pub struct Doubler;
//!
//! impl Service for Doubler {
//!     type Request = u64;
//!     type Response = u64;
//!     type Error = io::Error;
//!     type Future = BoxFuture<u64, io::Error>;
//!
//!     fn call(&self, req: u64) -> Self::Future {
//!         // Just return the request, doubled
//!         future::finished(req * 2).boxed()
//!     }
//! }
//!
//! // Finally, we can actually host this service locally!
//! fn main() {
//!     let addr = "0.0.0.0:12345".parse().unwrap();
//!     TcpServer::new(IntProto, addr)
//!         .serve(|| Ok(Doubler));
//! }
//! ```

#![doc(html_root_url = "https://docs.rs/tokio-proto/0.1")]
#![deny(warnings, missing_docs)]
#![allow(deprecated)] // TODO remove this

extern crate net2;
extern crate rand;
extern crate slab;
extern crate smallvec;
extern crate take;
extern crate tokio_core;
extern crate tokio_service;

#[macro_use]
extern crate futures;

#[macro_use]
extern crate log;

mod simple;
pub use simple::{pipeline, multiplex};

pub mod streaming;
pub mod util;

mod tcp_client;
pub use tcp_client::{TcpClient, Connect};

mod tcp_server;
pub use tcp_server::TcpServer;

use tokio_core::reactor::Handle;
use tokio_service::Service;

// TODO: move this into futures-rs
mod buffer_one;

/// Binds a service to an I/O object.
///
/// This trait is not intended to be implemented directly; instead, implement
/// one of the server protocol traits:
///
/// - `pipeline::ServerProto`
/// - `multiplex::ServerProto`
/// - `streaming::pipeline::ServerProto`
/// - `streaming::multiplex::ServerProto`
///
/// See the crate documentation for more details on those traits.
///
/// The `Kind` parameter, in particular, is a zero-sized type used to allow
/// blanket implementation from the various protocol traits. Any additional
/// implementations of this trait should use their own zero-sized kind type to
/// distinguish them.
pub trait BindServer<Kind, T: 'static>: 'static {
    /// The request type for the service.
    type ServiceRequest;

    /// The response type for the service.
    type ServiceResponse;

    /// The error type for the service.
    type ServiceError;

    /// Bind the service.
    ///
    /// This method should spawn a new task on the given event loop handle which
    /// provides the given service on the given I/O object.
    fn bind_server<S>(&self, handle: &Handle, io: T, service: S)
        where S: Service<Request = Self::ServiceRequest,
                         Response = Self::ServiceResponse,
                         Error = Self::ServiceError> + 'static;
}

/// Binds an I/O object as a client of a service.
///
/// This trait is not intended to be implemented directly; instead, implement
/// one of the server protocol traits:
///
/// - `pipeline::ClientProto`
/// - `multiplex::ClientProto`
/// - `streaming::pipeline::ClientProto`
/// - `streaming::multiplex::ClientProto`
///
/// See the crate documentation for more details on those traits.
///
/// The `Kind` parameter, in particular, is a zero-sized type used to allow
/// blanket implementation from the various protocol traits. Any additional
/// implementations of this trait should use their own zero-sized kind type to
/// distinguish them.
pub trait BindClient<Kind, T: 'static>: 'static {
    /// The request type for the service.
    type ServiceRequest;

    /// The response type for the service.
    type ServiceResponse;

    /// The error type for the service.
    type ServiceError;

    /// The bound service.
    type BindClient: Service<Request = Self::ServiceRequest,
                             Response = Self::ServiceResponse,
                             Error = Self::ServiceError>;

    /// Bind an I/O object as a service.
    fn bind_client(&self, handle: &Handle, io: T) -> Self::BindClient;
}
<|endoftext|>


<commit_before>#![feature(associated_consts)]
#![feature(drain)]

extern crate uuid;
extern crate typed_arena;
mod js_types;
mod alloc;

use std::collections::hash_set::HashSet;
use std::ptr::null_mut;
use std::rc::Rc;
use uuid::Uuid;

use alloc::scope::Scope;
use js_types::js_type::JsVar;

pub struct ScopeManager {
    root_scope: Rc<Scope>,
    curr_scope: *mut Rc<Scope>,
}

impl ScopeManager {
    pub fn new<F>(callback: F) -> ScopeManager where F: Fn() -> HashSet<Uuid> + 'static {
        let scope = Rc::new(Scope::new(callback));
        let mut mgr =
            ScopeManager {
                root_scope: scope,
                curr_scope: null_mut(),
            };
        mgr.curr_scope = &mut (mgr.root_scope) as *mut Rc<Scope>;
        mgr
    }

    pub fn add_scope<F>(&mut self, callback: F) where F: Fn() -> HashSet<Uuid> + 'static {
        unsafe {
            let weak_clone = Rc::downgrade(&*self.curr_scope.clone());
            self.curr_scope =
                Rc::get_mut(&mut *self.curr_scope)
                    .unwrap()
                    .add_child(Scope::as_child(weak_clone, callback)) as *mut Rc<Scope>;
        }
    }

    pub fn alloc(&mut self, var: JsVar) -> Uuid {
        unsafe {
            Rc::get_mut(&mut *self.curr_scope).unwrap().alloc(var)
        }
    }
}

pub fn init<F>(callback: F) -> ScopeManager
    where F: Fn() -> HashSet<Uuid> + 'static {
    ScopeManager::new(callback)
}

pub fn load(scope: &Scope, uuid: Uuid) -> Option<JsVar> {
    scope.get_var_copy(&uuid)
}

pub fn store(scope: &mut Scope, var: JsVar) -> bool {
    scope.update_var(var)
}
<commit_msg>Rename ScopeManager::add_scope -> push_scope<commit_after>#![feature(associated_consts)]
#![feature(drain)]

extern crate uuid;
extern crate typed_arena;
mod js_types;
mod alloc;

use std::collections::hash_set::HashSet;
use std::ptr::null_mut;
use std::rc::Rc;
use uuid::Uuid;

use alloc::scope::Scope;
use js_types::js_type::JsVar;

pub struct ScopeManager {
    root_scope: Rc<Scope>,
    curr_scope: *mut Rc<Scope>,
}

impl ScopeManager {
    pub fn new<F>(callback: F) -> ScopeManager where F: Fn() -> HashSet<Uuid> + 'static {
        let scope = Rc::new(Scope::new(callback));
        let mut mgr =
            ScopeManager {
                root_scope: scope,
                curr_scope: null_mut(),
            };
        mgr.curr_scope = &mut (mgr.root_scope) as *mut Rc<Scope>;
        mgr
    }

    pub fn push_scope<F>(&mut self, callback: F) where F: Fn() -> HashSet<Uuid> + 'static {
        unsafe {
            let weak_clone = Rc::downgrade(&*self.curr_scope.clone());
            self.curr_scope =
                Rc::get_mut(&mut *self.curr_scope)
                    .unwrap()
                    .add_child(Scope::as_child(weak_clone, callback)) as *mut Rc<Scope>;
        }
    }

    pub fn alloc(&mut self, var: JsVar) -> Uuid {
        unsafe {
            Rc::get_mut(&mut *self.curr_scope).unwrap().alloc(var)
        }
    }
}

pub fn init<F>(callback: F) -> ScopeManager
    where F: Fn() -> HashSet<Uuid> + 'static {
    ScopeManager::new(callback)
}

pub fn load(scope: &Scope, uuid: Uuid) -> Option<JsVar> {
    scope.get_var_copy(&uuid)
}

pub fn store(scope: &mut Scope, var: JsVar) -> bool {
    scope.update_var(var)
}
<|endoftext|>


<commit_before>//! A library for controlling i3-wm through its ipc interface.

extern crate unix_socket;
extern crate byteorder;
extern crate serde;

use std::process;
use unix_socket::UnixStream;
use std::io;
use std::io::prelude::*;
use byteorder::{ReadBytesExt, WriteBytesExt, LittleEndian};
use serde::json;

mod readhelp;
pub mod reply;

pub enum Event {
    // none of these are complete
    Workspace,
    Output,
    Mode,
    Window,
    BarConfigUpdate,
    Binding
}

/// An error while instantiating an I3Connection. Creating an I3Connection involves first getting
/// the i3 socket path, then connecting to the socket. Either part could go wrong, which is why
/// there are two possibilities here.
#[derive(Debug)]
pub enum I3ConnectError {
    /// An error while getting the socket path
    GetSocketPathError(io::Error),
    /// An error while accessing the socket
    SocketError(io::Error)
}

pub struct I3Connection {
    stream: UnixStream
}

impl I3Connection {

    /// Establishes an IPC connection to i3.
    pub fn connect() -> Result<I3Connection, I3ConnectError> {
        fn get_socket_path() -> io::Result<String> {
            let output = try!(process::Command::new("i3")
                                               .arg("--get-socketpath")
                                               .output());
            if output.status.success() {
                Ok(String::from_utf8_lossy(&output.stdout)
                          .trim_right_matches('\n')
                          .to_owned())
            } else {
                let prefix = "i3 --getsocketpath didn't return 0";
                let error_text = if output.stderr.len() > 0 {
                    format!("{}. stderr: {:?}", prefix, output.stderr)
                } else {
                    prefix.to_owned()
                };
                let error = io::Error::new(io::ErrorKind::Other, error_text);
                Err(error)
            }
        }

        return match get_socket_path() {
            Ok(path) => {
                match UnixStream::connect(path) {
                    Ok(stream) => Ok(I3Connection { stream: stream }),
                    Err(error) => Err(I3ConnectError::SocketError(error))
                }
            }
            Err(error) => Err(I3ConnectError::GetSocketPathError(error))
        }
    }

    fn send_message(&mut self, message_type: u32, payload: &str) -> io::Result<()> {
        let mut bytes = Vec::with_capacity(14 + payload.len());
        bytes.extend("i3-ipc".bytes());                              // 6 bytes
        try!(bytes.write_u32::<LittleEndian>(payload.len() as u32)); // 4 bytes
        try!(bytes.write_u32::<LittleEndian>(message_type));         // 4 bytes
        bytes.extend(payload.bytes());                               // payload.len() bytes
        self.stream.write_all(&bytes[..])
    }

    fn receive_message(&mut self) -> io::Result<String> {
        let magic_data = try!(readhelp::read_exact(&mut self.stream, 6));
        let magic_string = String::from_utf8_lossy(&magic_data);
        if magic_string != "i3-ipc" {
            let error_text = format!("unexpected magic string: expected 'i3-ipc' but got {}",
                                      magic_string);
            return Err(io::Error::new(io::ErrorKind::Other, error_text));
        }
        let payload_len = try!(self.stream.read_u32::<LittleEndian>());
        let message_type = try!(self.stream.read_u32::<LittleEndian>());
        let payload_data = try!(readhelp::read_exact(&mut self.stream, payload_len as usize));
        Ok(String::from_utf8_lossy(&payload_data).into_owned())
    }

    /// The payload of the message is a command for i3 (like the commands you can bind to keys
    /// in the configuration file) and will be executed directly after receiving it.
    pub fn command(&mut self, string: &str) -> io::Result<reply::Command> {
        try!(self.send_message(0, string));
        let payload = try!(self.receive_message());

        // assumes valid json
        let j: json::Value = json::from_str(&payload).unwrap();
        let commands = j.as_array().unwrap();
        let vec: Vec<_>
            = commands.iter()
                      .map(|c|
                           reply::CommandOutcome {
                               success: c.find("success").unwrap().as_boolean().unwrap(),
                               error: match c.find("error") {
                                   Some(val) => Some(val.as_string().unwrap().to_owned()),
                                   None => None
                               }
                           })
                      .collect();

        Ok(reply::Command { outcomes: vec })
    }

    fn unpack_rect(jrect: &json::Value) -> (i32, i32, i32, i32) {
        let x = jrect.find("x").unwrap().as_i64().unwrap() as i32;
        let y = jrect.find("y").unwrap().as_i64().unwrap() as i32;
        let width = jrect.find("width").unwrap().as_i64().unwrap() as i32;
        let height = jrect.find("height").unwrap().as_i64().unwrap() as i32;
        (x, y, width, height)
    }

    /// Gets the current workspaces.
    pub fn get_workspaces(&mut self) -> io::Result<reply::Workspaces> {
        try!(self.send_message(1, ""));
        let payload = try!(self.receive_message());

        let j: json::Value = json::from_str(&payload).unwrap();
        let jworkspaces = j.as_array().unwrap();
        let workspaces: Vec<_>
            = jworkspaces.iter()
                         .map(|w|
                              reply::Workspace {
                                  num: w.find("num").unwrap().as_i64().unwrap() as i32,
                                  name: w.find("name").unwrap().as_string().unwrap().to_owned(),
                                  visible: w.find("visible").unwrap().as_boolean().unwrap(),
                                  focused: w.find("focused").unwrap().as_boolean().unwrap(),
                                  urgent: w.find("urgent").unwrap().as_boolean().unwrap(),
                                  rect: I3Connection::unpack_rect(w.find("rect").unwrap()),
                                  output: w.find("output").unwrap().as_string().unwrap().to_owned()
                              })
                         .collect();
        Ok(reply::Workspaces { workspaces: workspaces })
    }

    /// Subscribes your connection to certain events.
    pub fn subscribe(&mut self) -> io::Result<reply::Subscribe> {
        panic!("not implemented");
    }

    /// Gets the current outputs.
    pub fn get_outputs(&mut self) -> io::Result<reply::Outputs> {
        try!(self.send_message(3, ""));
        let payload = try!(self.receive_message());

        let j: json::Value = json::from_str(&payload).unwrap();
        let joutputs = j.as_array().unwrap();
        let outputs: Vec<_>
            = joutputs.iter()
                      .map(|o|
                           reply::Output {
                               name: o.find("name").unwrap().as_string().unwrap().to_owned(),
                               active: o.find("active").unwrap().as_boolean().unwrap(),
                               current_workspace: match o.find("current_workspace").unwrap().clone() {
                                   json::Value::String(c_w) => Some(c_w),
                                   json::Value::Null => None,
                                   _ => unreachable!()
                               },
                               rect: I3Connection::unpack_rect(o.find("rect").unwrap())
                           })
                      .collect();
        Ok(reply::Outputs { outputs: outputs })
    }

    /// Gets the layout tree. i3 uses a tree as data structure which includes every container.
    pub fn get_tree(&mut self) -> io::Result<reply::Tree> {
        panic!("not implemented");
    }

    /// Gets a list of marks (identifiers for containers to easily jump to them later).
    pub fn get_marks(&mut self) -> io::Result<reply::Marks> {
        panic!("not implemented");
    }

    /// Gets an array with all configured bar IDs.
    pub fn get_bar_ids(&mut self) -> io::Result<reply::BarIds> {
        panic!("not implemented");
    }

    /// Gets the configuration of the workspace bar with the given ID.
    pub fn get_bar_config(&mut self, id: &str) -> io::Result<reply::BarConfig> {
        panic!("not implemented");
    }

    /// Gets the version of i3. The reply will include the major, minor, patch and human-readable
    /// version.
    pub fn get_version(&mut self) -> io::Result<reply::Version> {
        panic!("not implemented");
    }
}

#[cfg(test)]
mod test {
    use I3Connection;

    // for the following tests send a request and get the reponse.
    // response types are specific so often getting them at all indicates success.
    // can't do much better without mocking an i3 installation.

    #[test]
    fn connect() {
        I3Connection::connect().unwrap();
    }

    #[test]
    fn command_nothing() {
        let mut connection = I3Connection::connect().unwrap();
        let result = connection.command("").unwrap();
        assert_eq!(result.outcomes.len(), 0);
    }

    #[test]
    fn command_single_sucess() {
        let mut connection = I3Connection::connect().unwrap();
        let a = connection.command("exec /bin/true").unwrap();
        assert_eq!(a.outcomes.len(), 1);
        assert!(a.outcomes[0].success);
    }

    #[test]
    fn command_multiple_success() {
        let mut connection = I3Connection::connect().unwrap();
        let result = connection.command("exec /bin/true; exec /bin/true").unwrap();
        assert_eq!(result.outcomes.len(), 2);
        assert!(result.outcomes[0].success);
        assert!(result.outcomes[1].success);
    }

    #[test]
    fn command_fail() {
        let mut connection = I3Connection::connect().unwrap();
        let result = connection.command("ThisIsClearlyNotACommand").unwrap();
        assert_eq!(result.outcomes.len(), 1);
        assert!(!result.outcomes[0].success);
    }

    #[test]
    fn get_workspaces() {
        I3Connection::connect().unwrap().get_workspaces().unwrap();
    }

    #[test]
    fn subscribe() {
        I3Connection::connect().unwrap().subscribe().unwrap();
    }

    #[test]
    fn get_outputs() {
        I3Connection::connect().unwrap().get_outputs().unwrap();
    }

    #[test]
    fn get_tree() {
        I3Connection::connect().unwrap().get_tree().unwrap();
    }

    #[test]
    fn get_marks() {
        I3Connection::connect().unwrap().get_marks().unwrap();
    }

    #[test]
    fn get_bar_ids() {
        I3Connection::connect().unwrap().get_bar_ids().unwrap();
    }

    #[test]
    fn get_bar_ids_and_one_config() {
        let mut connection = I3Connection::connect().unwrap();
        let ids = connection.get_bar_ids().unwrap().ids;
        let oneconfig = connection.get_bar_config(&ids[0]).unwrap();
    }

    #[test]
    fn get_version() {
        I3Connection::connect().unwrap().get_version().unwrap();
    }
}
<commit_msg>implement get_marks<commit_after>//! A library for controlling i3-wm through its ipc interface.

extern crate unix_socket;
extern crate byteorder;
extern crate serde;

use std::process;
use unix_socket::UnixStream;
use std::io;
use std::io::prelude::*;
use byteorder::{ReadBytesExt, WriteBytesExt, LittleEndian};
use serde::json;

mod readhelp;
pub mod reply;

pub enum Event {
    // none of these are complete
    Workspace,
    Output,
    Mode,
    Window,
    BarConfigUpdate,
    Binding
}

/// An error while instantiating an I3Connection. Creating an I3Connection involves first getting
/// the i3 socket path, then connecting to the socket. Either part could go wrong, which is why
/// there are two possibilities here.
#[derive(Debug)]
pub enum I3ConnectError {
    /// An error while getting the socket path
    GetSocketPathError(io::Error),
    /// An error while accessing the socket
    SocketError(io::Error)
}

pub struct I3Connection {
    stream: UnixStream
}

impl I3Connection {

    /// Establishes an IPC connection to i3.
    pub fn connect() -> Result<I3Connection, I3ConnectError> {
        fn get_socket_path() -> io::Result<String> {
            let output = try!(process::Command::new("i3")
                                               .arg("--get-socketpath")
                                               .output());
            if output.status.success() {
                Ok(String::from_utf8_lossy(&output.stdout)
                          .trim_right_matches('\n')
                          .to_owned())
            } else {
                let prefix = "i3 --getsocketpath didn't return 0";
                let error_text = if output.stderr.len() > 0 {
                    format!("{}. stderr: {:?}", prefix, output.stderr)
                } else {
                    prefix.to_owned()
                };
                let error = io::Error::new(io::ErrorKind::Other, error_text);
                Err(error)
            }
        }

        return match get_socket_path() {
            Ok(path) => {
                match UnixStream::connect(path) {
                    Ok(stream) => Ok(I3Connection { stream: stream }),
                    Err(error) => Err(I3ConnectError::SocketError(error))
                }
            }
            Err(error) => Err(I3ConnectError::GetSocketPathError(error))
        }
    }

    fn send_message(&mut self, message_type: u32, payload: &str) -> io::Result<()> {
        let mut bytes = Vec::with_capacity(14 + payload.len());
        bytes.extend("i3-ipc".bytes());                              // 6 bytes
        try!(bytes.write_u32::<LittleEndian>(payload.len() as u32)); // 4 bytes
        try!(bytes.write_u32::<LittleEndian>(message_type));         // 4 bytes
        bytes.extend(payload.bytes());                               // payload.len() bytes
        self.stream.write_all(&bytes[..])
    }

    fn receive_message(&mut self) -> io::Result<String> {
        let magic_data = try!(readhelp::read_exact(&mut self.stream, 6));
        let magic_string = String::from_utf8_lossy(&magic_data);
        if magic_string != "i3-ipc" {
            let error_text = format!("unexpected magic string: expected 'i3-ipc' but got {}",
                                      magic_string);
            return Err(io::Error::new(io::ErrorKind::Other, error_text));
        }
        let payload_len = try!(self.stream.read_u32::<LittleEndian>());
        let message_type = try!(self.stream.read_u32::<LittleEndian>());
        let payload_data = try!(readhelp::read_exact(&mut self.stream, payload_len as usize));
        Ok(String::from_utf8_lossy(&payload_data).into_owned())
    }

    /// The payload of the message is a command for i3 (like the commands you can bind to keys
    /// in the configuration file) and will be executed directly after receiving it.
    pub fn command(&mut self, string: &str) -> io::Result<reply::Command> {
        try!(self.send_message(0, string));
        let payload = try!(self.receive_message());

        // assumes valid json
        let j: json::Value = json::from_str(&payload).unwrap();
        let commands = j.as_array().unwrap();
        let vec: Vec<_>
            = commands.iter()
                      .map(|c|
                           reply::CommandOutcome {
                               success: c.find("success").unwrap().as_boolean().unwrap(),
                               error: match c.find("error") {
                                   Some(val) => Some(val.as_string().unwrap().to_owned()),
                                   None => None
                               }
                           })
                      .collect();

        Ok(reply::Command { outcomes: vec })
    }

    fn unpack_rect(jrect: &json::Value) -> (i32, i32, i32, i32) {
        let x = jrect.find("x").unwrap().as_i64().unwrap() as i32;
        let y = jrect.find("y").unwrap().as_i64().unwrap() as i32;
        let width = jrect.find("width").unwrap().as_i64().unwrap() as i32;
        let height = jrect.find("height").unwrap().as_i64().unwrap() as i32;
        (x, y, width, height)
    }

    /// Gets the current workspaces.
    pub fn get_workspaces(&mut self) -> io::Result<reply::Workspaces> {
        try!(self.send_message(1, ""));
        let payload = try!(self.receive_message());

        let j: json::Value = json::from_str(&payload).unwrap();
        let jworkspaces = j.as_array().unwrap();
        let workspaces: Vec<_>
            = jworkspaces.iter()
                         .map(|w|
                              reply::Workspace {
                                  num: w.find("num").unwrap().as_i64().unwrap() as i32,
                                  name: w.find("name").unwrap().as_string().unwrap().to_owned(),
                                  visible: w.find("visible").unwrap().as_boolean().unwrap(),
                                  focused: w.find("focused").unwrap().as_boolean().unwrap(),
                                  urgent: w.find("urgent").unwrap().as_boolean().unwrap(),
                                  rect: I3Connection::unpack_rect(w.find("rect").unwrap()),
                                  output: w.find("output").unwrap().as_string().unwrap().to_owned()
                              })
                         .collect();
        Ok(reply::Workspaces { workspaces: workspaces })
    }

    /// Subscribes your connection to certain events.
    pub fn subscribe(&mut self) -> io::Result<reply::Subscribe> {
        panic!("not implemented");
    }

    /// Gets the current outputs.
    pub fn get_outputs(&mut self) -> io::Result<reply::Outputs> {
        try!(self.send_message(3, ""));
        let payload = try!(self.receive_message());

        let j: json::Value = json::from_str(&payload).unwrap();
        let joutputs = j.as_array().unwrap();
        let outputs: Vec<_>
            = joutputs.iter()
                      .map(|o|
                           reply::Output {
                               name: o.find("name").unwrap().as_string().unwrap().to_owned(),
                               active: o.find("active").unwrap().as_boolean().unwrap(),
                               current_workspace: match o.find("current_workspace").unwrap().clone() {
                                   json::Value::String(c_w) => Some(c_w),
                                   json::Value::Null => None,
                                   _ => unreachable!()
                               },
                               rect: I3Connection::unpack_rect(o.find("rect").unwrap())
                           })
                      .collect();
        Ok(reply::Outputs { outputs: outputs })
    }

    /// Gets the layout tree. i3 uses a tree as data structure which includes every container.
    pub fn get_tree(&mut self) -> io::Result<reply::Tree> {
        panic!("not implemented");
    }

    /// Gets a list of marks (identifiers for containers to easily jump to them later).
    pub fn get_marks(&mut self) -> io::Result<reply::Marks> {
        try!(self.send_message(5, ""));
        let payload = try!(self.receive_message());
        let marks: Vec<String> = json::from_str(&payload).unwrap();
        Ok(reply::Marks { marks: marks })
    }

    /// Gets an array with all configured bar IDs.
    pub fn get_bar_ids(&mut self) -> io::Result<reply::BarIds> {
        panic!("not implemented");
    }

    /// Gets the configuration of the workspace bar with the given ID.
    pub fn get_bar_config(&mut self, id: &str) -> io::Result<reply::BarConfig> {
        panic!("not implemented");
    }

    /// Gets the version of i3. The reply will include the major, minor, patch and human-readable
    /// version.
    pub fn get_version(&mut self) -> io::Result<reply::Version> {
        panic!("not implemented");
    }
}

#[cfg(test)]
mod test {
    use I3Connection;

    // for the following tests send a request and get the reponse.
    // response types are specific so often getting them at all indicates success.
    // can't do much better without mocking an i3 installation.

    #[test]
    fn connect() {
        I3Connection::connect().unwrap();
    }

    #[test]
    fn command_nothing() {
        let mut connection = I3Connection::connect().unwrap();
        let result = connection.command("").unwrap();
        assert_eq!(result.outcomes.len(), 0);
    }

    #[test]
    fn command_single_sucess() {
        let mut connection = I3Connection::connect().unwrap();
        let a = connection.command("exec /bin/true").unwrap();
        assert_eq!(a.outcomes.len(), 1);
        assert!(a.outcomes[0].success);
    }

    #[test]
    fn command_multiple_success() {
        let mut connection = I3Connection::connect().unwrap();
        let result = connection.command("exec /bin/true; exec /bin/true").unwrap();
        assert_eq!(result.outcomes.len(), 2);
        assert!(result.outcomes[0].success);
        assert!(result.outcomes[1].success);
    }

    #[test]
    fn command_fail() {
        let mut connection = I3Connection::connect().unwrap();
        let result = connection.command("ThisIsClearlyNotACommand").unwrap();
        assert_eq!(result.outcomes.len(), 1);
        assert!(!result.outcomes[0].success);
    }

    #[test]
    fn get_workspaces() {
        I3Connection::connect().unwrap().get_workspaces().unwrap();
    }

    #[test]
    fn subscribe() {
        I3Connection::connect().unwrap().subscribe().unwrap();
    }

    #[test]
    fn get_outputs() {
        I3Connection::connect().unwrap().get_outputs().unwrap();
    }

    #[test]
    fn get_tree() {
        I3Connection::connect().unwrap().get_tree().unwrap();
    }

    #[test]
    fn get_marks() {
        I3Connection::connect().unwrap().get_marks().unwrap();
    }

    #[test]
    fn get_bar_ids() {
        I3Connection::connect().unwrap().get_bar_ids().unwrap();
    }

    #[test]
    fn get_bar_ids_and_one_config() {
        let mut connection = I3Connection::connect().unwrap();
        let ids = connection.get_bar_ids().unwrap().ids;
        let oneconfig = connection.get_bar_config(&ids[0]).unwrap();
    }

    #[test]
    fn get_version() {
        I3Connection::connect().unwrap().get_version().unwrap();
    }
}
<|endoftext|>


<commit_before>#![crate_id = "staticfile"]
#![deny(missing_doc)]
#![feature(phase)]

//! Static file-serving middleware.

extern crate url;
#[phase(plugin, link)]
extern crate log;
extern crate http;
extern crate iron;
extern crate mount;

use iron::{Request, Response, Middleware, Alloy};
use iron::mixin::{GetUrl, Serve};
use iron::middleware::{Status, Continue, Unwind};
use mount::OriginalUrl;

/// The static file-serving `Middleware`.
#[deriving(Clone)]
pub struct Static {
    root_path: Path
}

impl Static {
    /// Create a new instance of `Static` with a given root path.
    ///
    /// This will attempt to serve static files from the given root path.
    /// The path may be relative or absolute. If `Path::new("")` is given,
    /// files will be served from the current directory.
    ///
    /// If a static file exists and can be read from, `enter` will serve it to
    /// the `Response` and `Unwind` the middleware stack with a status of `200`.
    ///
    /// In the case of any error, it will `Continue` through the stack.
    /// If a file should have been read but cannot, due to permissions or
    /// read errors, a different `Middleware` should handle it.
    ///
    /// If the path is '/', it will attempt to serve `index.html`.
    pub fn new(root_path: Path) -> Static {
        Static {
            root_path: root_path
        }
    }
}

impl Middleware for Static {
    fn enter(&mut self, req: &mut Request, res: &mut Response, alloy: &mut Alloy) -> Status {
        match req.url() {
            Some(path) => {
                // Check for requested file
                match res.serve_file(&self.root_path.join(
                    Path::new(
                        // Coerce to relative path.
                        // We include the slash to ensure that you never have a path like ".index.html"
                        // when you meant "./index.html", see http://is.gd/yz9p0B for an example.
                        "./".to_string().append(path.as_slice())))) {
                    Ok(()) => {
                        debug!("Serving static file at {}.",
                            &self.root_path.join("./".to_string().append(path.as_slice())).display());
                        return Unwind
                    },
                    Err(_) => ()
                }

                // Check for index.html
                let index_path = self.root_path.join(
                    Path::new("./".to_string().append(path.as_slice()))
                        .join("./index.html".to_string()));
                if index_path.is_file() {
                    // Avoid serving as a directory
                    if path.len() > 0 {
                        match path.as_slice().char_at_reverse(path.len()) {
                            '/' => {
                                match res.serve_file(&index_path) {
                                    Ok(()) => {
                                        debug!("Serving static file at {}.",
                                            &index_path.display());
                                        return Unwind
                                    },
                                    Err(err) => {
                                        debug!("Failed while trying to serve index.html: {}", err)
                                        return Continue
                                    }
                                }
                            },
                    // 303:
                            _ => ()
                        }
                    }
                    let redirect_path = match alloy.find::<OriginalUrl>() {
                        Some(&OriginalUrl(ref original_url)) => original_url.clone(),
                        None => path.clone()
                    }.append("/");
                    res.headers.extensions.insert("Location".to_string(), redirect_path.clone());
                    let _ = res.serve(::http::status::SeeOther,
                        format!("Redirecting to {}/", redirect_path).as_slice());
                    return Unwind
                }
            },
            None => ()
        }
        Continue
    }
}
<commit_msg>(feat) Added favicon.<commit_after>#![crate_id = "staticfile"]
#![deny(missing_doc)]
#![feature(phase)]

//! Static file-serving middleware.

extern crate url;
#[phase(plugin)]
extern crate regex_macros;
extern crate regex;

#[phase(plugin, link)]
extern crate log;
extern crate http;
extern crate iron;
extern crate mount;

use iron::{Request, Response, Middleware, Alloy};
use iron::mixin::{GetUrl, Serve};
use iron::middleware::{Status, Continue, Unwind};
use mount::OriginalUrl;

/// The static file-serving `Middleware`.
#[deriving(Clone)]
pub struct Static {
    root_path: Path
}

#[deriving(Clone)]
struct Favicon {
    favicon_path: Path
}

impl Static {
    /// Create a new instance of `Static` with a given root path.
    ///
    /// This will attempt to serve static files from the given root path.
    /// The path may be relative or absolute. If `Path::new("")` is given,
    /// files will be served from the current directory.
    ///
    /// If a static file exists and can be read from, `enter` will serve it to
    /// the `Response` and `Unwind` the middleware stack with a status of `200`.
    ///
    /// In the case of any error, it will `Continue` through the stack.
    /// If a file should have been read but cannot, due to permissions or
    /// read errors, a different `Middleware` should handle it.
    ///
    /// If the path is '/', it will attempt to serve `index.html`.
    pub fn new(root_path: Path) -> Static {
        Static {
            root_path: root_path
        }
    }

    pub fn favicon(favicon_path: Path) -> Favicon {
        Favicon {
            favicon_path: favicon_path
        }
    }
}

impl Middleware for Static {
    fn enter(&mut self, req: &mut Request, res: &mut Response, alloy: &mut Alloy) -> Status {
        match req.url() {
            Some(path) => {
                // Check for requested file
                match res.serve_file(&self.root_path.join(
                    Path::new(
                        // Coerce to relative path.
                        // We include the slash to ensure that you never have a path like ".index.html"
                        // when you meant "./index.html", see http://is.gd/yz9p0B for an example.
                        "./".to_string().append(path.as_slice())))) {
                    Ok(()) => {
                        debug!("Serving static file at {}.",
                            &self.root_path.join("./".to_string().append(path.as_slice())).display());
                        return Unwind
                    },
                    Err(_) => ()
                }

                // Check for index.html
                let index_path = self.root_path.join(
                    Path::new("./".to_string().append(path.as_slice()))
                        .join("./index.html".to_string()));
                if index_path.is_file() {
                    // Avoid serving as a directory
                    if path.len() > 0 {
                        match path.as_slice().char_at_reverse(path.len()) {
                            '/' => {
                                match res.serve_file(&index_path) {
                                    Ok(()) => {
                                        debug!("Serving static file at {}.",
                                            &index_path.display());
                                        return Unwind
                                    },
                                    Err(err) => {
                                        debug!("Failed while trying to serve index.html: {}", err)
                                        return Continue
                                    }
                                }
                            },
                    // 303:
                            _ => ()
                        }
                    }
                    let redirect_path = match alloy.find::<OriginalUrl>() {
                        Some(&OriginalUrl(ref original_url)) => original_url.clone(),
                        None => path.clone()
                    }.append("/");
                    res.headers.extensions.insert("Location".to_string(), redirect_path.clone());
                    let _ = res.serve(::http::status::SeeOther,
                        format!("Redirecting to {}/", redirect_path).as_slice());
                    return Unwind
                }
            },
            None => ()
        }
        Continue
    }
}

impl Middleware for Favicon {
    fn enter(&mut self, req: &mut Request, res: &mut Response, _alloy: &mut Alloy) -> Status {
        match req.request_uri {
            AbsolutePath(ref path) => {
                if regex!("/favicon$").is_match(path.as_slice()) {
                    match res.serve_file(&self.favicon_path) {
                        Ok(()) => {
                            res.headers.cache_control = Some("max-age=86400".to_str());
                            return Unwind },
                        Err(_) => { return Continue }
                    }
                }
                Continue
            },
            _ => {
                Continue
            }
        }
    }
}
<|endoftext|>