<commit_before>#![feature(rustc_private, decl_macro, type_alias_impl_trait, associated_type_bounds, never_type)]
#![allow(intra_doc_link_resolution_failure)]

extern crate flate2;
extern crate libc;
extern crate tempfile;
extern crate rustc;
extern crate rustc_codegen_ssa;
extern crate rustc_codegen_utils;
extern crate rustc_data_structures;
extern crate rustc_driver;
extern crate rustc_fs_util;
extern crate rustc_hir;
extern crate rustc_incremental;
extern crate rustc_index;
extern crate rustc_mir;
extern crate rustc_session;
extern crate rustc_span;
extern crate rustc_target;
extern crate rustc_ast;

use std::any::Any;

use rustc::dep_graph::{DepGraph, WorkProduct, WorkProductId};
use rustc::middle::cstore::{EncodedMetadata, MetadataLoader};
use rustc::session::config::OutputFilenames;
use rustc::ty::query::Providers;
use rustc::util::common::ErrorReported;
use rustc_codegen_utils::codegen_backend::CodegenBackend;

use cranelift_codegen::settings;

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

mod abi;
mod allocator;
mod analyze;
mod archive;
mod atomic_shim;
mod base;
mod backend;
mod cast;
mod codegen_i128;
mod common;
mod constant;
mod debuginfo;
mod discriminant;
mod driver;
mod intrinsics;
mod linkage;
mod main_shim;
mod metadata;
mod num;
mod optimize;
mod pointer;
mod pretty_clif;
mod target_features_whitelist;
mod trap;
mod unimpl;
mod unsize;
mod value_and_place;
mod vtable;

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

    pub use rustc_ast::ast::{FloatTy, IntTy, UintTy};
    pub use rustc_span::{Pos, Span};

    pub use rustc::bug;
    pub use rustc_hir::def_id::{CrateNum, DefId, LOCAL_CRATE};
    pub use rustc::mir::{self, interpret::AllocId, mono::MonoItem, *};
    pub use rustc::session::{
        config::{CrateType, Lto},
        Session,
    };
    pub use rustc::ty::layout::{self, Abi, LayoutOf, Scalar, Size, TyLayout, VariantIdx};
    pub use rustc::ty::{
        self, FnSig, Instance, InstanceDef, ParamEnv, PolyFnSig, Ty, TyCtxt, TypeAndMut,
        TypeFoldable,
    };

    pub use rustc_data_structures::{
        fx::{FxHashMap, FxHashSet},
        sync::Lrc,
    };

    pub use rustc_index::vec::Idx;

    pub use rustc_mir::monomorphize::collector;

    pub use rustc_codegen_ssa::mir::operand::{OperandRef, OperandValue};
    pub use rustc_codegen_ssa::traits::*;
    pub use rustc_codegen_ssa::{CodegenResults, CompiledModule, ModuleKind};

    pub use cranelift_codegen::Context;
    pub use cranelift_codegen::entity::EntitySet;
    pub use cranelift_codegen::ir::{AbiParam, Block, ExternalName, FuncRef, Inst, InstBuilder, MemFlags, Signature, SourceLoc, StackSlot, StackSlotData, StackSlotKind, TrapCode, Type, Value};
    pub use cranelift_codegen::ir::condcodes::{FloatCC, IntCC};
    pub use cranelift_codegen::ir::function::Function;
    pub use cranelift_codegen::ir::immediates::{Ieee32, Ieee64};
    pub use cranelift_codegen::ir::types;
    pub use cranelift_codegen::isa::{self, CallConv};
    pub use cranelift_codegen::settings::{self, Configurable};
    pub use cranelift_frontend::{FunctionBuilder, FunctionBuilderContext, Variable};
    pub use cranelift_module::{
        self, Backend, DataContext, DataId, FuncId, FuncOrDataId, Linkage, Module,
    };

    pub use crate::abi::*;
    pub use crate::base::{trans_operand, trans_place};
    pub use crate::cast::*;
    pub use crate::common::*;
    pub use crate::debuginfo::{DebugContext, FunctionDebugContext};
    pub use crate::pointer::Pointer;
    pub use crate::trap::*;
    pub use crate::unimpl::unimpl;
    pub use crate::value_and_place::{CPlace, CPlaceInner, CValue};
    pub use crate::CodegenCx;

    pub struct PrintOnPanic<F: Fn() -> String>(pub F);
    impl<F: Fn() -> String> Drop for PrintOnPanic<F> {
        fn drop(&mut self) {
            if ::std::thread::panicking() {
                println!("{}", (self.0)());
            }
        }
    }
}

pub struct CodegenCx<'clif, 'tcx, B: Backend + 'static> {
    tcx: TyCtxt<'tcx>,
    module: &'clif mut Module<B>,
    constants_cx: ConstantCx,
    cached_context: Context,
    vtables: HashMap<(Ty<'tcx>, Option<ty::PolyExistentialTraitRef<'tcx>>), DataId>,
    debug_context: Option<&'clif mut DebugContext<'tcx>>,
}

impl<'clif, 'tcx, B: Backend + 'static> CodegenCx<'clif, 'tcx, B> {
    fn new(
        tcx: TyCtxt<'tcx>,
        module: &'clif mut Module<B>,
        debug_context: Option<&'clif mut DebugContext<'tcx>>,
    ) -> Self {
        CodegenCx {
            tcx,
            module,
            constants_cx: ConstantCx::default(),
            cached_context: Context::new(),
            vtables: HashMap::new(),
            debug_context,
        }
    }

    fn finalize(self) {
        self.constants_cx.finalize(self.tcx, self.module);
    }
}

struct CraneliftCodegenBackend;

impl CodegenBackend for CraneliftCodegenBackend {
    fn init(&self, sess: &Session) {
        if sess.lto() != rustc_session::config::Lto::No {
            sess.warn("LTO is not supported. You may get a linker error.");
        }
    }

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

    fn provide(&self, providers: &mut Providers) {
        providers.target_features_whitelist = |tcx, cnum| {
            assert_eq!(cnum, LOCAL_CRATE);
            if tcx.sess.opts.actually_rustdoc {
                // rustdoc needs to be able to document functions that use all the features, so
                // whitelist them all
                tcx.arena.alloc(
                    target_features_whitelist::all_known_features()
                        .map(|(a, b)| (a.to_string(), b))
                        .collect(),
                )
            } else {
                tcx.arena.alloc(
                    target_features_whitelist::target_feature_whitelist(tcx.sess)
                        .iter()
                        .map(|&(a, b)| (a.to_string(), b))
                        .collect(),
                )
            }
        };
    }
    fn provide_extern(&self, _providers: &mut Providers) {}

    fn codegen_crate<'tcx>(
        &self,
        tcx: TyCtxt<'tcx>,
        metadata: EncodedMetadata,
        need_metadata_module: bool,
    ) -> Box<dyn Any> {
        rustc_codegen_utils::check_for_rustc_errors_attr(tcx);

        let res = driver::codegen_crate(tcx, metadata, need_metadata_module);

        rustc_incremental::assert_module_sources::assert_module_sources(tcx);
        rustc_codegen_utils::symbol_names_test::report_symbol_names(tcx);

        res
    }

    fn join_codegen(
        &self,
        ongoing_codegen: Box<dyn Any>,
        sess: &Session,
        dep_graph: &DepGraph,
    ) -> Result<Box<dyn Any>, ErrorReported> {
        let (codegen_results, work_products) = *ongoing_codegen.downcast::<(CodegenResults, FxHashMap<WorkProductId, WorkProduct>)>().unwrap();

        sess.time("serialize_work_products", move || {
            rustc_incremental::save_work_product_index(sess, &dep_graph, work_products)
        });

        Ok(Box::new(codegen_results))
    }

    fn link(
        &self,
        sess: &Session,
        res: Box<dyn Any>,
        outputs: &OutputFilenames,
    ) -> Result<(), ErrorReported> {
        use rustc_codegen_ssa::back::link::link_binary;

        let codegen_results = *res
            .downcast::<CodegenResults>()
            .expect("Expected CraneliftCodegenBackend's CodegenResult, found Box<Any>");

        let _timer = sess.prof.generic_activity("link_crate");

        sess.time("linking", || {
            let target_cpu = crate::target_triple(sess).to_string();
            link_binary::<crate::archive::ArArchiveBuilder<'_>>(
                sess,
                &codegen_results,
                outputs,
                &codegen_results.crate_name.as_str(),
                &target_cpu,
            );
        });

        rustc_incremental::finalize_session_directory(sess, codegen_results.crate_hash);

        Ok(())
    }
}

fn target_triple(sess: &Session) -> target_lexicon::Triple {
    sess.target.target.llvm_target.parse().unwrap()
}

fn build_isa(sess: &Session, enable_pic: bool) -> Box<dyn isa::TargetIsa + 'static> {
    use target_lexicon::BinaryFormat;

    let target_triple = crate::target_triple(sess);

    let mut flags_builder = settings::builder();
    if enable_pic {
        flags_builder.enable("is_pic").unwrap();
    } else {
        flags_builder.set("is_pic", "false").unwrap();
    }
    flags_builder.set("enable_probestack", "false").unwrap(); // __cranelift_probestack is not provided
    flags_builder
        .set(
            "enable_verifier",
            if cfg!(debug_assertions) {
                "true"
            } else {
                "false"
            },
        )
        .unwrap();

    let tls_model = match target_triple.binary_format {
        BinaryFormat::Elf => "elf_gd",
        BinaryFormat::Macho => "macho",
        BinaryFormat::Coff => "coff",
        _ => "none",
    };
    flags_builder.set("tls_model", tls_model).unwrap();

    // FIXME(CraneStation/cranelift#732) fix LICM in presence of jump tables
    /*
    use rustc::session::config::OptLevel;
    match sess.opts.optimize {
        OptLevel::No => {
            flags_builder.set("opt_level", "fastest").unwrap();
        }
        OptLevel::Less | OptLevel::Default => {}
        OptLevel::Aggressive => {
            flags_builder.set("opt_level", "best").unwrap();
        }
        OptLevel::Size | OptLevel::SizeMin => {
            sess.warn("Optimizing for size is not supported. Just ignoring the request");
        }
    }*/

    let flags = settings::Flags::new(flags_builder);
    cranelift_codegen::isa::lookup(target_triple)
        .unwrap()
        .finish(flags)
}

/// This is the entrypoint for a hot plugged rustc_codegen_cranelift
#[no_mangle]
pub fn __rustc_codegen_backend() -> Box<dyn CodegenBackend> {
    Box::new(CraneliftCodegenBackend)
}
<commit_msg>Remove unused import<commit_after>#![feature(rustc_private, decl_macro, type_alias_impl_trait, associated_type_bounds, never_type)]
#![allow(intra_doc_link_resolution_failure)]

extern crate flate2;
extern crate libc;
extern crate tempfile;
extern crate rustc;
extern crate rustc_codegen_ssa;
extern crate rustc_codegen_utils;
extern crate rustc_data_structures;
extern crate rustc_driver;
extern crate rustc_fs_util;
extern crate rustc_hir;
extern crate rustc_incremental;
extern crate rustc_index;
extern crate rustc_mir;
extern crate rustc_session;
extern crate rustc_span;
extern crate rustc_target;
extern crate rustc_ast;

use std::any::Any;

use rustc::dep_graph::{DepGraph, WorkProduct, WorkProductId};
use rustc::middle::cstore::{EncodedMetadata, MetadataLoader};
use rustc::session::config::OutputFilenames;
use rustc::ty::query::Providers;
use rustc::util::common::ErrorReported;
use rustc_codegen_utils::codegen_backend::CodegenBackend;

use cranelift_codegen::settings;

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

