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

extern crate flate2;
extern crate libc;
extern crate rustc_middle;
extern crate rustc_codegen_ssa;
extern crate rustc_data_structures;
extern crate rustc_errors;
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_symbol_mangling;
extern crate rustc_target;
extern crate rustc_ast;

// This prevents duplicating functions and statics that are already part of the host rustc process.
#[allow(unused_extern_crates)]
extern crate rustc_driver;

use std::any::Any;

use rustc_errors::ErrorReported;
use rustc_middle::dep_graph::{DepGraph, WorkProduct, WorkProductId};
use rustc_middle::middle::cstore::{EncodedMetadata, MetadataLoader};
use rustc_session::Session;
use rustc_session::config::OutputFilenames;
use rustc_middle::ty::query::Providers;
use rustc_codegen_ssa::CodegenResults;
use rustc_codegen_ssa::traits::CodegenBackend;

use cranelift_codegen::settings::{self, Configurable};

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 unsize;
mod value_and_place;
mod vtable;

mod prelude {
    pub(crate) use std::convert::{TryFrom, TryInto};

    pub(crate) use rustc_ast::ast::{FloatTy, IntTy, UintTy};
    pub(crate) use rustc_span::Span;

    pub(crate) use rustc_middle::bug;
    pub(crate) use rustc_hir::def_id::{DefId, LOCAL_CRATE};
    pub(crate) use rustc_middle::mir::{self, *};
    pub(crate) use rustc_middle::ty::layout::{self, TyAndLayout};
    pub(crate) use rustc_target::abi::{Abi, LayoutOf, Scalar, Size, VariantIdx};
    pub(crate) use rustc_middle::ty::{
        self, FnSig, Instance, InstanceDef, ParamEnv, Ty, TyCtxt, TypeAndMut, TypeFoldable,
    };

    pub(crate) use rustc_data_structures::fx::FxHashMap;

    pub(crate) use rustc_index::vec::Idx;

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

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

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

struct CodegenCx<'tcx, B: Backend + 'static> {
    tcx: TyCtxt<'tcx>,
    module: Module<B>,
    constants_cx: ConstantCx,
    cached_context: Context,
    vtables: FxHashMap<(Ty<'tcx>, Option<ty::PolyExistentialTraitRef<'tcx>>), DataId>,
    debug_context: Option<DebugContext<'tcx>>,
    unwind_context: UnwindContext<'tcx>,
}

impl<'tcx, B: Backend + 'static> CodegenCx<'tcx, B> {
    fn new(
        tcx: TyCtxt<'tcx>,
        module: Module<B>,
        debug_info: bool,
    ) -> Self {
        let unwind_context = UnwindContext::new(tcx, module.isa());
        let debug_context = if debug_info {
            Some(DebugContext::new(
                tcx,
                module.isa(),
            ))
        } else {
            None
        };
        CodegenCx {
            tcx,
            module,
            constants_cx: ConstantCx::default(),
            cached_context: Context::new(),
            vtables: FxHashMap::default(),
            debug_context,
            unwind_context,
        }
    }

    fn finalize(mut self) -> (Module<B>, Option<DebugContext<'tcx>>, UnwindContext<'tcx>) {
        self.constants_cx.finalize(self.tcx, &mut self.module);
        (self.module, self.debug_context, self.unwind_context)
    }
}

struct CraneliftCodegenBackend;