mod abi;
mod allocator;
mod analyze;
mod archive;
mod atomic_shim;
mod base;
mod backend;
mod cast;
mod codegen_i128;
mod common;
mod constant;
mod debuginfo;
mod discriminant;
mod driver;
mod intrinsics;
mod linkage;
mod main_shim;
mod metadata;
mod num;
mod optimize;
mod pointer;
mod pretty_clif;
mod target_features_whitelist;
mod trap;
mod unimpl;
mod unsize;
mod value_and_place;
mod vtable;

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

    pub use rustc_ast::ast::{FloatTy, IntTy, UintTy};
    pub use rustc_span::{Pos, Span};

    pub use rustc::bug;
    pub use rustc_hir::def_id::{CrateNum, DefId, LOCAL_CRATE};
    pub use rustc::mir::{self, interpret::AllocId, mono::MonoItem, *};
    pub use rustc::session::{
        config::{CrateType, Lto},
        Session,
    };
    pub use rustc::ty::layout::{self, Abi, LayoutOf, Scalar, Size, TyLayout, VariantIdx};
    pub use rustc::ty::{
        self, FnSig, Instance, InstanceDef, ParamEnv, PolyFnSig, Ty, TyCtxt, TypeAndMut,
        TypeFoldable,
    };

    pub use rustc_data_structures::{
        fx::{FxHashMap, FxHashSet},
        sync::Lrc,
    };

    pub use rustc_index::vec::Idx;

    pub use rustc_codegen_ssa::mir::operand::{OperandRef, OperandValue};
    pub use rustc_codegen_ssa::traits::*;
    pub use rustc_codegen_ssa::{CodegenResults, CompiledModule, ModuleKind};

    pub use cranelift_codegen::Context;
    pub use cranelift_codegen::entity::EntitySet;
    pub use cranelift_codegen::ir::{AbiParam, Block, ExternalName, FuncRef, Inst, InstBuilder, MemFlags, Signature, SourceLoc, StackSlot, StackSlotData, StackSlotKind, TrapCode, Type, Value};
    pub use cranelift_codegen::ir::condcodes::{FloatCC, IntCC};
    pub use cranelift_codegen::ir::function::Function;
    pub use cranelift_codegen::ir::immediates::{Ieee32, Ieee64};
    pub use cranelift_codegen::ir::types;
    pub use cranelift_codegen::isa::{self, CallConv};
    pub use cranelift_codegen::settings::{self, Configurable};
    pub use cranelift_frontend::{FunctionBuilder, FunctionBuilderContext, Variable};
    pub use cranelift_module::{
        self, Backend, DataContext, DataId, FuncId, FuncOrDataId, Linkage, Module,
    };

    pub use crate::abi::*;
    pub use crate::base::{trans_operand, trans_place};
    pub use crate::cast::*;
    pub use crate::common::*;
    pub use crate::debuginfo::{DebugContext, FunctionDebugContext};
    pub use crate::pointer::Pointer;
    pub use crate::trap::*;
    pub use crate::unimpl::unimpl;
    pub use crate::value_and_place::{CPlace, CPlaceInner, CValue};
    pub use crate::CodegenCx;

    pub struct PrintOnPanic<F: Fn() -> String>(pub F);
    impl<F: Fn() -> String> Drop for PrintOnPanic<F> {
        fn drop(&mut self) {
            if ::std::thread::panicking() {
                println!("{}", (self.0)());
            }
        }
    }
}

pub struct CodegenCx<'clif, 'tcx, B: Backend + 'static> {
    tcx: TyCtxt<'tcx>,
    module: &'clif mut Module<B>,
    constants_cx: ConstantCx,
    cached_context: Context,
    vtables: HashMap<(Ty<'tcx>, Option<ty::PolyExistentialTraitRef<'tcx>>), DataId>,
    debug_context: Option<&'clif mut DebugContext<'tcx>>,
}

impl<'clif, 'tcx, B: Backend + 'static> CodegenCx<'clif, 'tcx, B> {
    fn new(
        tcx: TyCtxt<'tcx>,
        module: &'clif mut Module<B>,
        debug_context: Option<&'clif mut DebugContext<'tcx>>,
    ) -> Self {
        CodegenCx {
            tcx,
            module,
            constants_cx: ConstantCx::default(),
            cached_context: Context::new(),
            vtables: HashMap::new(),
            debug_context,
        }
    }

    fn finalize(self) {
        self.constants_cx.finalize(self.tcx, self.module);
    }
}

struct CraneliftCodegenBackend;

impl CodegenBackend for CraneliftCodegenBackend {
    fn init(&self, sess: &Session) {
        if sess.lto() != rustc_session::config::Lto::No {
            sess.warn("LTO is not supported. You may get a linker error.");
        }
    }

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

    fn provide(&self, providers: &mut Providers) {
        providers.target_features_whitelist = |tcx, cnum| {
            assert_eq!(cnum, LOCAL_CRATE);
            if tcx.sess.opts.actually_rustdoc {
                // rustdoc needs to be able to document functions that use all the features, so
                // whitelist them all
                tcx.arena.alloc(
                    target_features_whitelist::all_known_features()
                        .map(|(a, b)| (a.to_string(), b))
                        .collect(),
                )
            } else {
                tcx.arena.alloc(
                    target_features_whitelist::target_feature_whitelist(tcx.sess)
                        .iter()
                        .map(|&(a, b)| (a.to_string(), b))
                        .collect(),
                )
            }
        };
    }
    fn provide_extern(&self, _providers: &mut Providers) {}

    fn codegen_crate<'tcx>(
        &self,
        tcx: TyCtxt<'tcx>,
        metadata: EncodedMetadata,
        need_metadata_module: bool,
    ) -> Box<dyn Any> {
        rustc_codegen_utils::check_for_rustc_errors_attr(tcx);

        let res = driver::codegen_crate(tcx, metadata, need_metadata_module);

        rustc_incremental::assert_module_sources::assert_module_sources(tcx);
        rustc_codegen_utils::symbol_names_test::report_symbol_names(tcx);

        res
    }

    fn join_codegen(
        &self,
        ongoing_codegen: Box<dyn Any>,
        sess: &Session,
        dep_graph: &DepGraph,
    ) -> Result<Box<dyn Any>, ErrorReported> {
        let (codegen_results, work_products) = *ongoing_codegen.downcast::<(CodegenResults, FxHashMap<WorkProductId, WorkProduct>)>().unwrap();

        sess.time("serialize_work_products", move || {
            rustc_incremental::save_work_product_index(sess, &dep_graph, work_products)
        });

        Ok(Box::new(codegen_results))
    }

    fn link(
        &self,
        sess: &Session,
        res: Box<dyn Any>,
        outputs: &OutputFilenames,
    ) -> Result<(), ErrorReported> {
        use rustc_codegen_ssa::back::link::link_binary;

        let codegen_results = *res
            .downcast::<CodegenResults>()
            .expect("Expected CraneliftCodegenBackend's CodegenResult, found Box<Any>");

        let _timer = sess.prof.generic_activity("link_crate");

        sess.time("linking", || {
            let target_cpu = crate::target_triple(sess).to_string();
            link_binary::<crate::archive::ArArchiveBuilder<'_>>(
                sess,
                &codegen_results,
                outputs,
                &codegen_results.crate_name.as_str(),
                &target_cpu,
            );
        });

        rustc_incremental::finalize_session_directory(sess, codegen_results.crate_hash);

        Ok(())
    }
}

fn target_triple(sess: &Session) -> target_lexicon::Triple {
    sess.target.target.llvm_target.parse().unwrap()
}

fn build_isa(sess: &Session, enable_pic: bool) -> Box<dyn isa::TargetIsa + 'static> {
    use target_lexicon::BinaryFormat;

    let target_triple = crate::target_triple(sess);

    let mut flags_builder = settings::builder();
    if enable_pic {
        flags_builder.enable("is_pic").unwrap();
    } else {
        flags_builder.set("is_pic", "false").unwrap();
    }
    flags_builder.set("enable_probestack", "false").unwrap(); // __cranelift_probestack is not provided
    flags_builder
        .set(
            "enable_verifier",
            if cfg!(debug_assertions) {
                "true"
            } else {
                "false"
            },
        )
        .unwrap();

    let tls_model = match target_triple.binary_format {
        BinaryFormat::Elf => "elf_gd",
        BinaryFormat::Macho => "macho",
        BinaryFormat::Coff => "coff",
        _ => "none",
    };
    flags_builder.set("tls_model", tls_model).unwrap();

    // FIXME(CraneStation/cranelift#732) fix LICM in presence of jump tables
    /*
    use rustc::session::config::OptLevel;
    match sess.opts.optimize {
        OptLevel::No => {
            flags_builder.set("opt_level", "fastest").unwrap();
        }
        OptLevel::Less | OptLevel::Default => {}
        OptLevel::Aggressive => {
            flags_builder.set("opt_level", "best").unwrap();
        }
        OptLevel::Size | OptLevel::SizeMin => {
            sess.warn("Optimizing for size is not supported. Just ignoring the request");
        }
    }*/

    let flags = settings::Flags::new(flags_builder);
    cranelift_codegen::isa::lookup(target_triple)
        .unwrap()
        .finish(flags)
}

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


<commit_before>#[macro_use]
extern crate nom;

use nom::IResult::*;
use nom::Err::*;
use std::fmt;

mod helper;
use helper::*;

macro_rules! errprint {
    ($($arg:tt)*) => (
        std::io::stderr().write_fmt(format_args!($($arg)*))
        );
}

macro_rules! errln {
    ($fmt:expr) => (errprint!(concat!($fmt, "\n")));
    ($fmt:expr, $($arg:tt)*) => (errprint!(concat!($fmt, "\n"), $($arg)*));
}

#[allow(unused_imports)] use std::io::Write;

#[derive(Eq,PartialEq)]
pub struct Date {
    year: i32,
    month: u32,
    day: u32,
}

#[derive(Eq,PartialEq)]
pub struct Time {
    hour: u32,
    minute: u32,
    second: u32,
    tz_offset: i32,
}

#[derive(Eq,PartialEq)]
pub struct DateTime {
    date: Date,
    time: Time,
}

impl fmt::Debug for Date {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{:0>4?}-{:0>2?}-{:0>2?}",
               self.year, self.month, self.day)
    }
}
impl fmt::Debug for Time {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{:0>2?}:{:0>2?}:{:0>2?}Z{:0>4?}",
               self.hour, self.minute, self.second, self.tz_offset*100)
    }
}
impl fmt::Debug for DateTime {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{:?}T{:?}", self.date, self.time)
    }
}

/// Take n bytes and ensure that they are only in the provided range of bytes
macro_rules! take_n_between(
    ($input:expr, $count:expr, $min:expr, $max:expr) => (
        {
            let new_min = $min as u8;
            let new_max = $max as u8;
            let cnt = $count as usize;
            if $input.len() < cnt {
                nom::IResult::Incomplete(nom::Needed::Size(cnt))
            } else {
                for idx in 0..$count {
                    if $input[idx] < new_min || $input[idx] > new_max {
                        return nom::IResult::Error(nom::Err::Position(42 as u32,$input));
                    }
                }

                nom::IResult::Done(&$input[$count..], &$input[0..$count])
            }
        }
        );
    );

macro_rules! char_between(
    ($input:expr, $min:expr, $max:expr) => (
        take_n_between!($input, 1, $min, $max)
    );
);

macro_rules! empty_or(
    ($i:expr, $submac:ident!( $($args:tt)* )) => (
        if $i.len() == 0 {
            nom::IResult::Done($i, None)
        } else {
            match $submac!($i, $($args)*) {
                nom::IResult::Done(i,o)     => nom::IResult::Done(i, Some(o)),
                nom::IResult::Error(_)      => nom::IResult::Done($i, None),
                nom::IResult::Incomplete(i) => nom::IResult::Incomplete(i)

            }
        }
    );
);