impl CodegenBackend for CraneliftCodegenBackend {
    fn init(&self, sess: &Session) {
        if sess.lto() != rustc_session::config::Lto::No && sess.opts.cg.embed_bitcode {
            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
                target_features_whitelist::all_known_features()
                    .chain(Some(("cg_clif", None)))
                    .map(|(a, b)| (a.to_string(), b))
                    .collect()
            } else {
                target_features_whitelist::target_feature_whitelist(tcx.sess)
                    .iter()
                    .chain(&Some(("cg_clif", None)))
                    .map(|&(a, b)| (a.to_string(), b))
                    .collect()
            }
        };
    }
    fn provide_extern(&self, _providers: &mut Providers<'_>) {}

    fn target_features(&self, _sess: &Session) -> Vec<rustc_span::Symbol> {
        vec![rustc_span::Symbol::intern("cg_clif")]
    }

    fn codegen_crate<'tcx>(
        &self,
        tcx: TyCtxt<'tcx>,
        metadata: EncodedMetadata,
        need_metadata_module: bool,
    ) -> Box<dyn Any> {
        let res = driver::codegen_crate(tcx, metadata, need_metadata_module);

        rustc_symbol_mangling::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", "none").unwrap();
        }
        OptLevel::Less | OptLevel::Default => {}
        OptLevel::Aggressive => {
            flags_builder.set("opt_level", "speed_and_size").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>Add sess.abort_if_errors() to link<commit_after>#![feature(rustc_private, decl_macro, type_alias_impl_trait, associated_type_bounds, never_type)]
#![allow(intra_doc_link_resolution_failure)]
#![warn(rust_2018_idioms)]
#![warn(unused_lifetimes)]

extern crate flate2;
extern crate libc;
extern crate rustc_middle;
extern crate rustc_codegen_ssa;
extern crate rustc_data_structures;
extern crate rustc_errors;
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_symbol_mangling;
extern crate rustc_target;
extern crate rustc_ast;

// This prevents duplicating functions and statics that are already part of the host rustc process.
#[allow(unused_extern_crates)]
extern crate rustc_driver;

use std::any::Any;

use rustc_errors::ErrorReported;
use rustc_middle::dep_graph::{DepGraph, WorkProduct, WorkProductId};
use rustc_middle::middle::cstore::{EncodedMetadata, MetadataLoader};
use rustc_session::Session;
use rustc_session::config::OutputFilenames;
use rustc_middle::ty::query::Providers;
use rustc_codegen_ssa::CodegenResults;
use rustc_codegen_ssa::traits::CodegenBackend;

use cranelift_codegen::settings::{self, Configurable};

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 unsize;
mod value_and_place;
mod vtable;

mod prelude {
    pub(crate) use std::convert::{TryFrom, TryInto};

    pub(crate) use rustc_ast::ast::{FloatTy, IntTy, UintTy};
    pub(crate) use rustc_span::Span;

    pub(crate) use rustc_middle::bug;
    pub(crate) use rustc_hir::def_id::{DefId, LOCAL_CRATE};
    pub(crate) use rustc_middle::mir::{self, *};
    pub(crate) use rustc_middle::ty::layout::{self, TyAndLayout};
    pub(crate) use rustc_target::abi::{Abi, LayoutOf, Scalar, Size, VariantIdx};
    pub(crate) use rustc_middle::ty::{
        self, FnSig, Instance, InstanceDef, ParamEnv, Ty, TyCtxt, TypeAndMut, TypeFoldable,
    };

    pub(crate) use rustc_data_structures::fx::FxHashMap;

    pub(crate) use rustc_index::vec::Idx;

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

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

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

struct CodegenCx<'tcx, B: Backend + 'static> {
    tcx: TyCtxt<'tcx>,
    module: Module<B>,
    constants_cx: ConstantCx,
    cached_context: Context,
    vtables: FxHashMap<(Ty<'tcx>, Option<ty::PolyExistentialTraitRef<'tcx>>), DataId>,
    debug_context: Option<DebugContext<'tcx>>,
    unwind_context: UnwindContext<'tcx>,
}

impl<'tcx, B: Backend + 'static> CodegenCx<'tcx, B> {
    fn new(
        tcx: TyCtxt<'tcx>,
        module: Module<B>,
        debug_info: bool,
    ) -> Self {
        let unwind_context = UnwindContext::new(tcx, module.isa());
        let debug_context = if debug_info {
            Some(DebugContext::new(
                tcx,
                module.isa(),
            ))
        } else {
            None
        };
        CodegenCx {
            tcx,
            module,
            constants_cx: ConstantCx::default(),
            cached_context: Context::new(),
            vtables: FxHashMap::default(),
            debug_context,
            unwind_context,
        }
    }

    fn finalize(mut self) -> (Module<B>, Option<DebugContext<'tcx>>, UnwindContext<'tcx>) {
        self.constants_cx.finalize(self.tcx, &mut self.module);
        (self.module, self.debug_context, self.unwind_context)
    }
}

struct CraneliftCodegenBackend;

impl CodegenBackend for CraneliftCodegenBackend {
    fn init(&self, sess: &Session) {
        if sess.lto() != rustc_session::config::Lto::No && sess.opts.cg.embed_bitcode {
            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
                target_features_whitelist::all_known_features()
                    .chain(Some(("cg_clif", None)))
                    .map(|(a, b)| (a.to_string(), b))
                    .collect()
            } else {
                target_features_whitelist::target_feature_whitelist(tcx.sess)
                    .iter()
                    .chain(&Some(("cg_clif", None)))
                    .map(|&(a, b)| (a.to_string(), b))
                    .collect()
            }
        };
    }
    fn provide_extern(&self, _providers: &mut Providers<'_>) {}

    fn target_features(&self, _sess: &Session) -> Vec<rustc_span::Symbol> {
        vec![rustc_span::Symbol::intern("cg_clif")]
    }

    fn codegen_crate<'tcx>(
        &self,
        tcx: TyCtxt<'tcx>,
        metadata: EncodedMetadata,
        need_metadata_module: bool,
    ) -> Box<dyn Any> {
        let res = driver::codegen_crate(tcx, metadata, need_metadata_module);

        rustc_symbol_mangling::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;

        sess.abort_if_errors();

        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", "none").unwrap();
        }
        OptLevel::Less | OptLevel::Default => {}
        OptLevel::Aggressive => {
            flags_builder.set("opt_level", "speed_and_size").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>/*!
A uniform is a global variable in your program. In order to draw something, you will need to
give `glium` the values of all your uniforms. Objects that implement the `Uniform` trait are
here to do that.

There are two primarly ways to do this. The first one is to create your own structure and put
the `#[uniforms]` attribute on it. See the `glium_macros` crate for more infos.

The second way is to use the `uniform!` macro provided by glium:

```no_run
#[macro_use]
extern crate glium;

# fn main() {
# let display: glium::Display = unsafe { std::mem::uninitialized() };
# let tex: f32 = unsafe { std::mem::uninitialized() };
# let matrix: f32 = unsafe { std::mem::uninitialized() };
let uniforms = uniform! {
    texture: tex,
    matrix: matrix
};
# }
```

In both situations, each field must implement the `UniformValue` trait.

## Samplers

In order to customize the way a texture is being sampled, you must use a `Sampler`.

```no_run
#[macro_use]
extern crate glium;

# fn main() {
# let display: glium::Display = unsafe { std::mem::uninitialized() };
# let texture: glium::texture::Texture2d = unsafe { std::mem::uninitialized() };
let uniforms = uniform! {
    texture: glium::uniforms::Sampler::new(&texture)
                        .magnify_filter(glium::uniforms::MagnifySamplerFilter::Nearest)
};
# }
```

## Blocks

In GLSL, you can choose to use a uniform *block*. When you use a block, you first need to
upload the content of this block in the video memory thanks to a `UniformBuffer`. Then you
can link the buffer to the name of the block, just like any other uniform.

```no_run
#[macro_use]
extern crate glium;
# fn main() {
# let display: glium::Display = unsafe { std::mem::uninitialized() };
# let texture: glium::texture::Texture2d = unsafe { std::mem::uninitialized() };

let program = glium::Program::from_source(&display,
    "
        #version 110

        attribute vec2 position;

        void main() {
            gl_Position = vec4(position, 0.0, 1.0);
        }
    ",
    "
        #version 330
        uniform layout(std140);

        uniform MyBlock {
            vec3 color;
        };

        void main() {
            gl_FragColor = vec4(color, 1.0);
        }
    ",
    None);

let buffer = glium::uniforms::UniformBuffer::new(&display, (0.5f32, 0.5f32, 0.5f32)).unwrap();

let uniforms = uniform! {
    MyBlock: &buffer
};
# }
```

*/
pub use self::buffer::UniformBuffer;
pub use self::sampler::{SamplerWrapFunction, MagnifySamplerFilter, MinifySamplerFilter};
pub use self::sampler::{Sampler, SamplerBehavior};
pub use self::uniforms::{EmptyUniforms, UniformsStorage};
pub use self::value::{UniformValue, UniformType};

use buffer::Content as BufferContent;
use buffer::Buffer;
use program;
use program::BlockLayout;

mod bind;
mod buffer;
mod sampler;
mod uniforms;
mod value;

/// Object that contains the values of all the uniforms to bind to a program.
///
/// Objects of this type can be passed to the `draw()` function.
pub trait Uniforms {
    /// Calls the parameter once with the name and value of each uniform.
    fn visit_values<'a, F: FnMut(&str, UniformValue<'a>)>(&'a self, F);
}

/// Error about a block layout mismatch.
#[derive(Clone, Debug)]
pub enum LayoutMismatchError {
    /// There is a mismatch in the type of one element.
    TypeMismatch {
        /// Type expected by the shader.
        expected: UniformType,
        /// Type that you gave.
        obtained: UniformType,
    },

    /// The expected layout is totally different from what we have.
    LayoutMismatch {
        /// Layout expected by the shader.
        expected: BlockLayout,
        /// Layout of the input.
        obtained: BlockLayout,
    },

    /// The type of data is good, but there is a misalignment.
    OffsetMismatch {
        /// Expected offset of a member.
        expected: usize,
        /// Offset of the same member in the input.
        obtained: usize,
    },

    /// There is a mismatch in a submember of this layout.
    ///
    /// This is kind of a hierarchy inside the `LayoutMismatchError`s.
    MemberMismatch {
        /// Name of the field.
        member: String,
        /// The sub-error.
        err: Box<LayoutMismatchError>,
    },

    /// A field is missing in either the expected of the input data layout.
    MissingField {
        /// Name of the field.
        name: String,
    },
}

/// Value that can be used as the value of a uniform.
///
/// This includes buffers and textures for example.
pub trait AsUniformValue {
    /// Builds a `UniformValue`.
    fn as_uniform_value(&self) -> UniformValue;
}

// TODO: no way to bind a slice
impl<'a, T: ?Sized> AsUniformValue for &'a Buffer<T> where T: UniformBlock + BufferContent {
    #[inline]
    fn as_uniform_value(&self) -> UniformValue {
        #[inline]
        fn f<T: ?Sized>(block: &program::UniformBlock)
                        -> Result<(), LayoutMismatchError> where T: UniformBlock + BufferContent
        {
            // TODO: more checks?
            T::matches(&block.layout, 0)
        }

        UniformValue::Block(self.as_slice_any(), f::<T>)
    }
}

/// Objects that are suitable for being inside a uniform block or a SSBO.
pub trait UniformBlock {        // TODO: `: Copy`, but unsized structs don't impl `Copy`
    /// Checks whether the uniforms' layout matches the given block if `Self` starts at
    /// the given offset.
    fn matches(&BlockLayout, base_offset: usize) -> Result<(), LayoutMismatchError>;

    /// Builds the `BlockLayout` corresponding to the current object.
    fn build_layout(base_offset: usize) -> BlockLayout;
}

impl<T> UniformBlock for [T] where T: UniformBlock {
    fn matches(layout: &BlockLayout, base_offset: usize)
               -> Result<(), LayoutMismatchError>
    {
        if let &BlockLayout::DynamicSizedArray { ref content } = layout {
            <T as UniformBlock>::matches(content, base_offset)
                .map_err(|err| {
                    LayoutMismatchError::MemberMismatch {
                        member: "<dynamic array content>".to_owned(),
                        err: Box::new(err),
                    }
                })

        } else if let &BlockLayout::Array { ref content, .. } = layout {
            <T as UniformBlock>::matches(content, base_offset)
                .map_err(|err| {
                    LayoutMismatchError::MemberMismatch {
                        member: "<dynamic array content>".to_owned(),
                        err: Box::new(err),
                    }
                })

        } else {
            Err(LayoutMismatchError::LayoutMismatch {
                expected: layout.clone(),
                obtained: <Self as UniformBlock>::build_layout(base_offset),
            })
        }
    }

    #[inline]
    fn build_layout(base_offset: usize) -> BlockLayout {
        BlockLayout::DynamicSizedArray {
            content: Box::new(<T as UniformBlock>::build_layout(base_offset)),
        }
    }
}

macro_rules! impl_uniform_block_array {
    ($len:expr) => (
        impl<T> UniformBlock for [T; $len] where T: UniformBlock {
            fn matches(layout: &program::BlockLayout, base_offset: usize)
                       -> Result<(), LayoutMismatchError>
            {
                if let &BlockLayout::Array { ref content, length } = layout {
                    if let Err(_) = T::matches(content, base_offset) {
                        return Err(LayoutMismatchError::LayoutMismatch {
                            expected: (**content).clone(),
                            obtained: T::build_layout(base_offset),
                        });
                    }

                    if length != $len {
                        return Err(LayoutMismatchError::LayoutMismatch {
                            expected: (**content).clone(),
                            obtained: T::build_layout(base_offset),
                        });
                    }

                    Ok(())

                } else {
                    Err(LayoutMismatchError::LayoutMismatch {
                        expected: layout.clone(),
                        obtained: Self::build_layout(base_offset),
                    })
                }
            }

            #[inline]
            fn build_layout(base_offset: usize) -> program::BlockLayout {
                BlockLayout::Array {
                    content: Box::new(T::build_layout(base_offset)),
                    length: $len,
                }
            }
        }
    );
}

impl_uniform_block_array!(5);
impl_uniform_block_array!(6);
impl_uniform_block_array!(7);
impl_uniform_block_array!(8);
impl_uniform_block_array!(9);
impl_uniform_block_array!(10);
impl_uniform_block_array!(11);
impl_uniform_block_array!(12);
impl_uniform_block_array!(13);
impl_uniform_block_array!(14);
impl_uniform_block_array!(15);
impl_uniform_block_array!(16);
impl_uniform_block_array!(17);
impl_uniform_block_array!(18);
impl_uniform_block_array!(19);
impl_uniform_block_array!(20);
impl_uniform_block_array!(21);
impl_uniform_block_array!(22);
impl_uniform_block_array!(23);
impl_uniform_block_array!(24);
impl_uniform_block_array!(25);
impl_uniform_block_array!(26);
impl_uniform_block_array!(27);
impl_uniform_block_array!(28);
impl_uniform_block_array!(29);
impl_uniform_block_array!(30);
impl_uniform_block_array!(31);
impl_uniform_block_array!(32);
impl_uniform_block_array!(64);
impl_uniform_block_array!(128);
impl_uniform_block_array!(256);
impl_uniform_block_array!(512);
impl_uniform_block_array!(1024);
impl_uniform_block_array!(2048);
<commit_msg>Arrays now match structs with single members<commit_after>/*!
A uniform is a global variable in your program. In order to draw something, you will need to
give `glium` the values of all your uniforms. Objects that implement the `Uniform` trait are
here to do that.

There are two primarly ways to do this. The first one is to create your own structure and put
the `#[uniforms]` attribute on it. See the `glium_macros` crate for more infos.

The second way is to use the `uniform!` macro provided by glium:

```no_run
#[macro_use]
extern crate glium;

# fn main() {
# let display: glium::Display = unsafe { std::mem::uninitialized() };
# let tex: f32 = unsafe { std::mem::uninitialized() };
# let matrix: f32 = unsafe { std::mem::uninitialized() };
let uniforms = uniform! {
    texture: tex,
    matrix: matrix
};
# }
```

In both situations, each field must implement the `UniformValue` trait.

## Samplers

In order to customize the way a texture is being sampled, you must use a `Sampler`.

```no_run
#[macro_use]
extern crate glium;

# fn main() {
# let display: glium::Display = unsafe { std::mem::uninitialized() };
# let texture: glium::texture::Texture2d = unsafe { std::mem::uninitialized() };
let uniforms = uniform! {
    texture: glium::uniforms::Sampler::new(&texture)
                        .magnify_filter(glium::uniforms::MagnifySamplerFilter::Nearest)
};
# }
```

## Blocks

In GLSL, you can choose to use a uniform *block*. When you use a block, you first need to
upload the content of this block in the video memory thanks to a `UniformBuffer`. Then you
can link the buffer to the name of the block, just like any other uniform.

```no_run
#[macro_use]
extern crate glium;
# fn main() {
# let display: glium::Display = unsafe { std::mem::uninitialized() };
# let texture: glium::texture::Texture2d = unsafe { std::mem::uninitialized() };

let program = glium::Program::from_source(&display,
    "
        #version 110

        attribute vec2 position;

        void main() {
            gl_Position = vec4(position, 0.0, 1.0);
        }
    ",
    "
        #version 330
        uniform layout(std140);

        uniform MyBlock {
            vec3 color;
        };

        void main() {
            gl_FragColor = vec4(color, 1.0);
        }
    ",
    None);

let buffer = glium::uniforms::UniformBuffer::new(&display, (0.5f32, 0.5f32, 0.5f32)).unwrap();

let uniforms = uniform! {
    MyBlock: &buffer
};
# }
```

*/
pub use self::buffer::UniformBuffer;
pub use self::sampler::{SamplerWrapFunction, MagnifySamplerFilter, MinifySamplerFilter};
pub use self::sampler::{Sampler, SamplerBehavior};
pub use self::uniforms::{EmptyUniforms, UniformsStorage};
pub use self::value::{UniformValue, UniformType};

use buffer::Content as BufferContent;
use buffer::Buffer;
use program;
use program::BlockLayout;

mod bind;
mod buffer;
mod sampler;
mod uniforms;
mod value;

/// Object that contains the values of all the uniforms to bind to a program.
///
/// Objects of this type can be passed to the `draw()` function.
pub trait Uniforms {
    /// Calls the parameter once with the name and value of each uniform.
    fn visit_values<'a, F: FnMut(&str, UniformValue<'a>)>(&'a self, F);
}

/// Error about a block layout mismatch.
#[derive(Clone, Debug)]
pub enum LayoutMismatchError {
    /// There is a mismatch in the type of one element.
    TypeMismatch {
        /// Type expected by the shader.
        expected: UniformType,
        /// Type that you gave.
        obtained: UniformType,
    },

    /// The expected layout is totally different from what we have.
    LayoutMismatch {
        /// Layout expected by the shader.
        expected: BlockLayout,
        /// Layout of the input.
        obtained: BlockLayout,
    },

    /// The type of data is good, but there is a misalignment.
    OffsetMismatch {
        /// Expected offset of a member.
        expected: usize,
        /// Offset of the same member in the input.
        obtained: usize,
    },

    /// There is a mismatch in a submember of this layout.
    ///
    /// This is kind of a hierarchy inside the `LayoutMismatchError`s.
    MemberMismatch {
        /// Name of the field.
        member: String,
        /// The sub-error.
        err: Box<LayoutMismatchError>,
    },

    /// A field is missing in either the expected of the input data layout.
    MissingField {
        /// Name of the field.
        name: String,
    },
}

/// Value that can be used as the value of a uniform.
///
/// This includes buffers and textures for example.
pub trait AsUniformValue {
    /// Builds a `UniformValue`.
    fn as_uniform_value(&self) -> UniformValue;
}

// TODO: no way to bind a slice
impl<'a, T: ?Sized> AsUniformValue for &'a Buffer<T> where T: UniformBlock + BufferContent {
    #[inline]
    fn as_uniform_value(&self) -> UniformValue {
        #[inline]
        fn f<T: ?Sized>(block: &program::UniformBlock)
                        -> Result<(), LayoutMismatchError> where T: UniformBlock + BufferContent
        {
            // TODO: more checks?
            T::matches(&block.layout, 0)
        }

        UniformValue::Block(self.as_slice_any(), f::<T>)
    }
}

/// Objects that are suitable for being inside a uniform block or a SSBO.
pub trait UniformBlock {        // TODO: `: Copy`, but unsized structs don't impl `Copy`
    /// Checks whether the uniforms' layout matches the given block if `Self` starts at
    /// the given offset.
    fn matches(&BlockLayout, base_offset: usize) -> Result<(), LayoutMismatchError>;

    /// Builds the `BlockLayout` corresponding to the current object.
    fn build_layout(base_offset: usize) -> BlockLayout;
}

impl<T> UniformBlock for [T] where T: UniformBlock {
    fn matches(layout: &BlockLayout, base_offset: usize)
               -> Result<(), LayoutMismatchError>
    {
        if let &BlockLayout::Struct { ref members } = layout {
            if members.len() == 1 {
                return Self::matches(&members[0].1, base_offset);
            }
        }

        if let &BlockLayout::DynamicSizedArray { ref content } = layout {
            <T as UniformBlock>::matches(content, base_offset)
                .map_err(|err| {
                    LayoutMismatchError::MemberMismatch {
                        member: "<dynamic array content>".to_owned(),
                        err: Box::new(err),
                    }
                })

        } else if let &BlockLayout::Array { ref content, .. } = layout {
            <T as UniformBlock>::matches(content, base_offset)
                .map_err(|err| {
                    LayoutMismatchError::MemberMismatch {
                        member: "<dynamic array content>".to_owned(),
                        err: Box::new(err),
                    }
                })

        } else {
            Err(LayoutMismatchError::LayoutMismatch {
                expected: layout.clone(),
                obtained: <Self as UniformBlock>::build_layout(base_offset),
            })
        }
    }

    #[inline]
    fn build_layout(base_offset: usize) -> BlockLayout {
        BlockLayout::DynamicSizedArray {
            content: Box::new(<T as UniformBlock>::build_layout(base_offset)),
        }
    }
}

macro_rules! impl_uniform_block_array {
    ($len:expr) => (
        impl<T> UniformBlock for [T; $len] where T: UniformBlock {
            fn matches(layout: &program::BlockLayout, base_offset: usize)
                       -> Result<(), LayoutMismatchError>
            {
                if let &BlockLayout::Struct { ref members } = layout {
                    if members.len() == 1 {
                        return Self::matches(&members[0].1, base_offset);
                    }
                }

                if let &BlockLayout::Array { ref content, length } = layout {
                    if let Err(_) = T::matches(content, base_offset) {
                        return Err(LayoutMismatchError::LayoutMismatch {
                            expected: (**content).clone(),
                            obtained: T::build_layout(base_offset),
                        });
                    }

                    if length != $len {
                        return Err(LayoutMismatchError::LayoutMismatch {
                            expected: (**content).clone(),
                            obtained: T::build_layout(base_offset),
                        });
                    }

                    Ok(())

                } else {
                    Err(LayoutMismatchError::LayoutMismatch {
                        expected: layout.clone(),
                        obtained: Self::build_layout(base_offset),
                    })
                }
            }

            #[inline]
            fn build_layout(base_offset: usize) -> program::BlockLayout {
                BlockLayout::Array {
                    content: Box::new(T::build_layout(base_offset)),
                    length: $len,
                }
            }
        }
    );
}

impl_uniform_block_array!(5);
impl_uniform_block_array!(6);
impl_uniform_block_array!(7);
impl_uniform_block_array!(8);
impl_uniform_block_array!(9);
impl_uniform_block_array!(10);
impl_uniform_block_array!(11);
impl_uniform_block_array!(12);
impl_uniform_block_array!(13);
impl_uniform_block_array!(14);
impl_uniform_block_array!(15);
impl_uniform_block_array!(16);
impl_uniform_block_array!(17);
impl_uniform_block_array!(18);
impl_uniform_block_array!(19);
impl_uniform_block_array!(20);
impl_uniform_block_array!(21);
impl_uniform_block_array!(22);
impl_uniform_block_array!(23);
impl_uniform_block_array!(24);
impl_uniform_block_array!(25);
impl_uniform_block_array!(26);
impl_uniform_block_array!(27);
impl_uniform_block_array!(28);
impl_uniform_block_array!(29);
impl_uniform_block_array!(30);
impl_uniform_block_array!(31);
impl_uniform_block_array!(32);
impl_uniform_block_array!(64);
impl_uniform_block_array!(128);
impl_uniform_block_array!(256);
impl_uniform_block_array!(512);
impl_uniform_block_array!(1024);
impl_uniform_block_array!(2048);
<|endoftext|>


<commit_before>// Copyright 2016 Philipp Oppermann. See the README.md
// file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.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.

#![feature(lang_items)]
#![feature(const_fn, unique)]
#![feature(alloc)]
#![feature(asm)]
#![feature(naked_functions)]
#![feature(abi_x86_interrupt)]
#![feature(const_unique_new)]
#![no_std]

extern crate rlibc;
extern crate volatile;
extern crate spin;
extern crate multiboot2;
#[macro_use]
extern crate bitflags;
extern crate x86_64;
#[macro_use]
extern crate once;
extern crate bit_field;
#[macro_use]
extern crate lazy_static;

extern crate hole_list_allocator as allocator;
#[macro_use]
extern crate alloc;

#[macro_use]
mod vga_buffer;
mod memory;

mod interrupts;

pub const HEAP_START: usize = 0o_000_001_000_000_0000;
pub const HEAP_SIZE: usize = 100 * 1024; // 100 KiB

#[no_mangle]
pub extern "C" fn rust_main(multiboot_information_address: usize) {
    // ATTENTION: we have a very small stack and no guard page
    vga_buffer::clear_screen();
    println!("Hello World{}", "!");

    let boot_info = unsafe { multiboot2::load(multiboot_information_address) };
    enable_nxe_bit();
    enable_write_protect_bit();

    // set up guard page and map the heap pages
    let mut memory_controller = memory::init(boot_info);

    // initialize our IDT
    interrupts::init(&mut memory_controller);

    fn stack_overflow() {
        stack_overflow(); // for each recursion, the return address is pushed
    }

    // trigger a stack overflow
    stack_overflow();

    println!("It did not crash!");
    loop {}
}

fn enable_nxe_bit() {
    use x86_64::registers::msr::{IA32_EFER, rdmsr, wrmsr};

    let nxe_bit = 1 << 11;
    unsafe {
        let efer = rdmsr(IA32_EFER);
        wrmsr(IA32_EFER, efer | nxe_bit);
    }
}

fn enable_write_protect_bit() {
    use x86_64::registers::control_regs::{cr0, cr0_write, Cr0};

    unsafe { cr0_write(cr0() | Cr0::WRITE_PROTECT) };
}

#[cfg(not(test))]
#[lang = "eh_personality"]
extern "C" fn eh_personality() {}

#[cfg(not(test))]
#[lang = "panic_fmt"]
#[no_mangle]
pub extern "C" fn panic_fmt(fmt: core::fmt::Arguments, file: &'static str, line: u32) -> ! {
    println!("\n\nPANIC in {} at line {}:", file, line);
    println!("    {}", fmt);
    loop {}
}

#[allow(non_snake_case)]
#[no_mangle]
pub extern "C" fn _Unwind_Resume() -> ! {
    loop {}
}
<commit_msg>Fix eh_personality linker errors (#364)<commit_after>// Copyright 2016 Philipp Oppermann. See the README.md
// file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.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.

#![feature(lang_items)]
#![feature(const_fn, unique)]
#![feature(alloc)]
#![feature(asm)]
#![feature(naked_functions)]
#![feature(abi_x86_interrupt)]
#![feature(const_unique_new)]
#![no_std]

extern crate rlibc;
extern crate volatile;
extern crate spin;
extern crate multiboot2;
#[macro_use]
extern crate bitflags;
extern crate x86_64;
#[macro_use]
extern crate once;
extern crate bit_field;
#[macro_use]
extern crate lazy_static;

extern crate hole_list_allocator as allocator;
#[macro_use]
extern crate alloc;

#[macro_use]
mod vga_buffer;
mod memory;

mod interrupts;

pub const HEAP_START: usize = 0o_000_001_000_000_0000;
pub const HEAP_SIZE: usize = 100 * 1024; // 100 KiB

#[no_mangle]
pub extern "C" fn rust_main(multiboot_information_address: usize) {
    // ATTENTION: we have a very small stack and no guard page
    vga_buffer::clear_screen();
    println!("Hello World{}", "!");

    let boot_info = unsafe { multiboot2::load(multiboot_information_address) };
    enable_nxe_bit();
    enable_write_protect_bit();

    // set up guard page and map the heap pages
    let mut memory_controller = memory::init(boot_info);

    // initialize our IDT
    interrupts::init(&mut memory_controller);

    fn stack_overflow() {
        stack_overflow(); // for each recursion, the return address is pushed
    }

    // trigger a stack overflow
    stack_overflow();

    println!("It did not crash!");
    loop {}
}

fn enable_nxe_bit() {
    use x86_64::registers::msr::{IA32_EFER, rdmsr, wrmsr};

    let nxe_bit = 1 << 11;
    unsafe {
        let efer = rdmsr(IA32_EFER);
        wrmsr(IA32_EFER, efer | nxe_bit);
    }
}

fn enable_write_protect_bit() {
    use x86_64::registers::control_regs::{cr0, cr0_write, Cr0};

    unsafe { cr0_write(cr0() | Cr0::WRITE_PROTECT) };
}

#[cfg(not(test))]
#[lang = "eh_personality"]
#[no_mangle]
pub extern "C" fn eh_personality() {}

#[cfg(not(test))]
#[lang = "panic_fmt"]
#[no_mangle]
pub extern "C" fn panic_fmt(fmt: core::fmt::Arguments, file: &'static str, line: u32) -> ! {
    println!("\n\nPANIC in {} at line {}:", file, line);
    println!("    {}", fmt);
    loop {}
}

#[allow(non_snake_case)]
#[no_mangle]
pub extern "C" fn _Unwind_Resume() -> ! {
    loop {}
}
<|endoftext|>


<commit_before>#![feature(catch_panic)]
#[macro_use]
extern crate lazy_static;
use std::string::ToString;
use std::thread::{JoinHandle, spawn, catch_panic};
use std::sync::*;
use std::any::{Any};
use std::io::{self, Write};

pub struct ExampleGroup {
    description: String,
    running_examples: Vec<JoinHandle<Result<(), Box<Any + Send>>>>,
}

pub struct ExampleGroupAndBlock {
    group: ExampleGroup,
    block: Box<Fn(&mut ExampleGroup) + Sync + Send + 'static>,
}

pub struct Example {
    description: String,
}

impl ExampleGroup {
    pub fn it<F>(&mut self, description: &'static str, example_definition_block: F) where F: Fn() + Sync + Send + 'static {
        self.running_examples.push(spawn(move || {
            let result = catch_panic(move || {
                example_definition_block();
            });

            with_world(|world| {
                if result.is_err() {
                    world.reporter.example_failed();
                } else {
                    world.reporter.example_passed();
                }
            });

            return result;
        }));
    }

    fn block_on_all_examples(self) -> Result<(), ()> {
        let mut failed = false;
        for jh in self.running_examples.into_iter() {
            if jh.join().unwrap().is_err() {
                failed = true;
            }
        }

        if failed {
            return Err(());
        } else {
            return Ok(());
        }
    }

    fn run(mut self, block: Box<Fn(&mut ExampleGroup) + Send + Sync + 'static>) -> bool {
        block(&mut self);

        let result = self.block_on_all_examples();
        return result.is_ok();
    }
}

pub struct Reporter;

impl Reporter {
    pub fn example_failed(&self) {
        print!("F");
        io::stdout().flush();
    }

    pub fn example_passed(&self) {
        print!(".");
        io::stdout().flush();
    }
}

struct World {
    reporter: Reporter,
    failed: bool,
    example_groups: Vec<ExampleGroupAndBlock>,
}

fn with_world<F>(blk: F) where F: FnOnce(&mut World) -> () {
    let c = WORLD.clone();
    let mut guard = c.lock().unwrap();
    blk(&mut guard);
}

impl World {
}

lazy_static! {
    static ref WORLD: Arc<Mutex<World>> = Arc::new(Mutex::new(World { failed: false, reporter: Reporter, example_groups: Vec::new() }));
}

pub fn describe<F>(description: &str, example_group_definition_block: F) where F: Fn(&mut ExampleGroup) + Sync + Send + 'static {
    with_world(|world| {
        world.example_groups.push(
            ExampleGroupAndBlock {
                group: ExampleGroup {
                    description: description.to_string(),
                    running_examples: Vec::new(),
                },
                block: Box::new(example_group_definition_block)
            }
        );
    });
}

fn get_examples_from_world() -> Vec<ExampleGroupAndBlock> {
    let mut result = Vec::new();

    with_world(|world| {
        while !world.example_groups.is_empty() {
            result.push(world.example_groups.remove(0));
        }
    });

    return result;

}

pub fn descriptor_main() {
    let mut example_groups = get_examples_from_world();
    let mut join_handles = Vec::new();

    while !example_groups.is_empty() {
        let example_group_and_block = example_groups.remove(0);
        let example_group = example_group_and_block.group;
        let block = example_group_and_block.block;
        join_handles.push(spawn(|| -> Result<(), ()> {
            if example_group.run(block) {
                return Ok(());
            } else {
                return Err(());
            }
        }));
    }

    for join_handle in join_handles.into_iter() {
        let result = join_handle.join().unwrap();
        if result.is_err() {
            with_world(|world| {
                world.failed = true;
            });
        }
    }
    with_world(|world| {
        println!("{}", world.failed);
    });
}
<commit_msg>Make describe a method on world.<commit_after>#![feature(catch_panic)]
#[macro_use]
extern crate lazy_static;
use std::string::ToString;
use std::thread::{JoinHandle, spawn, catch_panic};
use std::sync::*;
use std::any::{Any};
use std::io::{self, Write};

pub struct ExampleGroup {
    description: String,
    running_examples: Vec<JoinHandle<Result<(), Box<Any + Send>>>>,
}

pub struct ExampleGroupAndBlock {
    group: ExampleGroup,
    block: Box<Fn(&mut ExampleGroup) + Sync + Send + 'static>,
}

pub struct Example {
    description: String,
}

impl ExampleGroup {
    pub fn it<F>(&mut self, description: &'static str, example_definition_block: F) where F: Fn() + Sync + Send + 'static {
        self.running_examples.push(spawn(move || {
            let result = catch_panic(move || {
                example_definition_block();
            });

            with_world(|world| {
                if result.is_err() {
                    world.reporter.example_failed();
                } else {
                    world.reporter.example_passed();
                }
            });

            return result;
        }));
    }

    fn block_on_all_examples(self) -> Result<(), ()> {
        let mut failed = false;
        for jh in self.running_examples.into_iter() {
            if jh.join().unwrap().is_err() {
                failed = true;
            }
        }

        if failed {
            return Err(());
        } else {
            return Ok(());
        }
    }

    fn run(mut self, block: Box<Fn(&mut ExampleGroup) + Send + Sync + 'static>) -> bool {
        block(&mut self);

        let result = self.block_on_all_examples();
        return result.is_ok();
    }
}

pub struct Reporter;

impl Reporter {
    pub fn example_failed(&self) {
        print!("F");
        io::stdout().flush();
    }

    pub fn example_passed(&self) {
        print!(".");
        io::stdout().flush();
    }
}

struct World {
    reporter: Reporter,
    failed: bool,
    example_groups: Vec<ExampleGroupAndBlock>,
}

fn with_world<F>(blk: F) where F: FnOnce(&mut World) -> () {
    let c = WORLD.clone();
    let mut guard = c.lock().unwrap();
    blk(&mut guard);
}

impl World {
    fn describe<F>(&mut self, description: &str, example_group_definition_block: F) where F: Fn(&mut ExampleGroup) + Sync + Send + 'static {
        self.example_groups.push(
            ExampleGroupAndBlock {
                group: ExampleGroup {
                    description: description.to_string(),
                    running_examples: Vec::new(),
                },
                block: Box::new(example_group_definition_block)
            }
        );
    }
}

lazy_static! {
    static ref WORLD: Arc<Mutex<World>> = Arc::new(Mutex::new(World { failed: false, reporter: Reporter, example_groups: Vec::new() }));
}

pub fn describe<F>(description: &str, example_group_definition_block: F) where F: Fn(&mut ExampleGroup) + Sync + Send + 'static {
    with_world(|world| {
        world.describe(description, example_group_definition_block);
    });
}

fn get_examples_from_world() -> Vec<ExampleGroupAndBlock> {
    let mut result = Vec::new();

    with_world(|world| {
        while !world.example_groups.is_empty() {
            result.push(world.example_groups.remove(0));
        }
    });

    return result;

}

pub fn descriptor_main() {
    let mut example_groups = get_examples_from_world();
    let mut join_handles = Vec::new();

    while !example_groups.is_empty() {
        let example_group_and_block = example_groups.remove(0);
        let example_group = example_group_and_block.group;
        let block = example_group_and_block.block;
        join_handles.push(spawn(|| -> Result<(), ()> {
            if example_group.run(block) {
                return Ok(());
            } else {
                return Err(());
            }
        }));
    }

    for join_handle in join_handles.into_iter() {
        let result = join_handle.join().unwrap();
        if result.is_err() {
            with_world(|world| {
                world.failed = true;
            });
        }
    }
    with_world(|world| {
        println!("{}", world.failed);
    });
}
<|endoftext|>


<commit_before>mod atom;
pub use atom::*;

mod molecule;
pub use molecule::*;

mod reaction;
pub use reaction::*;

pub mod namings;
pub mod atoms;
pub mod molecules;

#[test]
fn reaction_check() {
    use atoms::*;

    let sodium_molecule = &Molecule {
        compounds: &[ MoleculeCompound { atom: SODIUM, amount: 1 } ]
    };

    let chlorine_molecule = &Molecule {
        compounds: &[ MoleculeCompound { atom: CHLORINE, amount: 2 } ]
    };

    let lithium_molecule = &Molecule {
        compounds: &[ MoleculeCompound { atom: LITHIUM, amount: 1 } ]
    };

    let hydrogen_molecule = &Molecule {
        compounds: &[ MoleculeCompound { atom: HYDROGEN, amount: 2 } ]
    };

    let salt_molecule = &Molecule {
        compounds: &[
            MoleculeCompound { atom: CHLORINE, amount: 1 },
            MoleculeCompound { atom: SODIUM, amount: 1 }
        ]
    };

    let good_reaction = Reaction {
        lefthandside: &ReactionSide {
            compounds: &[
                ReactionCompound { amount: 2, molecule: sodium_molecule },
                ReactionCompound { amount: 1, molecule: chlorine_molecule }
            ]
        },

        righthandside: &ReactionSide {
            compounds: &[  ReactionCompound { amount: 2, molecule: salt_molecule }  ]
        }
    };

    let wrong_reaction_0 = Reaction {
        lefthandside: &ReactionSide {
            compounds: &[
                ReactionCompound { amount: 9, molecule: sodium_molecule },
                ReactionCompound { amount: 5, molecule: chlorine_molecule }
            ]
        },

        righthandside: &ReactionSide {
            compounds: &[  ReactionCompound { amount: 3, molecule: salt_molecule }  ]
        }
    };

    let wrong_reaction_1 = Reaction {
        lefthandside: &ReactionSide {
            compounds: &[
                ReactionCompound { amount: 1, molecule: lithium_molecule }
            ]
        },

        righthandside: &ReactionSide {
            compounds: &[
                ReactionCompound { amount: 3, molecule: hydrogen_molecule }
            ]
        }
    };

    assert!(good_reaction.check_sides_equal());
    assert!(! wrong_reaction_0.check_sides_equal());
    assert!(! wrong_reaction_1.check_sides_equal());
}

#[test]
fn atoms_database_correct() {
    use atoms::*;

    assert_eq!(1, HYDROGEN.number);
    assert_eq!("oxygen", OXYGEN.name);
    assert_eq!("He", HELIUM.symbol);
    assert_eq!(35.45, CHLORINE.mass);

    assert!(HYDROGEN.is_diatomic);
    assert!(OXYGEN.is_diatomic);
    assert!(! CARBON.is_diatomic);
    assert!(! SULFUR.is_diatomic);

    assert_eq!("aluminium", atoms::ALUMINIUM.name);
}

#[test]
fn molecule_mass_calculation() {
    use atoms::*;
    use molecules::*;

    let sugar = Molecule {
        compounds: &[
            MoleculeCompound { atom: CARBON, amount: 12 },
            MoleculeCompound { atom: HYDROGEN, amount: 22 },
            MoleculeCompound { atom: OXYGEN, amount: 11 }
        ]
    };

    assert_eq!(18.015, WATER.mass());
    assert_eq!(342.297, sugar.mass());
}

#[test]
fn greek_namings() {
    use namings::number_to_greek as to_greek;

    assert_eq!("di", to_greek(2));
    assert_eq!("undeca", to_greek(11));
    assert_eq!("dodeca", to_greek(12));
    assert_eq!("tetradeca", to_greek(14));
    assert_eq!("icosa", to_greek(20));
    assert_eq!("henicosa", to_greek(21));
    assert_eq!("tricosa", to_greek(23));
    assert_eq!("triaconta", to_greek(30));
    assert_eq!("pentatriaconta", to_greek(35));
    assert_eq!("pentaconta", to_greek(50));
    assert_eq!("dohexaconta", to_greek(62));
    assert_eq!("nonanonaconta", to_greek(99));
}

#[test]
fn roman_namings() {
    use namings::number_to_roman as to_roman;

    assert_eq!("0", to_roman(0));
    assert_eq!("IV", to_roman(4));
    assert_eq!("-III", to_roman(-3));
    assert_eq!("VII", to_roman(7));
    assert_eq!("-VII", to_roman(-7));
    assert_eq!("XI", to_roman(11));
    assert_eq!("XIV", to_roman(14));
    assert_eq!("-XVI", to_roman(-16));
}

#[test]
#[should_panic]
fn panic_case_0() {
    namings::number_to_greek(250);
}
<commit_msg>Added diatomic tests<commit_after>mod atom;
pub use atom::*;

mod molecule;
pub use molecule::*;

mod reaction;
pub use reaction::*;

pub mod namings;
pub mod atoms;
pub mod molecules;

macro_rules! molecule_from_atom {
    ($atom:expr) => (
        Molecule { compounds: &[ MoleculeCompound::from_atom($atom) ] }
    )
}

#[test]
fn diatomic_check() {
    use atoms::*;

    assert_eq!(2, MoleculeCompound::from_atom(HYDROGEN).amount);
    assert_eq!(2, MoleculeCompound::from_atom(NITROGEN).amount);
    assert_eq!(2, MoleculeCompound::from_atom(OXYGEN).amount);
    assert_eq!(2, MoleculeCompound::from_atom(FLUORINE).amount);
    assert_eq!(2, MoleculeCompound::from_atom(CHLORINE).amount);
    assert_eq!(2, MoleculeCompound::from_atom(BROMINE).amount);
    assert_eq!(2, MoleculeCompound::from_atom(IODINE).amount);
    assert_eq!(1, MoleculeCompound::from_atom(CARBON).amount);
    assert_eq!(1, MoleculeCompound::from_atom(LITHIUM).amount);
}

#[test]
fn reaction_check() {
    use atoms::*;

    let sodium_molecule = &Molecule {
        compounds: &[ MoleculeCompound { atom: SODIUM, amount: 1 } ]
    };

    let chlorine_molecule = &Molecule {
        compounds: &[ MoleculeCompound { atom: CHLORINE, amount: 2 } ]
    };

    let lithium_molecule = &Molecule {
        compounds: &[ MoleculeCompound { atom: LITHIUM, amount: 1 } ]
    };

    let hydrogen_molecule = &Molecule {
        compounds: &[ MoleculeCompound { atom: HYDROGEN, amount: 2 } ]
    };

    let salt_molecule = &Molecule {
        compounds: &[
            MoleculeCompound { atom: CHLORINE, amount: 1 },
            MoleculeCompound { atom: SODIUM, amount: 1 }
        ]
    };

    let good_reaction = Reaction {
        lefthandside: &ReactionSide {
            compounds: &[
                ReactionCompound { amount: 2, molecule: sodium_molecule },
                ReactionCompound { amount: 1, molecule: chlorine_molecule }
            ]
        },

        righthandside: &ReactionSide {
            compounds: &[  ReactionCompound { amount: 2, molecule: salt_molecule }  ]
        }
    };

    let wrong_reaction_0 = Reaction {
        lefthandside: &ReactionSide {
            compounds: &[
                ReactionCompound { amount: 9, molecule: sodium_molecule },
                ReactionCompound { amount: 5, molecule: chlorine_molecule }
            ]
        },

        righthandside: &ReactionSide {
            compounds: &[  ReactionCompound { amount: 3, molecule: salt_molecule }  ]
        }
    };

    let wrong_reaction_1 = Reaction {
        lefthandside: &ReactionSide {
            compounds: &[
                ReactionCompound { amount: 1, molecule: lithium_molecule }
            ]
        },

        righthandside: &ReactionSide {
            compounds: &[
                ReactionCompound { amount: 3, molecule: hydrogen_molecule }
            ]
        }
    };

    assert!(good_reaction.check_sides_equal());
    assert!(! wrong_reaction_0.check_sides_equal());
    assert!(! wrong_reaction_1.check_sides_equal());
}

#[test]
fn atoms_database_correct() {
    use atoms::*;

    assert_eq!(1, HYDROGEN.number);
    assert_eq!("oxygen", OXYGEN.name);
    assert_eq!("He", HELIUM.symbol);
    assert_eq!(35.45, CHLORINE.mass);

    assert!(HYDROGEN.is_diatomic);
    assert!(OXYGEN.is_diatomic);
    assert!(! CARBON.is_diatomic);
    assert!(! SULFUR.is_diatomic);

    assert_eq!("aluminium", atoms::ALUMINIUM.name);
}

#[test]
fn molecule_mass_calculation() {
    use atoms::*;
    use molecules::*;

    let sugar = Molecule {
        compounds: &[
            MoleculeCompound { atom: CARBON, amount: 12 },
            MoleculeCompound { atom: HYDROGEN, amount: 22 },
            MoleculeCompound { atom: OXYGEN, amount: 11 }
        ]
    };

    assert_eq!(18.015, WATER.mass());
    assert_eq!(342.297, sugar.mass());
}

#[test]
fn greek_namings() {
    use namings::number_to_greek as to_greek;

    assert_eq!("di", to_greek(2));
    assert_eq!("undeca", to_greek(11));
    assert_eq!("dodeca", to_greek(12));
    assert_eq!("tetradeca", to_greek(14));
    assert_eq!("icosa", to_greek(20));
    assert_eq!("henicosa", to_greek(21));
    assert_eq!("tricosa", to_greek(23));
    assert_eq!("triaconta", to_greek(30));
    assert_eq!("pentatriaconta", to_greek(35));
    assert_eq!("pentaconta", to_greek(50));
    assert_eq!("dohexaconta", to_greek(62));
    assert_eq!("nonanonaconta", to_greek(99));
}

#[test]
fn roman_namings() {
    use namings::number_to_roman as to_roman;

    assert_eq!("0", to_roman(0));
    assert_eq!("IV", to_roman(4));
    assert_eq!("-III", to_roman(-3));
    assert_eq!("VII", to_roman(7));
    assert_eq!("-VII", to_roman(-7));
    assert_eq!("XI", to_roman(11));
    assert_eq!("XIV", to_roman(14));
    assert_eq!("-XVI", to_roman(-16));
}

#[test]
#[should_panic]
fn panic_case_0() {
    namings::number_to_greek(250);
}
<|endoftext|>


<commit_before>//! Temporarily redirect stdout/stderr.
//!
//! For example, one can temporarily throw away stdout output:
//!
//! ```
//! use gag::Gag;
//! println!("Hello world!");
//! {
//!     let print_gag = Gag::stdout().unwrap();
//!     println!("No one will see this!");
//!     println!("Or this!");
//! }
//! println!("But they will see this!");
//! ```
//!
//! You can also temporarily un-gag by dropping the gag:
//!
//! ```
//! use gag::Gag;
//! let mut print_gag = Gag::stdout().unwrap();
//! println!("No one will see this!");
//! if true {
//!     drop(print_gag);
//!     println!("They will see this...");
//!     print_gag = Gag::stdout().unwrap();
//!     println!("Not this...");
//! }
//! println!("Nor this.");
//! ```
//!
//! If you don't want to throw away stdout, you can write it to a file:
//!
//! ```
//! #![feature(io)]
//! use std::fs::OpenOptions;
//! use std::io::{Read, Write, Seek, SeekFrom};
//! use gag::Redirect;
//!
//! println!("Displayed");
//!
//! // Open a log
//! let log = OpenOptions::new()
//!     .truncate(true)
//!     .read(true)
//!     .create(true)
//!     .write(true)
//!     .open("/tmp/my_log.log")
//!     .unwrap();
//!
//! let print_redirect = Redirect::stdout(log).unwrap();
//! println!("Hidden");
//!
//! // Extract redirect
//! let mut log = print_redirect.into_inner();
//! println!("Displayed");
//!
//! let mut buf = String::new();
//! log.seek(SeekFrom::Start(0)).unwrap();
//! log.read_to_string(&mut buf).unwrap();
//! assert_eq!(&buf[..], "Hidden\n");
//!
//! ```
//!
//! Alternatively, you can buffer stdout in-memory (requires linux 3.11 or later):
//!
//! ```
//! use std::io::Read;
//! use gag::BufferRedirect;
//!
//! let mut buf = BufferRedirect::stdout().unwrap();
//! println!("Hello world!");
//!
//! let mut output = String::new();
//! buf.read_to_string(&mut output).unwrap();
//!
//! assert_eq!(&output[..], "Hello world!\n");
//! ```
#![feature(unsafe_destructor, io_ext)]
extern crate libc;
extern crate tempdir;

mod redirect;
mod gag;
mod buffer;
mod tempfile;

pub use gag::Gag;
pub use redirect::Redirect;
pub use buffer::{BufferRedirect, Buffer};
<commit_msg>Note that buffering works on all platforms.<commit_after>//! Temporarily redirect stdout/stderr.
//!
//! For example, one can temporarily throw away stdout output:
//!
//! ```
//! use gag::Gag;
//! println!("Hello world!");
//! {
//!     let print_gag = Gag::stdout().unwrap();
//!     println!("No one will see this!");
//!     println!("Or this!");
//! }
//! println!("But they will see this!");
//! ```
//!
//! You can also temporarily un-gag by dropping the gag:
//!
//! ```
//! use gag::Gag;
//! let mut print_gag = Gag::stdout().unwrap();
//! println!("No one will see this!");
//! if true {
//!     drop(print_gag);
//!     println!("They will see this...");
//!     print_gag = Gag::stdout().unwrap();
//!     println!("Not this...");
//! }
//! println!("Nor this.");
//! ```
//!
//! If you don't want to throw away stdout, you can write it to a file:
//!
//! ```
//! #![feature(io)]
//! use std::fs::OpenOptions;
//! use std::io::{Read, Write, Seek, SeekFrom};
//! use gag::Redirect;
//!
//! println!("Displayed");
//!
//! // Open a log
//! let log = OpenOptions::new()
//!     .truncate(true)
//!     .read(true)
//!     .create(true)
//!     .write(true)
//!     .open("/tmp/my_log.log")
//!     .unwrap();
//!
//! let print_redirect = Redirect::stdout(log).unwrap();
//! println!("Hidden");
//!
//! // Extract redirect
//! let mut log = print_redirect.into_inner();
//! println!("Displayed");
//!
//! let mut buf = String::new();
//! log.seek(SeekFrom::Start(0)).unwrap();
//! log.read_to_string(&mut buf).unwrap();
//! assert_eq!(&buf[..], "Hidden\n");
//!
//! ```
//!
//! Alternatively, you can buffer stdout to a temporary file. On linux 3.11+, this file is
//! guarenteed to be stored in-memory.
//!
//! ```
//! use std::io::Read;
//! use gag::BufferRedirect;
//!
//! let mut buf = BufferRedirect::stdout().unwrap();
//! println!("Hello world!");
//!
//! let mut output = String::new();
//! buf.read_to_string(&mut output).unwrap();
//!
//! assert_eq!(&output[..], "Hello world!\n");
//! ```
#![feature(unsafe_destructor, io_ext)]
extern crate libc;
extern crate tempdir;

mod redirect;
mod gag;
mod buffer;
mod tempfile;

pub use gag::Gag;
pub use redirect::Redirect;
pub use buffer::{BufferRedirect, Buffer};
<|endoftext|>


<commit_before>
extern crate ndarray;
extern crate num;

use ndarray::prelude::*;

#[inline(always)]
pub fn lorenz63(p: f64, b: f64, r: f64, mut v: Array<f64, Ix>) -> Array<f64, Ix> {
    let x = v[0];
    let y = v[1];
    let z = v[2];
    v[0] = p * (y - x);
    v[1] = x * (r - z) - y;
    v[2] = x * y - b * z;
    v
}

pub fn euler<TEO, D: Dimension>(u: &TEO, dt: f64, x: Array<f64, D>) -> Array<f64, D>
    where TEO: Fn(Array<f64, D>) -> Array<f64, D>
{
    let y = x.clone();
    x + dt * u(y)
}

pub fn rk4<TEO, D: Dimension>(u: &TEO, dt: f64, x: Array<f64, D>) -> Array<f64, D>
    where TEO: Fn(Array<f64, D>) -> Array<f64, D>
{
    let mut l = x.clone();
    l = u(l);
    let k1 = l.clone();
    l = (0.5 * dt) * l + &x;
    l = u(l);
    let k2 = l.clone();
    l = (0.5 * dt) * l + &x;
    l = u(l);
    let k3 = l.clone();
    l = dt * l + &x;
    l = u(l);
    x + dt * (k1 + 2.0 * (k2 + k3) + l) / 6.0
}
<commit_msg>Add Roessler system<commit_after>
extern crate ndarray;
extern crate num;

use ndarray::prelude::*;

#[inline(always)]
pub fn lorenz63(p: f64, b: f64, r: f64, mut v: Array<f64, Ix>) -> Array<f64, Ix> {
    let x = v[0];
    let y = v[1];
    let z = v[2];
    v[0] = p * (y - x);
    v[1] = x * (r - z) - y;
    v[2] = x * y - b * z;
    v
}

#[inline(always)]
pub fn roessler(a: f64, b: f64, c: f64, mut v: Array<f64, Ix>) -> Array<f64, Ix> {
    let x = v[0];
    let y = v[1];
    let z = v[2];
    v[0] = -y - z;
    v[1] = x + a * y;
    v[2] = b + x * z - c * z;
    v
}

pub fn euler<TEO, D: Dimension>(u: &TEO, dt: f64, x: Array<f64, D>) -> Array<f64, D>
    where TEO: Fn(Array<f64, D>) -> Array<f64, D>
{
    let y = x.clone();
    x + dt * u(y)
}

pub fn rk4<TEO, D: Dimension>(u: &TEO, dt: f64, x: Array<f64, D>) -> Array<f64, D>
    where TEO: Fn(Array<f64, D>) -> Array<f64, D>
{
    let mut l = x.clone();
    l = u(l);
    let k1 = l.clone();
    l = (0.5 * dt) * l + &x;
    l = u(l);
    let k2 = l.clone();
    l = (0.5 * dt) * l + &x;
    l = u(l);
    let k3 = l.clone();
    l = dt * l + &x;
    l = u(l);
    x + dt * (k1 + 2.0 * (k2 + k3) + l) / 6.0
}
<|endoftext|>


<commit_before>#![feature(core, std_misc)]
//! URL Encoded Plugin for Iron.
//!
//! Parses "url encoded" data from client requests.
//! Capable of parsing both URL query strings and POST request bodies.

extern crate iron;
extern crate bodyparser;
extern crate url;
extern crate plugin;

use iron::prelude::*;
use iron::typemap::Key;

use plugin::Pluggable;

use url::form_urlencoded;
use std::collections::HashMap;
use std::collections::hash_map::Entry::*;
use std::fmt;
use std::error::Error as StdError;

/// Plugin for `Request` that extracts URL encoded data from the URL query string.
///
/// Use it like this: `req.get_ref::<UrlEncodedQuery>()`
pub struct UrlEncodedQuery;

/// Plugin for `Request` that extracts URL encoded data from the request body.
///
/// Use it like this: `req.get_ref::<UrlEncodedBody>()`
pub struct UrlEncodedBody;

/// An error representing the two possible errors that can occur during URL decoding.
///
/// The first and probably most common one is for the query to be empty,
/// and that goes for both body and url queries.
///
/// The second type of error that can occur is that something goes wrong
/// when parsing the request body.
#[derive(Clone, Debug)]
pub enum UrlDecodingError{
    /// An error parsing the request body
    BodyError(bodyparser::BodyError),
    /// An empty query string, either in body or url query
    EmptyQuery
}
pub use UrlDecodingError::*;

impl fmt::Display for UrlDecodingError {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        self.description().fmt(f)
    }
}

impl StdError for UrlDecodingError {
    fn description(&self) -> &str {
        match *self {
            BodyError(ref err) => err.description(),
            EmptyQuery => "Expected query, found empty string."
        }
    }

    fn cause(&self) -> Option<&StdError> {
        match *self {
            BodyError(ref err) => Some(err),
            _ => None
        }
    }
}

/// Hashmap mapping strings to vectors of strings.
pub type QueryMap = HashMap<String, Vec<String>>;
/// Result type for decoding query parameters.
pub type QueryResult = Result<QueryMap, UrlDecodingError>;

impl Key for UrlEncodedBody {
    type Value = QueryMap;
}
impl Key for UrlEncodedQuery {
    type Value = QueryMap;
}

impl<'a> plugin::Plugin<Request<'a>> for UrlEncodedQuery {
    type Error = UrlDecodingError;

    fn eval(req: &mut Request) -> QueryResult {
        match req.url.query {
            Some(ref query) => create_param_hashmap(&query),
            None => Err(UrlDecodingError::EmptyQuery)
        }
    }
}

impl<'a> plugin::Plugin<Request<'a>> for UrlEncodedBody {
    type Error = UrlDecodingError;

    fn eval(req: &mut Request) -> QueryResult {
        req.get::<bodyparser::Raw>()
            .map(|x| x.unwrap_or("".to_string()))
            .map_err(|e| UrlDecodingError::BodyError(e))
            .and_then(|x| create_param_hashmap(&x))
    }
}

/// Parse a urlencoded string into an optional HashMap.
fn create_param_hashmap(data: &str) -> QueryResult {
    match data {
        "" => Err(UrlDecodingError::EmptyQuery),
        _ => Ok(combine_duplicates(form_urlencoded::parse(data.as_bytes())))
    }
}

/// Convert a list of (key, value) pairs into a hashmap with vector values.
fn combine_duplicates(q: Vec<(String, String)>) -> QueryMap {
    let mut deduplicated: QueryMap = HashMap::new();

    for (k, v) in q.into_iter() {
        match deduplicated.entry(k) {
            // Already a Vec here, push onto it
            Occupied(entry) => { entry.into_mut().push(v); },

            // No value, create a one-element Vec.
            Vacant(entry) => { entry.insert(vec![v]); },
        };
    }

    deduplicated
}

#[test]
fn test_combine_duplicates() {
    let my_vec = vec![("band".to_string(), "arctic monkeys".to_string()),
                      ("band".to_string(), "temper trap".to_string()),
                      ("color".to_string(),"green".to_string())];
    let answer = combine_duplicates(my_vec);
    let mut control = HashMap::new();
    control.insert("band".to_string(),
                   vec!["arctic monkeys".to_string(), "temper trap".to_string()]);
    control.insert("color".to_string(), vec!["green".to_string()]);
    assert_eq!(answer, control);
}
<commit_msg>(fix) Add second lifetime param to Request. Changes in Hyper propagated to Iron making this change necessary. See iron/iron@942159f017fe6b8fb23cad3736ef4cad0b7f659a for details.<commit_after>#![feature(core, std_misc)]
//! URL Encoded Plugin for Iron.
//!
//! Parses "url encoded" data from client requests.
//! Capable of parsing both URL query strings and POST request bodies.

extern crate iron;
extern crate bodyparser;
extern crate url;
extern crate plugin;

use iron::prelude::*;
use iron::typemap::Key;

use plugin::Pluggable;

use url::form_urlencoded;
use std::collections::HashMap;
use std::collections::hash_map::Entry::*;
use std::fmt;
use std::error::Error as StdError;

/// Plugin for `Request` that extracts URL encoded data from the URL query string.
///
/// Use it like this: `req.get_ref::<UrlEncodedQuery>()`
pub struct UrlEncodedQuery;

/// Plugin for `Request` that extracts URL encoded data from the request body.
///
/// Use it like this: `req.get_ref::<UrlEncodedBody>()`
pub struct UrlEncodedBody;

/// An error representing the two possible errors that can occur during URL decoding.
///
/// The first and probably most common one is for the query to be empty,
/// and that goes for both body and url queries.
///
/// The second type of error that can occur is that something goes wrong
/// when parsing the request body.
#[derive(Clone, Debug)]
pub enum UrlDecodingError{
    /// An error parsing the request body
    BodyError(bodyparser::BodyError),
    /// An empty query string, either in body or url query
    EmptyQuery
}
pub use UrlDecodingError::*;

impl fmt::Display for UrlDecodingError {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        self.description().fmt(f)
    }
}