named!(year_prefix, alt!(tag!("+") | tag!("-")));

named!(pub year <&[u8], i32>, chain!(
        pref: opt!(year_prefix) ~
        year: take_n_between!(4, '0', '9')
        ,
        || {
            match pref {
                Some(b"-") => -buf_to_i32(year),
                _ => buf_to_i32(year)
            }
        }));

named!(lower_month <&[u8], u32>, chain!(tag!("0") ~ s:char_between!('1', '9') , || buf_to_u32(s)));
named!(upper_month <&[u8], u32>, chain!(tag!("1") ~ s:char_between!('0', '2') ,       || 10+buf_to_u32(s)));

named!(pub month <&[u8], u32>, alt!(lower_month | upper_month));

named!(day_zero <&[u8], u32>,  chain!(tag!("0") ~ s:char_between!('1', '9') ,  || buf_to_u32(s)));
named!(day_one <&[u8], u32>,   chain!(tag!("1") ~ s:char_between!('0', '9') , || 10+buf_to_u32(s)));
named!(day_two <&[u8], u32>,   chain!(tag!("2") ~ s:char_between!('0', '9') , || 20+buf_to_u32(s)));
named!(day_three <&[u8], u32>, chain!(tag!("3") ~ s:char_between!('0', '1') ,         || 30+buf_to_u32(s)));

named!(pub day <&[u8], u32>, alt!(day_zero | day_one | day_two | day_three));

named!(pub date <&[u8], Date>, chain!(
        y: year ~
        tag!("-") ~
        m: month ~
        tag!("-") ~
        d: day
        ,
        || { Date{ year: y, month: m, day: d } }
        ));

named!(lower_hour <&[u8], u32>, chain!(f:char_between!('0','1') ~ s:char_between!('0','9') ,
                                       || { buf_to_u32(f)*10 + buf_to_u32(s) } ));
named!(upper_hour <&[u8], u32>, chain!(tag!("2") ~ s:char_between!('0','4') , || 20+buf_to_u32(s)));
named!(pub hour <&[u8], u32>, alt!(lower_hour | upper_hour));

named!(below_sixty <&[u8], u32>, chain!(f:char_between!('0','5') ~ s:char_between!('0','9') ,
                                       || { buf_to_u32(f)*10 + buf_to_u32(s) } ));

named!(pub minute <&[u8], u32>, call!(below_sixty));
named!(pub second <&[u8], u32>, call!(below_sixty));

named!(append_seconds <&[u8], u32>, chain!(tag!(":") ~ sec:second, || sec));

named!(pub time <&[u8], Time>, chain!(
        h: hour ~
        tag!(":") ~
        m: minute ~
        s: empty_or!(
            chain!(tag!(":") ~ s:second , || s)
            )
        ,
        || {
            Time {
                hour: h,
                minute: m,
                second: s.unwrap_or(0),
                tz_offset: 0
            }
        }
        ));

named!(timezone <&[u8], u32>, chain!(
        tag!("+") ~
        h: hour ~
        m: empty_or!(
            chain!(
                tag!(":")? ~ m: minute , || { m }
            ))
        ,
        || { h }));

named!(tz_z, tag!("Z"));
named!(timezone_utc <&[u8], u32>, map!(tz_z, |_| 0));

named!(pub time_with_timezone <&[u8], Time>, chain!(
        t: time ~
        s: empty_or!(alt!(timezone_utc | timezone))
        ,
        || {
            Time {
                hour: t.hour,
                minute: t.minute,
                second: t.second,
                tz_offset: s.unwrap_or(0) as i32
            }
        }
        ));

named!(pub datetime <&[u8], DateTime>, chain!(
        d: date ~
        tag!("T") ~
        t: time_with_timezone
        ,
        || {
            DateTime{
                date: d,
                time: t,
            }
        }
        ));
<commit_msg>Remove unused functions, parsers and variables<commit_after>#[macro_use]
extern crate nom;

use nom::IResult::*;
use nom::Err::*;
use std::fmt;

mod helper;
use helper::*;

#[derive(Eq,PartialEq)]
pub struct Date {
    year: i32,
    month: u32,
    day: u32,
}

#[derive(Eq,PartialEq)]
pub struct Time {
    hour: u32,
    minute: u32,
    second: u32,
    tz_offset: i32,
}

#[derive(Eq,PartialEq)]
pub struct DateTime {
    date: Date,
    time: Time,
}

impl fmt::Debug for Date {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{:0>4?}-{:0>2?}-{:0>2?}",
               self.year, self.month, self.day)
    }
}
impl fmt::Debug for Time {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{:0>2?}:{:0>2?}:{:0>2?}Z{:0>4?}",
               self.hour, self.minute, self.second, self.tz_offset*100)
    }
}
impl fmt::Debug for DateTime {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{:?}T{:?}", self.date, self.time)
    }
}

/// Take n bytes and ensure that they are only in the provided range of bytes
macro_rules! take_n_between(
    ($input:expr, $count:expr, $min:expr, $max:expr) => (
        {
            let new_min = $min as u8;
            let new_max = $max as u8;
            let cnt = $count as usize;
            if $input.len() < cnt {
                nom::IResult::Incomplete(nom::Needed::Size(cnt))
            } else {
                for idx in 0..$count {
                    if $input[idx] < new_min || $input[idx] > new_max {
                        return nom::IResult::Error(nom::Err::Position(42 as u32,$input));
                    }
                }

                nom::IResult::Done(&$input[$count..], &$input[0..$count])
            }
        }
        );
    );

macro_rules! char_between(
    ($input:expr, $min:expr, $max:expr) => (
        take_n_between!($input, 1, $min, $max)
    );
);

macro_rules! empty_or(
    ($i:expr, $submac:ident!( $($args:tt)* )) => (
        if $i.len() == 0 {
            nom::IResult::Done($i, None)
        } else {
            match $submac!($i, $($args)*) {
                nom::IResult::Done(i,o)     => nom::IResult::Done(i, Some(o)),
                nom::IResult::Error(_)      => nom::IResult::Done($i, None),
                nom::IResult::Incomplete(i) => nom::IResult::Incomplete(i)

            }
        }
    );
);

named!(year_prefix, alt!(tag!("+") | tag!("-")));

named!(pub year <&[u8], i32>, chain!(
        pref: opt!(year_prefix) ~
        year: take_n_between!(4, '0', '9')
        ,
        || {
            match pref {
                Some(b"-") => -buf_to_i32(year),
                _ => buf_to_i32(year)
            }
        }));

named!(lower_month <&[u8], u32>, chain!(tag!("0") ~ s:char_between!('1', '9') , || buf_to_u32(s)));
named!(upper_month <&[u8], u32>, chain!(tag!("1") ~ s:char_between!('0', '2') ,       || 10+buf_to_u32(s)));

named!(pub month <&[u8], u32>, alt!(lower_month | upper_month));

named!(day_zero <&[u8], u32>,  chain!(tag!("0") ~ s:char_between!('1', '9') ,  || buf_to_u32(s)));
named!(day_one <&[u8], u32>,   chain!(tag!("1") ~ s:char_between!('0', '9') , || 10+buf_to_u32(s)));
named!(day_two <&[u8], u32>,   chain!(tag!("2") ~ s:char_between!('0', '9') , || 20+buf_to_u32(s)));
named!(day_three <&[u8], u32>, chain!(tag!("3") ~ s:char_between!('0', '1') ,         || 30+buf_to_u32(s)));

named!(pub day <&[u8], u32>, alt!(day_zero | day_one | day_two | day_three));

named!(pub date <&[u8], Date>, chain!(
        y: year ~
        tag!("-") ~
        m: month ~
        tag!("-") ~
        d: day
        ,
        || { Date{ year: y, month: m, day: d } }
        ));

named!(lower_hour <&[u8], u32>, chain!(f:char_between!('0','1') ~ s:char_between!('0','9') ,
                                       || { buf_to_u32(f)*10 + buf_to_u32(s) } ));
named!(upper_hour <&[u8], u32>, chain!(tag!("2") ~ s:char_between!('0','4') , || 20+buf_to_u32(s)));
named!(pub hour <&[u8], u32>, alt!(lower_hour | upper_hour));

named!(below_sixty <&[u8], u32>, chain!(f:char_between!('0','5') ~ s:char_between!('0','9') ,
                                       || { buf_to_u32(f)*10 + buf_to_u32(s) } ));

named!(pub minute <&[u8], u32>, call!(below_sixty));
named!(pub second <&[u8], u32>, call!(below_sixty));

named!(pub time <&[u8], Time>, chain!(
        h: hour ~
        tag!(":") ~
        m: minute ~
        s: empty_or!(
            chain!(tag!(":") ~ s:second , || s)
            )
        ,
        || {
            Time {
                hour: h,
                minute: m,
                second: s.unwrap_or(0),
                tz_offset: 0
            }
        }
        ));

named!(timezone <&[u8], u32>, chain!(
        tag!("+") ~
        h: hour ~
        empty_or!(
            chain!(
                tag!(":")? ~ m: minute , || { m }
            ))
        ,
        || { h }));

named!(tz_z, tag!("Z"));
named!(timezone_utc <&[u8], u32>, map!(tz_z, |_| 0));

named!(pub time_with_timezone <&[u8], Time>, chain!(
        t: time ~
        s: empty_or!(alt!(timezone_utc | timezone))
        ,
        || {
            Time {
                hour: t.hour,
                minute: t.minute,
                second: t.second,
                tz_offset: s.unwrap_or(0) as i32
            }
        }
        ));

named!(pub datetime <&[u8], DateTime>, chain!(
        d: date ~
        tag!("T") ~
        t: time_with_timezone
        ,
        || {
            DateTime{
                date: d,
                time: t,
            }
        }
        ));
<|endoftext|>


<commit_before>// Copyright 2016 The android_logger Developers
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.

//! A logger which writes to android output.
//!
//! ## Example
//!
//! ```ignore
//! #[macro_use] extern crate log;
//! extern crate android_logger;
//!
//! use log::LogLevel;
//!
//! fn native_activity_create() {
//!     android_logger::init_once(LogLevel::Trace);
//!
//!     debug!("this is a debug {}", "message");
//!     error!("this is printed by default");
//!
//!     if log_enabled!(LogLevel::Info) {
//!         let x = 3 * 4; // expensive computation
//!         info!("the answer was: {}", x);
//!     }
//! }
//! ```

extern crate android_log_sys as log_ffi;
#[macro_use] extern crate log;

use log_ffi::LogPriority;
use log::{Log,LogLevel,LogMetadata,LogRecord};
use std::ffi::CStr;
use std::mem;
use std::fmt;

/// Output log to android system.
fn android_log(prio: log_ffi::LogPriority, tag: &CStr, msg: &CStr) {
    unsafe { log_ffi::__android_log_write(prio as log_ffi::c_int, tag.as_ptr(), msg.as_ptr()) };
}

struct PlatformLogger;

const LOGGING_TAG_MAX_LEN: usize = 23;
const LOGGING_MSG_MAX_LEN: usize = 4000;

impl Log for PlatformLogger {
    fn enabled(&self, _: &LogMetadata) -> bool {
        true
    }

    fn log(&self, record: &LogRecord) {
        // tag must not exceed LOGGING_TAG_MAX_LEN
        let mut tag_bytes: [u8; LOGGING_TAG_MAX_LEN + 1] = unsafe { mem::uninitialized() };
        // truncate the tag here to fit into LOGGING_TAG_MAX_LEN
        self.fill_tag_bytes(&mut tag_bytes, record);
        // use stack array as C string
        let tag: &CStr = unsafe { CStr::from_ptr(mem::transmute(tag_bytes.as_ptr())) };

        // message must not exceed LOGGING_MSG_MAX_LEN
        // therefore split log message into multiple log calls
        let mut writer = PlatformLogWriter::new(
            record.level(),
            tag
        );

        // use PlatformLogWriter to output chunks if they exceed max size
        let _ = fmt::write(&mut writer, *record.args());

        // output the remaining message (this would usually be the most common case)
        writer.flush();
    }
}

impl PlatformLogger {
    fn fill_tag_bytes(&self, array: &mut [u8], record: &LogRecord) {
        let tag_bytes_iter = record.location().module_path().bytes();
        if tag_bytes_iter.len() > LOGGING_TAG_MAX_LEN {
            for (input, output) in tag_bytes_iter
                .take(LOGGING_TAG_MAX_LEN - 2)
                .chain(b"..\0".iter().cloned())
                .zip(array.iter_mut())
            {
                *output = input;
            }
        } else {
            for (input, output) in tag_bytes_iter
                .chain(b"\0".iter().cloned())
                .zip(array.iter_mut())
            {
                *output = input;
            }
        }
    }
}

struct PlatformLogWriter<'a> {
    priority: LogPriority,
    len: usize,
    last_newline_index: usize,
    tag: &'a CStr,
    buffer: [u8; LOGGING_MSG_MAX_LEN + 1],
}

impl<'a> PlatformLogWriter<'a> {
    pub fn new<'r>(level: LogLevel, tag: &'r CStr) -> PlatformLogWriter<'r> {
        PlatformLogWriter {
            priority: match level {
                LogLevel::Warn => LogPriority::WARN,
                LogLevel::Info => LogPriority::INFO,
                LogLevel::Debug => LogPriority::DEBUG,
                LogLevel::Error => LogPriority::ERROR,
                LogLevel::Trace => LogPriority::VERBOSE,
            },
            len: 0,
            last_newline_index: 0,
            tag: tag,
            buffer: unsafe { mem::uninitialized() },
        }
    }

    /// Flush some bytes to android logger.
    ///
    /// If there is a newline, flush up to it.
    /// If ther was no newline, flush all.
    ///
    /// Not guaranteed to flush everything.
    fn temporal_flush(&mut self) {
        let total_len = self.len;

        if total_len == 0 {
            return;
        }

        if self.last_newline_index > 0 {
            let copy_from_index = self.last_newline_index;
            let remaining_chunk_len = total_len - copy_from_index;

            self.output_specified_len(copy_from_index);
            self.copy_bytes_to_start(copy_from_index, remaining_chunk_len);
            self.len = remaining_chunk_len;
        } else {
            self.output_specified_len(total_len);
            self.len = 0;
        }
        self.last_newline_index = 0;
    }

    /// Flush everything remaining to android logger.
    fn flush(&mut self) {
        let total_len = self.len;

        if total_len == 0 {
            return;
        }

        self.output_specified_len(total_len);
        self.len = 0;
        self.last_newline_index = 0;
    }

    /// Output buffer up until the \0 which will be placed at `len` position.
    fn output_specified_len(&mut self, len: usize) {
        let mut last_byte: u8 = b'\0';
        mem::swap(&mut last_byte, unsafe { self.buffer.get_unchecked_mut(len) });

        let msg: &CStr = unsafe { CStr::from_ptr(mem::transmute(self.buffer.as_ptr())) };
        android_log(self.priority, self.tag, msg);

        *unsafe { self.buffer.get_unchecked_mut(len) } = last_byte;
    }

    /// Copy `len` bytes from `index` position to starting position.
    fn copy_bytes_to_start(&mut self, index: usize, len: usize) {
        for i in 0..len {
            *unsafe { self.buffer.get_unchecked_mut(i) } =
                *unsafe { self.buffer.get_unchecked_mut(i + index) };
        }
    }
}

impl<'a> fmt::Write for PlatformLogWriter<'a> {
    fn write_str(&mut self, s: &str) -> fmt::Result {
        let mut incomming_bytes = s.as_bytes();

        while incomming_bytes.len() > 0 {
            let len = self.len;

            // write everything possible to buffer and mark last \n
            let new_len = len + incomming_bytes.len();
            let last_newline = self.buffer[len..LOGGING_MSG_MAX_LEN].iter_mut()
                .zip(incomming_bytes)
                .enumerate()
                .fold(None, |acc, (i, (output, input))| {
                    *output = *input;
                    if *input == b'\n' { Some(i) } else { acc }
                });

            // update last \n index
            if let Some(newline) = last_newline {
                self.last_newline_index = len + newline;
            }

            // calculate how many bytes were written
            let written_len = if new_len <= LOGGING_MSG_MAX_LEN {
                // if the len was not exceeded
                self.len = new_len;
                new_len - len // written len
            } else {
                // if new length was exceeded
                self.len = LOGGING_MSG_MAX_LEN;
                self.temporal_flush();

                LOGGING_MSG_MAX_LEN - len // written len
            };

            incomming_bytes = &incomming_bytes[written_len..];
        }

        Ok(())
    }
}

/// Initializes the global logger with an android logger.
///
/// This can be called many times, but will only initialize logging once,
/// and will not replace any other previously initialized logger.
///
/// It is ok to call this at the activity creation, and it will be
/// repeatedly called on every lifecycle restart (i.e. screen rotation).
pub fn init_once(log_level: LogLevel) {
    match log::set_logger(|max_log_level| {
        max_log_level.set(log_level.to_log_level_filter());
        return Box::new(PlatformLogger);
    }) {
        Err(e) => debug!("{}", e),
        _ => (),
    }
}
<commit_msg>make copy_bytes_to_start little faster and readable<commit_after>// Copyright 2016 The android_logger Developers
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.

//! A logger which writes to android output.
//!
//! ## Example
//!
//! ```ignore
//! #[macro_use] extern crate log;
//! extern crate android_logger;
//!
//! use log::LogLevel;
//!
//! fn native_activity_create() {
//!     android_logger::init_once(LogLevel::Trace);
//!
//!     debug!("this is a debug {}", "message");
//!     error!("this is printed by default");
//!
//!     if log_enabled!(LogLevel::Info) {
//!         let x = 3 * 4; // expensive computation
//!         info!("the answer was: {}", x);
//!     }
//! }
//! ```

extern crate android_log_sys as log_ffi;
#[macro_use] extern crate log;

use log_ffi::LogPriority;
use log::{Log,LogLevel,LogMetadata,LogRecord};
use std::ffi::CStr;
use std::mem;
use std::fmt;
use std::ptr;

/// Output log to android system.
fn android_log(prio: log_ffi::LogPriority, tag: &CStr, msg: &CStr) {
    unsafe { log_ffi::__android_log_write(prio as log_ffi::c_int, tag.as_ptr(), msg.as_ptr()) };
}

struct PlatformLogger;

const LOGGING_TAG_MAX_LEN: usize = 23;
const LOGGING_MSG_MAX_LEN: usize = 4000;

impl Log for PlatformLogger {
    fn enabled(&self, _: &LogMetadata) -> bool {
        true
    }

    fn log(&self, record: &LogRecord) {
        // tag must not exceed LOGGING_TAG_MAX_LEN
        let mut tag_bytes: [u8; LOGGING_TAG_MAX_LEN + 1] = unsafe { mem::uninitialized() };
        // truncate the tag here to fit into LOGGING_TAG_MAX_LEN
        self.fill_tag_bytes(&mut tag_bytes, record);
        // use stack array as C string
        let tag: &CStr = unsafe { CStr::from_ptr(mem::transmute(tag_bytes.as_ptr())) };

        // message must not exceed LOGGING_MSG_MAX_LEN
        // therefore split log message into multiple log calls
        let mut writer = PlatformLogWriter::new(
            record.level(),
            tag
        );

        // use PlatformLogWriter to output chunks if they exceed max size
        let _ = fmt::write(&mut writer, *record.args());

        // output the remaining message (this would usually be the most common case)
        writer.flush();
    }
}

impl PlatformLogger {
    fn fill_tag_bytes(&self, array: &mut [u8], record: &LogRecord) {
        let tag_bytes_iter = record.location().module_path().bytes();
        if tag_bytes_iter.len() > LOGGING_TAG_MAX_LEN {
            for (input, output) in tag_bytes_iter
                .take(LOGGING_TAG_MAX_LEN - 2)
                .chain(b"..\0".iter().cloned())
                .zip(array.iter_mut())
            {
                *output = input;
            }
        } else {
            for (input, output) in tag_bytes_iter
                .chain(b"\0".iter().cloned())
                .zip(array.iter_mut())
            {
                *output = input;
            }
        }
    }
}

struct PlatformLogWriter<'a> {
    priority: LogPriority,
    len: usize,
    last_newline_index: usize,
    tag: &'a CStr,
    buffer: [u8; LOGGING_MSG_MAX_LEN + 1],
}

impl<'a> PlatformLogWriter<'a> {
    pub fn new<'r>(level: LogLevel, tag: &'r CStr) -> PlatformLogWriter<'r> {
        PlatformLogWriter {
            priority: match level {
                LogLevel::Warn => LogPriority::WARN,
                LogLevel::Info => LogPriority::INFO,
                LogLevel::Debug => LogPriority::DEBUG,
                LogLevel::Error => LogPriority::ERROR,
                LogLevel::Trace => LogPriority::VERBOSE,
            },
            len: 0,
            last_newline_index: 0,
            tag: tag,
            buffer: unsafe { mem::uninitialized() },
        }
    }

    /// Flush some bytes to android logger.
    ///
    /// If there is a newline, flush up to it.
    /// If ther was no newline, flush all.
    ///
    /// Not guaranteed to flush everything.
    fn temporal_flush(&mut self) {
        let total_len = self.len;

        if total_len == 0 {
            return;
        }

        if self.last_newline_index > 0 {
            let copy_from_index = self.last_newline_index;
            let remaining_chunk_len = total_len - copy_from_index;

            self.output_specified_len(copy_from_index);
            self.copy_bytes_to_start(copy_from_index, remaining_chunk_len);
            self.len = remaining_chunk_len;
        } else {
            self.output_specified_len(total_len);
            self.len = 0;
        }
        self.last_newline_index = 0;
    }

    /// Flush everything remaining to android logger.
    fn flush(&mut self) {
        let total_len = self.len;

        if total_len == 0 {
            return;
        }

        self.output_specified_len(total_len);
        self.len = 0;
        self.last_newline_index = 0;
    }

    /// Output buffer up until the \0 which will be placed at `len` position.
    fn output_specified_len(&mut self, len: usize) {
        let mut last_byte: u8 = b'\0';
        mem::swap(&mut last_byte, unsafe { self.buffer.get_unchecked_mut(len) });

        let msg: &CStr = unsafe { CStr::from_ptr(mem::transmute(self.buffer.as_ptr())) };
        android_log(self.priority, self.tag, msg);

        *unsafe { self.buffer.get_unchecked_mut(len) } = last_byte;
    }

    /// Copy `len` bytes from `index` position to starting position.
    fn copy_bytes_to_start(&mut self, index: usize, len: usize) {
        let src = unsafe { self.buffer.as_ptr().offset(index as isize) };
        let dst = self.buffer.as_mut_ptr();
        unsafe { ptr::copy(src, dst, len) };
    }
}

impl<'a> fmt::Write for PlatformLogWriter<'a> {
    fn write_str(&mut self, s: &str) -> fmt::Result {
        let mut incomming_bytes = s.as_bytes();

        while incomming_bytes.len() > 0 {
            let len = self.len;

            // write everything possible to buffer and mark last \n
            let new_len = len + incomming_bytes.len();
            let last_newline = self.buffer[len..LOGGING_MSG_MAX_LEN].iter_mut()
                .zip(incomming_bytes)
                .enumerate()
                .fold(None, |acc, (i, (output, input))| {
                    *output = *input;
                    if *input == b'\n' { Some(i) } else { acc }
                });

            // update last \n index
            if let Some(newline) = last_newline {
                self.last_newline_index = len + newline;
            }

            // calculate how many bytes were written
            let written_len = if new_len <= LOGGING_MSG_MAX_LEN {
                // if the len was not exceeded
                self.len = new_len;
                new_len - len // written len
            } else {
                // if new length was exceeded
                self.len = LOGGING_MSG_MAX_LEN;
                self.temporal_flush();

                LOGGING_MSG_MAX_LEN - len // written len
            };

            incomming_bytes = &incomming_bytes[written_len..];
        }

        Ok(())
    }
}