impl StdError for UrlDecodingError {
    fn description(&self) -> &str {
        match *self {
            BodyError(ref err) => err.description(),
            EmptyQuery => "Expected query, found empty string."
        }
    }

    fn cause(&self) -> Option<&StdError> {
        match *self {
            BodyError(ref err) => Some(err),
            _ => None
        }
    }
}

/// Hashmap mapping strings to vectors of strings.
pub type QueryMap = HashMap<String, Vec<String>>;
/// Result type for decoding query parameters.
pub type QueryResult = Result<QueryMap, UrlDecodingError>;

impl Key for UrlEncodedBody {
    type Value = QueryMap;
}
impl Key for UrlEncodedQuery {
    type Value = QueryMap;
}

impl<'a, 'b> plugin::Plugin<Request<'a, 'b>> for UrlEncodedQuery {
    type Error = UrlDecodingError;

    fn eval(req: &mut Request) -> QueryResult {
        match req.url.query {
            Some(ref query) => create_param_hashmap(&query),
            None => Err(UrlDecodingError::EmptyQuery)
        }
    }
}

impl<'a, 'b> plugin::Plugin<Request<'a, 'b>> for UrlEncodedBody {
    type Error = UrlDecodingError;

    fn eval(req: &mut Request) -> QueryResult {
        req.get::<bodyparser::Raw>()
            .map(|x| x.unwrap_or("".to_string()))
            .map_err(|e| UrlDecodingError::BodyError(e))
            .and_then(|x| create_param_hashmap(&x))
    }
}

/// Parse a urlencoded string into an optional HashMap.
fn create_param_hashmap(data: &str) -> QueryResult {
    match data {
        "" => Err(UrlDecodingError::EmptyQuery),
        _ => Ok(combine_duplicates(form_urlencoded::parse(data.as_bytes())))
    }
}

/// Convert a list of (key, value) pairs into a hashmap with vector values.
fn combine_duplicates(q: Vec<(String, String)>) -> QueryMap {
    let mut deduplicated: QueryMap = HashMap::new();

    for (k, v) in q.into_iter() {
        match deduplicated.entry(k) {
            // Already a Vec here, push onto it
            Occupied(entry) => { entry.into_mut().push(v); },

            // No value, create a one-element Vec.
            Vacant(entry) => { entry.insert(vec![v]); },
        };
    }

    deduplicated
}

#[test]
fn test_combine_duplicates() {
    let my_vec = vec![("band".to_string(), "arctic monkeys".to_string()),
                      ("band".to_string(), "temper trap".to_string()),
                      ("color".to_string(),"green".to_string())];
    let answer = combine_duplicates(my_vec);
    let mut control = HashMap::new();
    control.insert("band".to_string(),
                   vec!["arctic monkeys".to_string(), "temper trap".to_string()]);
    control.insert("color".to_string(), vec!["green".to_string()]);
    assert_eq!(answer, control);
}
<|endoftext|>