/// Initializes the global logger with an android logger.
///
/// This can be called many times, but will only initialize logging once,
/// and will not replace any other previously initialized logger.
///
/// It is ok to call this at the activity creation, and it will be
/// repeatedly called on every lifecycle restart (i.e. screen rotation).
pub fn init_once(log_level: LogLevel) {
    match log::set_logger(|max_log_level| {
        max_log_level.set(log_level.to_log_level_filter());
        return Box::new(PlatformLogger);
    }) {
        Err(e) => debug!("{}", e),
        _ => (),
    }
}
<|endoftext|>


<commit_before>// Filebuffer -- Fast and simple file reading
// Copyright 2016 Ruud van Asseldonk
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// A copy of the License has been included in the root of the repository.

//! Filebuffer, a library for fast and simple file reading.
//!
//! # Examples
//!
//! Map a file into memory and access it as a slice of bytes. This is simple and will generally
//! outperform `Read::read_to_end()`.
//!
//! ```
//! use filebuffer::FileBuffer;
//! let fbuffer = FileBuffer::open("src/lib.rs").unwrap();
//! assert_eq!(&fbuffer[3..45], &b"Filebuffer -- Fast and simple file reading"[..]);
//! ```

#![warn(missing_docs)]

use std::cmp;
use std::io;
use std::fs;
use std::ops::Deref;
use std::path::Path;
use std::ptr;
use std::slice;

#[cfg(unix)]
mod unix;

#[cfg(windows)]
mod windows;

#[cfg(unix)]
use unix::{PlatformData, get_resident, get_page_size, map_file, unmap_file, prefetch};

#[cfg(windows)]
use windows::{PlatformData, get_resident, get_page_size, map_file, unmap_file, prefetch};

/// A memory-mapped file.
///
/// # Safety
///
/// **On Unix-ish platforms, external modifications to the file made after the file buffer was
/// opened can show up in this file buffer.** In particular, if a file is truncated after opening,
/// accessing the removed part causes undefined behavior. On Windows it is possible to prevent this
/// by opening the file in exclusive mode, but that functionality is not available in stable Rust
/// currently. (Filebuffer will be updated after stabilization.)
///
/// It is recommended to ensure that other applications do not write to the file when it is mapped,
/// possibly by marking the file read-only. (Though even this is no guarantee.)
pub struct FileBuffer {
    page_size: usize,
    buffer: *const u8,
    length: usize,

    #[allow(dead_code)] // This field is not dead, it might have an effectful destructor.
    platform_data: PlatformData,
}

/// Rounds `size` up to the nearest multiple of `power_of_two`.
fn round_up_to(size: usize, power_of_two: usize) -> usize {
    (size + (power_of_two - 1)) & !(power_of_two - 1)
}

#[test]
fn verify_round_up_to() {
    assert_eq!(1024, round_up_to(23, 1024));
    assert_eq!(1024, round_up_to(1024, 1024));
    assert_eq!(2048, round_up_to(1025, 1024));
}

/// Rounds `size` down to the nearest multiple of `power_of_two`.
fn round_down_to(size: usize, power_of_two: usize) -> usize {
    size & !(power_of_two - 1)
}

#[test]
fn verify_round_down_to() {
    assert_eq!(0, round_down_to(23, 1024));
    assert_eq!(1024, round_down_to(1024, 1024));
    assert_eq!(1024, round_down_to(1025, 1024));
}

impl FileBuffer {
    /// Maps the file at `path` into memory.
    pub fn open<P: AsRef<Path>>(path: P) -> io::Result<FileBuffer> {
        // Open the `fs::File` so we get all of std's error handling for free, then use it to
        // extract the file descriptor. The file is closed again when `map_file` returns on
        // Unix-ish platforms, but `mmap` only requires the descriptor to be open for the `mmap`
        // call, so this is fine. On Windows, the file must be kept open for the lifetime of the
        // mapping, so `map_file` moves the file into the platform data.
        let mut open_opts = fs::OpenOptions::new();
        open_opts.read(true);

        // TODO: On Windows, set `share_mode()` to read-only. This requires the `open_options_ext`
        // feature that is currently unstable, but it is required to ensure that a different
        // process does not suddenly modify the contents of the file.

        let file = try!(open_opts.open(path));
        let (buffer, length, platform_data) = try!(map_file(file));
        let fbuffer = FileBuffer {
            page_size: get_page_size(),
            buffer: buffer,
            length: length,
            platform_data: platform_data
        };
        Ok(fbuffer)
    }

    /// Returns the number of bytes resident in physical memory, starting from `offset`.
    ///
    /// The slice `[offset..offset + resident_len]` can be accessed without causing page faults or
    /// disk access. Note that this is only a snapshot, and the kernel might decide to evict pages
    /// or make them resident at any time.
    ///
    /// The returned resident length is at most `length`.
    ///
    /// # Panics
    ///
    /// Panics if the specified range lies outside of the buffer.
    ///
    /// # Remarks
    ///
    /// Windows does not expose a mechanism to query which pages are resident in physical
    /// memory. Therefore this function optimistically claims that the entire range is resident
    /// on Windows.
    pub fn resident_len(&self, offset: usize, length: usize) -> usize {
        // The specified offset and length must lie within the buffer.
        assert!(offset + length <= self.length);

        // This is a no-op for empty files.
        if self.buffer == ptr::null() { return 0; }

        let aligned_offset = round_down_to(offset, self.page_size);
        let aligned_length = round_up_to(length + (offset - aligned_offset), self.page_size);
        let num_pages = aligned_length / self.page_size;

        // There is a tradeoff here: to store residency information, we need an array of booleans.
        // The requested range can potentially be very large and it is only known at runtime. We
        // could allocate a vector here, but that requires a heap allocation just to get residency
        // information (which might in turn cause a page fault). Instead, check at most 32 pages at
        // once. This means more syscalls for large ranges, but it saves us the heap allocation,
        // and for ranges up to 32 pages (128 KiB typically) there is only one syscall.
        let mut residency = [false; 32];
        let mut pages_checked = 0;
        let mut pages_resident = 0;

        while pages_checked < num_pages {
            let pages_to_check = cmp::min(32, num_pages - pages_checked);
            let check_offset = (aligned_offset + pages_checked * self.page_size) as isize;
            let check_buffer = unsafe { self.buffer.offset(check_offset) };
            let check_length = pages_to_check * self.page_size;
            get_resident(check_buffer, check_length, &mut residency);

            // Count the number of resident pages.
            match residency[..pages_to_check].iter().position(|resident| !resident) {
                Some(non_resident) => {
                    // The index of the non-resident page is the number of resident pages.
                    pages_resident += non_resident;
                    break;
                }
                None => {
                    pages_resident += pages_to_check;
                    pages_checked += pages_to_check;
                }
            }
        }

        let resident_length = pages_resident * self.page_size + aligned_offset - offset;

        // Never return more than the requested length. The resident length might be larger than
        // the length of the buffer, because it is rounded up to the page size.
        cmp::min(length, resident_length)
    }

    /// Returns the system page size.
    ///
    /// When the kernel makes the file resident in physical memory, it does so with page
    /// granularity. (In practice this happens in larger chunks, but still in multiples of
    /// the page size.) Therefore, when processing the file in chunks, this is a good chunk
    /// length.
    pub fn chunk_len_hint(&self) -> usize {
        self.page_size
    }

    /// Advises the kernel to make a slice of the file resident in physical memory.
    ///
    /// This method does not block, meaning that when the function returns, the slice is not
    /// necessarily resident. After this function returns, the kernel may read the requested slice
    /// from disk and make it resident. Note that this is only an advice, the kernel need not honor
    /// it.
    ///
    /// To check whether the slice is resident at a later time, use `resident_len()`.
    ///
    /// # Panics
    ///
    /// Panics if the specified range lies outside of the buffer.
    pub fn prefetch(&self, offset: usize, length: usize) {
        // TODO: This function should use `collections::range::RangeArgument` once stabilized.
        // The specified offset and length must lie within the buffer.
        assert!(offset + length <= self.length);

        // This is a no-op for empty files.
        if self.buffer == ptr::null() { return; }

        let aligned_offset = round_down_to(offset, self.page_size);
        let aligned_length = round_up_to(length + (offset - aligned_offset), self.page_size);

        let buffer = unsafe { self.buffer.offset(aligned_offset as isize) };
        prefetch(buffer, aligned_length);
    }

    /// Leaks the file buffer as a byte slice.
    ///
    /// This prevents the buffer from being unmapped, keeping the file mapped until the program
    /// ends. This is not as bad as it sounds, because the kernel is free to evict pages from
    /// physical memory in case of memory pressure. Because the file is mapped read-only, it can
    /// always be read from disk again.
    ///
    /// If the file buffer is going to be open for the entire duration of the program anyway, this
    /// method can avoid some lifetime issues. Still, it is good practice to close the file buffer
    /// if possible. This method should be a last resort.
    pub fn leak(mut self) -> &'static [u8] {
        let buffer = unsafe { slice::from_raw_parts(self.buffer, self.length) };

        // Prevent `drop()` from freeing the buffer.
        self.buffer = ptr::null();
        self.length = 0;

        buffer
    }
}

// There is no possibility of data races when passing `&FileBuffer` across threads,
// because the buffer is read-only. `&FileBuffer` has no interior mutability.
unsafe impl Sync for FileBuffer {}

// It is safe to move a `FileBuffer` into a different thread.
unsafe impl Send for FileBuffer {}

impl Drop for FileBuffer {
    fn drop(&mut self) {
        if self.buffer != ptr::null() { unmap_file(self.buffer, self.length); }
    }
}

impl Deref for FileBuffer {
    type Target = [u8];

    fn deref(&self) -> &[u8] {
        unsafe { slice::from_raw_parts(self.buffer, self.length) }
    }
}

#[test]
fn open_file() {
    let fbuffer = FileBuffer::open("src/lib.rs");
    assert!(fbuffer.is_ok());
}

#[test]
fn make_resident() {
    let fbuffer = FileBuffer::open("src/lib.rs").unwrap();

    // Touch the first page to make it resident.
    assert_eq!(&fbuffer[3..13], &b"Filebuffer"[..]);

    // Now at least that part should be resident.
    assert_eq!(fbuffer.resident_len(3, 10), 10);
}

#[test]
fn prefetch_is_not_harmful() {
    let fbuffer = FileBuffer::open("src/lib.rs").unwrap();

    // It is impossible to test that this actually works without root access to instruct the kernel
    // to drop its caches, but at least we can verify that calling `prefetch` is not harmful.
    fbuffer.prefetch(0, fbuffer.len());

    // Reading from the file should still work as normal.
    assert_eq!(&fbuffer[3..13], &b"Filebuffer"[..]);
}

#[test]
fn drop_after_leak() {
    let mut bytes = &[0u8][..];
    assert_eq!(bytes[0], 0);
    {
        let fbuffer = FileBuffer::open("src/lib.rs").unwrap();
        bytes = fbuffer.leak();
    }
    assert_eq!(&bytes[3..13], &b"Filebuffer"[..]);
}