<commit_before>#![feature(libc)]

#[allow(dead_code)]
#[allow(non_camel_case_types)]

extern crate libc;
use libc::c_int;

/**
 * Abstraction of libnl core functionality
 */
#[link(name="nl-3")]
extern "C" {
	// Exposed socket functions
	fn nl_socket_alloc() -> *const nl_sock;
	fn nl_socket_free(socket: *const nl_sock);
	fn nl_socket_get_fd(socket: *const nl_sock) -> i32;
	fn nl_socket_set_buffer_size(socket: *const nl_sock, rxbuf: c_int, txbuf: c_int) -> i32;

	fn nl_socket_set_local_port(socket: *const nl_sock, port: u32);
	fn nl_socket_get_local_port(socket: *const nl_sock) -> u32;

	fn nl_connect(socket: *const nl_sock, protocol: u32) -> i32;
	fn nl_close(socket: *const nl_sock);

	fn nl_socket_set_cb(socket: *const nl_sock, cb: *const nl_cb);
	fn nl_socket_get_cb(socket: *const nl_sock) -> nl_cb;

	// Exposed socket transceiver
	fn nl_send_simple(socket: *const nl_sock, msg_type: c_int, flags: c_int, buf: *const u8, size: c_int) -> i32;
	// Exposed msg functions
	fn nlmsg_alloc() -> *const nl_msg;
	fn nlmsg_free(msg: *const nl_msg);

}

// exposed structures - these are wrapped
struct nl_sock;
struct nl_msg;
struct nl_cb;

// RSNL datatypes wrapping the libnl data structures
pub struct socket {
	ptr: *const nl_sock
}

/* library version of nlmsghdr
 * the name is altered to differentiate
 * between the native libnl and rsnl
 */
pub struct rsnl_msghdr {
	nlmsg_len: u32,
	nlmsg_type: u16,
	nlmsg_flags: u16,
	nlmsg_seq: u32,
	nlmsg_pid: u32
}

pub struct msg {
	ptr: *const nl_msg
}

pub enum NetlinkProtocol {
	route,
	unused,
	usersock,
	firewall,
	sock_diag,
	nflog,
	xfrm,
	selinux,
	iscsi,
	audit,
	fib_lookup,
	connector,
	netfilter,
	ip6_fw,
	dnrtmsg,
	kobject_uevent,
	DMEVENTS,
	scsitransport,
	ecryptfs,
	rdma,
	crypto,
	zu= 30
}

impl socket {
	pub fn new() -> socket {
		unsafe {
			let nlptr = nl_socket_alloc();
			socket {
				ptr: nlptr
			}
		}
	}

	pub fn free(&self) {
		unsafe {
			nl_socket_free(self.ptr)
		}
	}