#[test]
fn fbuffer_can_be_moved_into_thread() {
    use std::thread;

    let fbuffer = FileBuffer::open("src/lib.rs").unwrap();
    thread::spawn(move || {
        assert_eq!(&fbuffer[3..13], &b"Filebuffer"[..]);
    });
}

#[test]
fn fbuffer_can_be_shared_among_threads() {
    use std::sync;
    use std::thread;

    let fbuffer = FileBuffer::open("src/lib.rs").unwrap();
    let buffer1 = sync::Arc::new(fbuffer);
    let buffer2 = buffer1.clone();
    thread::spawn(move || {
        assert_eq!(&buffer2[3..13], &b"Filebuffer"[..]);
    });
    assert_eq!(&buffer1[17..45], &b"Fast and simple file reading"[..]);
}

#[test]
fn open_empty_file_is_fine() {
    FileBuffer::open("src/empty_file_for_testing.rs").unwrap();
}

#[test]
fn empty_file_prefetch_is_fine() {
    let fbuffer = FileBuffer::open("src/empty_file_for_testing.rs").unwrap();
    fbuffer.prefetch(0, 0);
}

#[test]
fn empty_file_deref_is_fine() {
    let fbuffer = FileBuffer::open("src/empty_file_for_testing.rs").unwrap();
    assert_eq!(fbuffer.iter().any(|_| true), false);
}

#[test]
fn empty_file_has_zero_resident_len() {
    let fbuffer = FileBuffer::open("src/empty_file_for_testing.rs").unwrap();
    assert_eq!(fbuffer.resident_len(0, 0), 0);
}

#[test]
fn page_size_at_least_4096() {
    // There is no reason why the page size cannot be smaller, it is just that in practice there
    // is no platform with a smaller page size, so this tests that `get_page_size()` returns
    // a plausible value.
    assert!(get_page_size() >= 4096);
}
<commit_msg>Add reference to Rust issue<commit_after>// Filebuffer -- Fast and simple file reading
// Copyright 2016 Ruud van Asseldonk
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// A copy of the License has been included in the root of the repository.

//! Filebuffer, a library for fast and simple file reading.
//!
//! # Examples
//!
//! Map a file into memory and access it as a slice of bytes. This is simple and will generally
//! outperform `Read::read_to_end()`.
//!
//! ```
//! use filebuffer::FileBuffer;
//! let fbuffer = FileBuffer::open("src/lib.rs").unwrap();
//! assert_eq!(&fbuffer[3..45], &b"Filebuffer -- Fast and simple file reading"[..]);
//! ```

#![warn(missing_docs)]

use std::cmp;
use std::io;
use std::fs;
use std::ops::Deref;
use std::path::Path;
use std::ptr;
use std::slice;

#[cfg(unix)]
mod unix;

#[cfg(windows)]
mod windows;

#[cfg(unix)]
use unix::{PlatformData, get_resident, get_page_size, map_file, unmap_file, prefetch};

#[cfg(windows)]
use windows::{PlatformData, get_resident, get_page_size, map_file, unmap_file, prefetch};

/// A memory-mapped file.
///
/// # Safety
///
/// **On Unix-ish platforms, external modifications to the file made after the file buffer was
/// opened can show up in this file buffer.** In particular, if a file is truncated after opening,
/// accessing the removed part causes undefined behavior. On Windows it is possible to prevent this
/// by opening the file in exclusive mode, but that functionality is not available in stable Rust
/// currently. (Filebuffer will be updated after stabilization.)
///
/// It is recommended to ensure that other applications do not write to the file when it is mapped,
/// possibly by marking the file read-only. (Though even this is no guarantee.)
pub struct FileBuffer {
    page_size: usize,
    buffer: *const u8,
    length: usize,

    #[allow(dead_code)] // This field is not dead, it might have an effectful destructor.
    platform_data: PlatformData,
}

/// Rounds `size` up to the nearest multiple of `power_of_two`.
fn round_up_to(size: usize, power_of_two: usize) -> usize {
    (size + (power_of_two - 1)) & !(power_of_two - 1)
}

#[test]
fn verify_round_up_to() {
    assert_eq!(1024, round_up_to(23, 1024));
    assert_eq!(1024, round_up_to(1024, 1024));
    assert_eq!(2048, round_up_to(1025, 1024));
}

/// Rounds `size` down to the nearest multiple of `power_of_two`.
fn round_down_to(size: usize, power_of_two: usize) -> usize {
    size & !(power_of_two - 1)
}

#[test]
fn verify_round_down_to() {
    assert_eq!(0, round_down_to(23, 1024));
    assert_eq!(1024, round_down_to(1024, 1024));
    assert_eq!(1024, round_down_to(1025, 1024));
}

impl FileBuffer {
    /// Maps the file at `path` into memory.
    pub fn open<P: AsRef<Path>>(path: P) -> io::Result<FileBuffer> {
        // Open the `fs::File` so we get all of std's error handling for free, then use it to
        // extract the file descriptor. The file is closed again when `map_file` returns on
        // Unix-ish platforms, but `mmap` only requires the descriptor to be open for the `mmap`
        // call, so this is fine. On Windows, the file must be kept open for the lifetime of the
        // mapping, so `map_file` moves the file into the platform data.
        let mut open_opts = fs::OpenOptions::new();
        open_opts.read(true);

        // TODO: On Windows, set `share_mode()` to read-only. This requires the
        // `open_options_ext` feature that is currently unstable, but it is
        // required to ensure that a different process does not suddenly modify
        // the contents of the file. See also Rust issue 27720.

        let file = try!(open_opts.open(path));
        let (buffer, length, platform_data) = try!(map_file(file));
        let fbuffer = FileBuffer {
            page_size: get_page_size(),
            buffer: buffer,
            length: length,
            platform_data: platform_data
        };
        Ok(fbuffer)
    }

    /// Returns the number of bytes resident in physical memory, starting from `offset`.
    ///
    /// The slice `[offset..offset + resident_len]` can be accessed without causing page faults or
    /// disk access. Note that this is only a snapshot, and the kernel might decide to evict pages
    /// or make them resident at any time.
    ///
    /// The returned resident length is at most `length`.
    ///
    /// # Panics
    ///
    /// Panics if the specified range lies outside of the buffer.
    ///
    /// # Remarks
    ///
    /// Windows does not expose a mechanism to query which pages are resident in physical
    /// memory. Therefore this function optimistically claims that the entire range is resident
    /// on Windows.
    pub fn resident_len(&self, offset: usize, length: usize) -> usize {
        // The specified offset and length must lie within the buffer.
        assert!(offset + length <= self.length);

        // This is a no-op for empty files.
        if self.buffer == ptr::null() { return 0; }

        let aligned_offset = round_down_to(offset, self.page_size);
        let aligned_length = round_up_to(length + (offset - aligned_offset), self.page_size);
        let num_pages = aligned_length / self.page_size;

        // There is a tradeoff here: to store residency information, we need an array of booleans.
        // The requested range can potentially be very large and it is only known at runtime. We
        // could allocate a vector here, but that requires a heap allocation just to get residency
        // information (which might in turn cause a page fault). Instead, check at most 32 pages at
        // once. This means more syscalls for large ranges, but it saves us the heap allocation,
        // and for ranges up to 32 pages (128 KiB typically) there is only one syscall.
        let mut residency = [false; 32];
        let mut pages_checked = 0;
        let mut pages_resident = 0;

        while pages_checked < num_pages {
            let pages_to_check = cmp::min(32, num_pages - pages_checked);
            let check_offset = (aligned_offset + pages_checked * self.page_size) as isize;
            let check_buffer = unsafe { self.buffer.offset(check_offset) };
            let check_length = pages_to_check * self.page_size;
            get_resident(check_buffer, check_length, &mut residency);

            // Count the number of resident pages.
            match residency[..pages_to_check].iter().position(|resident| !resident) {
                Some(non_resident) => {
                    // The index of the non-resident page is the number of resident pages.
                    pages_resident += non_resident;
                    break;
                }
                None => {
                    pages_resident += pages_to_check;
                    pages_checked += pages_to_check;
                }
            }
        }

        let resident_length = pages_resident * self.page_size + aligned_offset - offset;

        // Never return more than the requested length. The resident length might be larger than
        // the length of the buffer, because it is rounded up to the page size.
        cmp::min(length, resident_length)
    }

    /// Returns the system page size.
    ///
    /// When the kernel makes the file resident in physical memory, it does so with page
    /// granularity. (In practice this happens in larger chunks, but still in multiples of
    /// the page size.) Therefore, when processing the file in chunks, this is a good chunk
    /// length.
    pub fn chunk_len_hint(&self) -> usize {
        self.page_size
    }

    /// Advises the kernel to make a slice of the file resident in physical memory.
    ///
    /// This method does not block, meaning that when the function returns, the slice is not
    /// necessarily resident. After this function returns, the kernel may read the requested slice
    /// from disk and make it resident. Note that this is only an advice, the kernel need not honor
    /// it.
    ///
    /// To check whether the slice is resident at a later time, use `resident_len()`.
    ///
    /// # Panics
    ///
    /// Panics if the specified range lies outside of the buffer.
    pub fn prefetch(&self, offset: usize, length: usize) {
        // TODO: This function should use `collections::range::RangeArgument` once stabilized.
        // The specified offset and length must lie within the buffer.
        assert!(offset + length <= self.length);

        // This is a no-op for empty files.
        if self.buffer == ptr::null() { return; }

        let aligned_offset = round_down_to(offset, self.page_size);
        let aligned_length = round_up_to(length + (offset - aligned_offset), self.page_size);

        let buffer = unsafe { self.buffer.offset(aligned_offset as isize) };
        prefetch(buffer, aligned_length);
    }

    /// Leaks the file buffer as a byte slice.
    ///
    /// This prevents the buffer from being unmapped, keeping the file mapped until the program
    /// ends. This is not as bad as it sounds, because the kernel is free to evict pages from
    /// physical memory in case of memory pressure. Because the file is mapped read-only, it can
    /// always be read from disk again.
    ///
    /// If the file buffer is going to be open for the entire duration of the program anyway, this
    /// method can avoid some lifetime issues. Still, it is good practice to close the file buffer
    /// if possible. This method should be a last resort.
    pub fn leak(mut self) -> &'static [u8] {
        let buffer = unsafe { slice::from_raw_parts(self.buffer, self.length) };

        // Prevent `drop()` from freeing the buffer.
        self.buffer = ptr::null();
        self.length = 0;

        buffer
    }
}

// There is no possibility of data races when passing `&FileBuffer` across threads,
// because the buffer is read-only. `&FileBuffer` has no interior mutability.
unsafe impl Sync for FileBuffer {}

// It is safe to move a `FileBuffer` into a different thread.
unsafe impl Send for FileBuffer {}

impl Drop for FileBuffer {
    fn drop(&mut self) {
        if self.buffer != ptr::null() { unmap_file(self.buffer, self.length); }
    }
}

impl Deref for FileBuffer {
    type Target = [u8];

    fn deref(&self) -> &[u8] {
        unsafe { slice::from_raw_parts(self.buffer, self.length) }
    }
}

#[test]
fn open_file() {
    let fbuffer = FileBuffer::open("src/lib.rs");
    assert!(fbuffer.is_ok());
}

#[test]
fn make_resident() {
    let fbuffer = FileBuffer::open("src/lib.rs").unwrap();

    // Touch the first page to make it resident.
    assert_eq!(&fbuffer[3..13], &b"Filebuffer"[..]);

    // Now at least that part should be resident.
    assert_eq!(fbuffer.resident_len(3, 10), 10);
}

#[test]
fn prefetch_is_not_harmful() {
    let fbuffer = FileBuffer::open("src/lib.rs").unwrap();

    // It is impossible to test that this actually works without root access to instruct the kernel
    // to drop its caches, but at least we can verify that calling `prefetch` is not harmful.
    fbuffer.prefetch(0, fbuffer.len());

    // Reading from the file should still work as normal.
    assert_eq!(&fbuffer[3..13], &b"Filebuffer"[..]);
}