	pub fn set_buffer_size(&self, rxbuf: c_int, txbuf: c_int) -> i32 {
		unsafe {
			nl_socket_set_buffer_size(self.ptr, rxbuf, txbuf)
		}
	}

	pub fn connect(&self, protocol: NetlinkProtocol) -> i32 {
		unsafe { nl_connect(self.ptr, protocol as u32) }
	}

	pub fn close(&self) {
		unsafe{ nl_close(self.ptr) }
	}

	pub fn get_fd(&self) -> i32 {
		unsafe { nl_socket_get_fd(self.ptr) }
	}

	pub fn get_local_port(&self) -> u32 {
		unsafe { nl_socket_get_local_port(self.ptr) }
	}

	pub fn set_local_port(&self, port: u32) {
		unsafe { nl_socket_set_local_port(self.ptr, port) }
	}

	pub fn send_simple(&self, msg_type: c_int, flags: c_int, buf: *const u8, size: c_int) -> c_int {
		unsafe { nl_send_simple(self.ptr, msg_type, flags, buf, size) }
	}
}

impl msg {
	pub fn new() -> msg {
	unsafe {
		let nlmsg = nlmsg_alloc();
		msg {
			ptr: nlmsg
		}
	}
	}

	pub fn free(&self) {
		unsafe{ nlmsg_free(self.ptr); }
	}
}
<commit_msg>Actually enable dead-code and non_camel_case warning suppressions<commit_after>#![feature(libc)]