#[test]
fn drop_after_leak() {
    let mut bytes = &[0u8][..];
    assert_eq!(bytes[0], 0);
    {
        let fbuffer = FileBuffer::open("src/lib.rs").unwrap();
        bytes = fbuffer.leak();
    }
    assert_eq!(&bytes[3..13], &b"Filebuffer"[..]);
}

#[test]
fn fbuffer_can_be_moved_into_thread() {
    use std::thread;

    let fbuffer = FileBuffer::open("src/lib.rs").unwrap();
    thread::spawn(move || {
        assert_eq!(&fbuffer[3..13], &b"Filebuffer"[..]);
    });
}

#[test]
fn fbuffer_can_be_shared_among_threads() {
    use std::sync;
    use std::thread;

    let fbuffer = FileBuffer::open("src/lib.rs").unwrap();
    let buffer1 = sync::Arc::new(fbuffer);
    let buffer2 = buffer1.clone();
    thread::spawn(move || {
        assert_eq!(&buffer2[3..13], &b"Filebuffer"[..]);
    });
    assert_eq!(&buffer1[17..45], &b"Fast and simple file reading"[..]);
}

#[test]
fn open_empty_file_is_fine() {
    FileBuffer::open("src/empty_file_for_testing.rs").unwrap();
}

#[test]
fn empty_file_prefetch_is_fine() {
    let fbuffer = FileBuffer::open("src/empty_file_for_testing.rs").unwrap();
    fbuffer.prefetch(0, 0);
}

#[test]
fn empty_file_deref_is_fine() {
    let fbuffer = FileBuffer::open("src/empty_file_for_testing.rs").unwrap();
    assert_eq!(fbuffer.iter().any(|_| true), false);
}

#[test]
fn empty_file_has_zero_resident_len() {
    let fbuffer = FileBuffer::open("src/empty_file_for_testing.rs").unwrap();
    assert_eq!(fbuffer.resident_len(0, 0), 0);
}

#[test]
fn page_size_at_least_4096() {
    // There is no reason why the page size cannot be smaller, it is just that in practice there
    // is no platform with a smaller page size, so this tests that `get_page_size()` returns
    // a plausible value.
    assert!(get_page_size() >= 4096);
}
<|endoftext|>


<commit_before>/*!
# Simple usage

## Creating the server

The easiest way to create a server is to call `Server::new()`.

The `new()` function returns an `IoResult<Server>` which will return an error
in the case where the server creation fails (for example if the listening port is already
occupied).

```rust
let server = httpd::ServerBuilder::new().build().unwrap();
```

A newly-created `Server` will immediatly start listening for incoming connections and HTTP
requests.

## Receiving requests

Calling `server.recv()` will block until the next request is available.
This function returns an `IoResult<Request>`, so you need to handle the possible errors.

```rust
loop {
    // blocks until the next request is received
    let request = match server.recv() {
        Ok(rq) => rq,
        Err(e) => { println!("error: {}", e); break }
    };

    // do something with the request
    ...
}
```

In a real-case scenario, you will probably want to spawn multiple worker tasks and call
`server.recv()` on all of them. Like this:

```rust
let server = Arc::new(server);

for _ in range(0u, 4) {
    let server = server.clone();

    spawn(proc() {
        loop {
            let rq = server.recv().unwrap();

            ...
        }
    })
}
```

If you don't want to block, you can call `server.try_recv()` instead.

## Handling requests

The `Request` object returned by `server.recv()` contains informations about the client's request.
The most useful methods are probably `request.get_method()` and `request.get_url()` which return
the requested method (`GET`, `POST`, etc.) and url.

To handle a request, you need to create a `Response` object. See the docs of this object for
more infos. Here is an example of creating a `Response` from a file:

```rust
let response = httpd::Response::from_file(Path::new("image.png"));
```

All that remains to do is call `request.respond()`:

```rust
request.respond(response)
```
*/

#![crate_name = "tiny-http"]
#![crate_type = "lib"]
#![license = "Apache"]
#![feature(unsafe_destructor)]

extern crate encoding;
extern crate flate;
extern crate time;
extern crate url;

use std::io::{Acceptor, IoResult, Listener};
use std::io::net::ip;
use std::io::net::tcp;
use std::comm::Select;
use std::sync::{Arc, Mutex};
use std::sync::atomics::AtomicBool;
use client::ClientConnection;

pub use common::{Header, HeaderField, HTTPVersion, Method, StatusCode};
pub use request::Request;
pub use response::Response;

mod client;
mod common;
mod request;
mod response;

#[allow(dead_code)]     // TODO: remove when everything is implemented
mod util;

/// The main class of this library.
///
/// Destroying this object will immediatly close the listening socket annd the reading
///  part of all the client's connections. Requests that have already been returned by
///  the `recv()` function will not close and the responses will be transferred to the client.
#[unstable]
pub struct Server {
    // tasks where the client connections are dispatched
    tasks_pool: util::TaskPool,

    // receiver for client connections
    connections_receiver: Mutex<Receiver<IoResult<ClientConnection>>>,

    // should be false as long as the server exists
    // when set to true, all the subtasks will close within a few hundreds ms
    close: Arc<AtomicBool>,

    // the sender linked to requests_receiver
    // cloned each time a client connection is created
    requests_sender: Mutex<Sender<Request>>,

    // channel to receive requests from
    requests_receiver: Mutex<Receiver<Request>>,

    // result of TcpListener::socket_name()
    listening_addr: ip::SocketAddr,
}

// this trait is to make sure that Server implements Share and Send
#[doc(hidden)]
trait MustBeShareDummy : Share + Send {}
#[doc(hidden)]
impl MustBeShareDummy for Server {}

#[unstable]
pub struct IncomingRequests<'a> {
    server: &'a Server
}

/// Object which allows you to build a server.
pub struct ServerBuilder {
    // the address to listen to
    address: ip::SocketAddr,

    // number of milliseconds before client timeout
    client_timeout_ms: u32,

    // maximum number of clients before 503
    // TODO:
    //max_clients: uint,
}

impl ServerBuilder {
    /// Creates a new builder.
    pub fn new() -> ServerBuilder {
        ServerBuilder {
            address: ip::SocketAddr { ip: ip::Ipv4Addr(0, 0, 0, 0), port: 80 },
            client_timeout_ms: 10 * 1000,
            //max_clients: { use std::num::Bounded; Bounded::max_value() },
        }
    }

    /// The server will use a precise port.
    pub fn with_port(mut self, port: ip::Port) -> ServerBuilder {
        self.address.port = port;
        self
    }

    /// The server will use a random port.
    ///
    /// Call `server.get_server_addr()` to retreive it once the server is created.
    pub fn with_random_port(mut self) -> ServerBuilder {
        self.address.port = 0;
        self
    }

    /// The server will use a precise port.
    pub fn with_client_connections_timeout(mut self, milliseconds: u32) -> ServerBuilder {
        self.client_timeout_ms = milliseconds;
        self
    }

    /// Builds the server with the given configuration.
    pub fn build(self) -> IoResult<Server> {
        Server::new(self)
    }
}

impl Server {
    /// Builds a new server that listens on the specified address.
    fn new(config: ServerBuilder) -> IoResult<Server> {
        // building the "close" variable
        let close_trigger = Arc::new(AtomicBool::new(false));

        // building the TcpAcceptor
        let (server, local_addr) = {
            let mut listener = try!(tcp::TcpListener::bind(
                format!("{}", config.address.ip).as_slice(), config.address.port));
            let local_addr = try!(listener.socket_name());
            let server = try!(listener.listen());
            let server = util::ClosableTcpAcceptor::new(server, close_trigger.clone());
            (server, local_addr)
        };

        // creating a task where server.accept() is continuously called
        // and ClientConnection objects are returned in the receiver
        let (tx_incoming, rx_incoming) = channel();

        let inside_close_trigger = close_trigger.clone();
        spawn(proc() {
            let mut server = server;

            loop {
                let new_client = server.accept().map(|sock| {
                    use util::ClosableTcpStream;

                    let read_closable = ClosableTcpStream::new(sock.clone(),
                        inside_close_trigger.clone(), true, false,
                        config.client_timeout_ms);

                    let write_closable = ClosableTcpStream::new(sock.clone(),
                        inside_close_trigger.clone(), false, true,
                        config.client_timeout_ms);

                    ClientConnection::new(write_closable, read_closable)
                });

                if tx_incoming.send_opt(new_client).is_err() {
                    break
                }
            }
        });

        //
        let (tx_requests, rx_requests) = channel();

        // result
        Ok(Server {
            tasks_pool: util::TaskPool::new(),
            connections_receiver: Mutex::new(rx_incoming),
            close: close_trigger,
            requests_sender: Mutex::new(tx_requests),
            requests_receiver: Mutex::new(rx_requests),
            listening_addr: local_addr,
        })
    }

    /// Returns an iterator for all the incoming requests.
    ///
    /// The iterator will return `None` if the server socket is shutdown.
    #[unstable]
    #[inline]
    pub fn incoming_requests<'a>(&'a self) -> IncomingRequests<'a> {
        IncomingRequests { server: self }
    }

    /// Returns the address the server is listening to.
    #[experimental]
    #[inline]
    pub fn get_server_addr(&self) -> ip::SocketAddr {
        self.listening_addr.clone()
    }

    /// Returns the number of clients currently connected to the server.
    #[stable]
    pub fn get_num_connections(&self) -> uint {
        unimplemented!()
        //self.requests_receiver.lock().len()
    }

    /// Blocks until an HTTP request has been submitted and returns it.
    #[stable]
    pub fn recv(&self) -> IoResult<Request> {
        let connections_receiver = self.connections_receiver.lock();
        let requests_receiver = self.requests_receiver.lock();

        // TODO: the select! macro doesn't seem to be usable without moving
        //       out of self, so we use Select directly

        let select = Select::new();

        let mut request_handle = select.handle(&*requests_receiver);
        unsafe { request_handle.add() };

        let mut connect_handle = select.handle(&*connections_receiver);
        unsafe { connect_handle.add() };

        loop {
            let id = select.wait();

            if id == request_handle.id() {
                let request = request_handle.recv();

                unsafe { request_handle.remove() };
                unsafe { connect_handle.remove() };

                return Ok(request)
            }

            if id == connect_handle.id() {
                let client = connect_handle.recv_opt();

                match client {
                    Ok(Ok(client)) => {
                        self.add_client(client);
                        continue
                    },
                    Ok(Err(err)) => {
                        unsafe { request_handle.remove() };
                        unsafe { connect_handle.remove() };

                        return Err(err)
                    },
                    Err(_) => {
                        use std::io;

                        unsafe { request_handle.remove() };
                        unsafe { connect_handle.remove() };

                        return Err(io::standard_error(io::Closed));
                    }
                }
            }

            unreachable!()
        }
    }

    /// Same as `recv()` but doesn't block.
    #[stable]
    pub fn try_recv(&self) -> IoResult<Option<Request>> {
        let mut connections_receiver = self.connections_receiver.lock();
        let mut requests_receiver = self.requests_receiver.lock();

        // processing all new clients
        loop {
            match connections_receiver.try_recv() {
                Ok(client) => self.add_client(try!(client)),
                Err(_) => break
            }
        }

        // reading the next request
        Ok(requests_receiver.try_recv().ok())
    }

    /// Adds a new client to the list.
    fn add_client(&self, client: ClientConnection) {
        let requests_sender = self.requests_sender.lock().clone();

        self.tasks_pool.spawn(proc() {
            let mut client = client;

            for rq in client {
                let res = requests_sender.send_opt(rq);
                if res.is_err() {
                    break
                }
            }
        });
    }
}