#![allow(dead_code)]
#![allow(non_camel_case_types)]

extern crate libc;
use libc::c_int;

/**
 * Abstraction of libnl core functionality
 */
#[link(name="nl-3")]
extern "C" {
	// Exposed socket functions
	fn nl_socket_alloc() -> *const nl_sock;
	fn nl_socket_free(socket: *const nl_sock);
	fn nl_socket_get_fd(socket: *const nl_sock) -> i32;
	fn nl_socket_set_buffer_size(socket: *const nl_sock, rxbuf: c_int, txbuf: c_int) -> i32;

	fn nl_socket_set_local_port(socket: *const nl_sock, port: u32);
	fn nl_socket_get_local_port(socket: *const nl_sock) -> u32;

	fn nl_connect(socket: *const nl_sock, protocol: u32) -> i32;
	fn nl_close(socket: *const nl_sock);

	fn nl_socket_set_cb(socket: *const nl_sock, cb: *const nl_cb);
	fn nl_socket_get_cb(socket: *const nl_sock) -> nl_cb;

	// Exposed socket transceiver
	fn nl_send_simple(socket: *const nl_sock, msg_type: c_int, flags: c_int, buf: *const u8, size: c_int) -> i32;
	// Exposed msg functions
	fn nlmsg_alloc() -> *const nl_msg;
	fn nlmsg_free(msg: *const nl_msg);

}

// exposed structures - these are wrapped
struct nl_sock;
struct nl_msg;
struct nl_cb;

// RSNL datatypes wrapping the libnl data structures
pub struct socket {
	ptr: *const nl_sock
}

/* library version of nlmsghdr
 * the name is altered to differentiate
 * between the native libnl and rsnl
 */
pub struct rsnl_msghdr {
	nlmsg_len: u32,
	nlmsg_type: u16,
	nlmsg_flags: u16,
	nlmsg_seq: u32,
	nlmsg_pid: u32
}

pub struct msg {
	ptr: *const nl_msg
}

pub enum NetlinkProtocol {
	route,
	unused,
	usersock,
	firewall,
	sock_diag,
	nflog,
	xfrm,
	selinux,
	iscsi,
	audit,
	fib_lookup,
	connector,
	netfilter,
	ip6_fw,
	dnrtmsg,
	kobject_uevent,
	DMEVENTS,
	scsitransport,
	ecryptfs,
	rdma,
	crypto,
	zu= 30
}

impl socket {
	pub fn new() -> socket {
		unsafe {
			let nlptr = nl_socket_alloc();
			socket {
				ptr: nlptr
			}
		}
	}

	pub fn free(&self) {
		unsafe {
			nl_socket_free(self.ptr)
		}
	}

	pub fn set_buffer_size(&self, rxbuf: c_int, txbuf: c_int) -> i32 {
		unsafe {
			nl_socket_set_buffer_size(self.ptr, rxbuf, txbuf)
		}
	}

	pub fn connect(&self, protocol: NetlinkProtocol) -> i32 {
		unsafe { nl_connect(self.ptr, protocol as u32) }
	}

	pub fn close(&self) {
		unsafe{ nl_close(self.ptr) }
	}

	pub fn get_fd(&self) -> i32 {
		unsafe { nl_socket_get_fd(self.ptr) }
	}

	pub fn get_local_port(&self) -> u32 {
		unsafe { nl_socket_get_local_port(self.ptr) }
	}

	pub fn set_local_port(&self, port: u32) {
		unsafe { nl_socket_set_local_port(self.ptr, port) }
	}

	pub fn send_simple(&self, msg_type: c_int, flags: c_int, buf: *const u8, size: c_int) -> c_int {
		unsafe { nl_send_simple(self.ptr, msg_type, flags, buf, size) }
	}
}

impl msg {
	pub fn new() -> msg {
	unsafe {
		let nlmsg = nlmsg_alloc();
		msg {
			ptr: nlmsg
		}
	}
	}

	pub fn free(&self) {
		unsafe{ nlmsg_free(self.ptr); }
	}
}
<|endoftext|>