impl<'a> Iterator<Request> for IncomingRequests<'a> {
    fn next(&mut self) -> Option<Request> {
        self.server.recv().ok()
    }
}

impl Drop for Server {
    fn drop(&mut self) {
        use std::sync::atomics::Relaxed;
        self.close.store(true, Relaxed);
    }
}
<commit_msg>Default client timeout is now one minute<commit_after>/*!
# Simple usage

## Creating the server

The easiest way to create a server is to call `Server::new()`.

The `new()` function returns an `IoResult<Server>` which will return an error
in the case where the server creation fails (for example if the listening port is already
occupied).

```rust
let server = httpd::ServerBuilder::new().build().unwrap();
```

A newly-created `Server` will immediatly start listening for incoming connections and HTTP
requests.

## Receiving requests

Calling `server.recv()` will block until the next request is available.
This function returns an `IoResult<Request>`, so you need to handle the possible errors.

```rust
loop {
    // blocks until the next request is received
    let request = match server.recv() {
        Ok(rq) => rq,
        Err(e) => { println!("error: {}", e); break }
    };

    // do something with the request
    ...
}
```

In a real-case scenario, you will probably want to spawn multiple worker tasks and call
`server.recv()` on all of them. Like this:

```rust
let server = Arc::new(server);

for _ in range(0u, 4) {
    let server = server.clone();

    spawn(proc() {
        loop {
            let rq = server.recv().unwrap();

            ...
        }
    })
}
```

If you don't want to block, you can call `server.try_recv()` instead.

## Handling requests

The `Request` object returned by `server.recv()` contains informations about the client's request.
The most useful methods are probably `request.get_method()` and `request.get_url()` which return
the requested method (`GET`, `POST`, etc.) and url.

To handle a request, you need to create a `Response` object. See the docs of this object for
more infos. Here is an example of creating a `Response` from a file:

```rust
let response = httpd::Response::from_file(Path::new("image.png"));
```

All that remains to do is call `request.respond()`:

```rust
request.respond(response)
```
*/

#![crate_name = "tiny-http"]
#![crate_type = "lib"]
#![license = "Apache"]
#![feature(unsafe_destructor)]

extern crate encoding;
extern crate flate;
extern crate time;
extern crate url;

use std::io::{Acceptor, IoResult, Listener};
use std::io::net::ip;
use std::io::net::tcp;
use std::comm::Select;
use std::sync::{Arc, Mutex};
use std::sync::atomics::AtomicBool;
use client::ClientConnection;

pub use common::{Header, HeaderField, HTTPVersion, Method, StatusCode};
pub use request::Request;
pub use response::Response;

mod client;
mod common;
mod request;
mod response;

#[allow(dead_code)]     // TODO: remove when everything is implemented
mod util;

/// The main class of this library.
///
/// Destroying this object will immediatly close the listening socket annd the reading
///  part of all the client's connections. Requests that have already been returned by
///  the `recv()` function will not close and the responses will be transferred to the client.
#[unstable]
pub struct Server {
    // tasks where the client connections are dispatched
    tasks_pool: util::TaskPool,

    // receiver for client connections
    connections_receiver: Mutex<Receiver<IoResult<ClientConnection>>>,

    // should be false as long as the server exists
    // when set to true, all the subtasks will close within a few hundreds ms
    close: Arc<AtomicBool>,

    // the sender linked to requests_receiver
    // cloned each time a client connection is created
    requests_sender: Mutex<Sender<Request>>,

    // channel to receive requests from
    requests_receiver: Mutex<Receiver<Request>>,

    // result of TcpListener::socket_name()
    listening_addr: ip::SocketAddr,
}

// this trait is to make sure that Server implements Share and Send
#[doc(hidden)]
trait MustBeShareDummy : Share + Send {}
#[doc(hidden)]
impl MustBeShareDummy for Server {}

#[unstable]
pub struct IncomingRequests<'a> {
    server: &'a Server
}

/// Object which allows you to build a server.
pub struct ServerBuilder {
    // the address to listen to
    address: ip::SocketAddr,

    // number of milliseconds before client timeout
    client_timeout_ms: u32,

    // maximum number of clients before 503
    // TODO:
    //max_clients: uint,
}

impl ServerBuilder {
    /// Creates a new builder.
    pub fn new() -> ServerBuilder {
        ServerBuilder {
            address: ip::SocketAddr { ip: ip::Ipv4Addr(0, 0, 0, 0), port: 80 },
            client_timeout_ms: 60 * 1000,
            //max_clients: { use std::num::Bounded; Bounded::max_value() },
        }
    }

    /// The server will use a precise port.
    pub fn with_port(mut self, port: ip::Port) -> ServerBuilder {
        self.address.port = port;
        self
    }

    /// The server will use a random port.
    ///
    /// Call `server.get_server_addr()` to retreive it once the server is created.
    pub fn with_random_port(mut self) -> ServerBuilder {
        self.address.port = 0;
        self
    }

    /// The server will use a precise port.
    pub fn with_client_connections_timeout(mut self, milliseconds: u32) -> ServerBuilder {
        self.client_timeout_ms = milliseconds;
        self
    }

    /// Builds the server with the given configuration.
    pub fn build(self) -> IoResult<Server> {
        Server::new(self)
    }
}

impl Server {
    /// Builds a new server that listens on the specified address.
    fn new(config: ServerBuilder) -> IoResult<Server> {
        // building the "close" variable
        let close_trigger = Arc::new(AtomicBool::new(false));

        // building the TcpAcceptor
        let (server, local_addr) = {
            let mut listener = try!(tcp::TcpListener::bind(
                format!("{}", config.address.ip).as_slice(), config.address.port));
            let local_addr = try!(listener.socket_name());
            let server = try!(listener.listen());
            let server = util::ClosableTcpAcceptor::new(server, close_trigger.clone());
            (server, local_addr)
        };

        // creating a task where server.accept() is continuously called
        // and ClientConnection objects are returned in the receiver
        let (tx_incoming, rx_incoming) = channel();

        let inside_close_trigger = close_trigger.clone();
        spawn(proc() {
            let mut server = server;

            loop {
                let new_client = server.accept().map(|sock| {
                    use util::ClosableTcpStream;

                    let read_closable = ClosableTcpStream::new(sock.clone(),
                        inside_close_trigger.clone(), true, false,
                        config.client_timeout_ms);

                    let write_closable = ClosableTcpStream::new(sock.clone(),
                        inside_close_trigger.clone(), false, true,
                        config.client_timeout_ms);

                    ClientConnection::new(write_closable, read_closable)
                });

                if tx_incoming.send_opt(new_client).is_err() {
                    break
                }
            }
        });

        //
        let (tx_requests, rx_requests) = channel();

        // result
        Ok(Server {
            tasks_pool: util::TaskPool::new(),
            connections_receiver: Mutex::new(rx_incoming),
            close: close_trigger,
            requests_sender: Mutex::new(tx_requests),
            requests_receiver: Mutex::new(rx_requests),
            listening_addr: local_addr,
        })
    }

    /// Returns an iterator for all the incoming requests.
    ///
    /// The iterator will return `None` if the server socket is shutdown.
    #[unstable]
    #[inline]
    pub fn incoming_requests<'a>(&'a self) -> IncomingRequests<'a> {
        IncomingRequests { server: self }
    }

    /// Returns the address the server is listening to.
    #[experimental]
    #[inline]
    pub fn get_server_addr(&self) -> ip::SocketAddr {
        self.listening_addr.clone()
    }

    /// Returns the number of clients currently connected to the server.
    #[stable]
    pub fn get_num_connections(&self) -> uint {
        unimplemented!()
        //self.requests_receiver.lock().len()
    }

    /// Blocks until an HTTP request has been submitted and returns it.
    #[stable]
    pub fn recv(&self) -> IoResult<Request> {
        let connections_receiver = self.connections_receiver.lock();
        let requests_receiver = self.requests_receiver.lock();

        // TODO: the select! macro doesn't seem to be usable without moving
        //       out of self, so we use Select directly

        let select = Select::new();

        let mut request_handle = select.handle(&*requests_receiver);
        unsafe { request_handle.add() };

        let mut connect_handle = select.handle(&*connections_receiver);
        unsafe { connect_handle.add() };

        loop {
            let id = select.wait();

            if id == request_handle.id() {
                let request = request_handle.recv();

                unsafe { request_handle.remove() };
                unsafe { connect_handle.remove() };

                return Ok(request)
            }

            if id == connect_handle.id() {
                let client = connect_handle.recv_opt();

                match client {
                    Ok(Ok(client)) => {
                        self.add_client(client);
                        continue
                    },
                    Ok(Err(err)) => {
                        unsafe { request_handle.remove() };
                        unsafe { connect_handle.remove() };

                        return Err(err)
                    },
                    Err(_) => {
                        use std::io;

                        unsafe { request_handle.remove() };
                        unsafe { connect_handle.remove() };

                        return Err(io::standard_error(io::Closed));
                    }
                }
            }

            unreachable!()
        }
    }

    /// Same as `recv()` but doesn't block.
    #[stable]
    pub fn try_recv(&self) -> IoResult<Option<Request>> {
        let mut connections_receiver = self.connections_receiver.lock();
        let mut requests_receiver = self.requests_receiver.lock();

        // processing all new clients
        loop {
            match connections_receiver.try_recv() {
                Ok(client) => self.add_client(try!(client)),
                Err(_) => break
            }
        }

        // reading the next request
        Ok(requests_receiver.try_recv().ok())
    }

    /// Adds a new client to the list.
    fn add_client(&self, client: ClientConnection) {
        let requests_sender = self.requests_sender.lock().clone();

        self.tasks_pool.spawn(proc() {
            let mut client = client;

            for rq in client {
                let res = requests_sender.send_opt(rq);
                if res.is_err() {
                    break
                }
            }
        });
    }
}

impl<'a> Iterator<Request> for IncomingRequests<'a> {
    fn next(&mut self) -> Option<Request> {
        self.server.recv().ok()
    }
}

impl Drop for Server {
    fn drop(&mut self) {
        use std::sync::atomics::Relaxed;
        self.close.store(true, Relaxed);
    }
}
<|endoftext|>


<commit_before>#![feature(libc)]
extern crate libc;

use std::io::Write;
use std::io;

fn isatty() -> bool {
    let isatty = unsafe { libc::isatty(libc::STDIN_FILENO as i32) } != 0;
    isatty
}

pub fn readline(prompt: &'static str) -> Option<String> {
    // Write prompt and flush it to stdout
    let mut stdout = io::stdout();
    stdout.write(prompt.as_bytes());
    stdout.flush();

    let mut buffer = String::new();
    if isatty() {
        Some(buffer)
    } else {
        None
    }
}

fn read_handler(buffer: String) -> String {
   buffer
}
<commit_msg>Added function to read from a terminal<commit_after>extern crate libc;

use std::io::{Write, Read};
use std::io;

fn isatty() -> bool {
    let isatty = unsafe { libc::isatty(libc::STDIN_FILENO as i32) } != 0;
    isatty
}

pub fn readline(prompt: &'static str) -> Option<String> {
    // Write prompt and flush it to stdout
    let mut stdout = io::stdout();
    stdout.write(prompt.as_bytes());
    stdout.flush();

    if isatty() {
        Some(read_handler())
    } else {
        None
    }
}

fn read_handler() -> String {
    let mut buffer = Vec::new();
    let mut input: [u8; 1] = [0];

    // Create handle to stdin
    let mut stdin = io::stdin();
    let numread = stdin.take(1).read(&mut input).unwrap();

    println!("Read #{:?} bytes with a value of{:?}",numread,input[0]);
    buffer.push(input[0]);

    String::from_utf8(buffer).unwrap()
}
<|endoftext|>