<commit_before>extern crate graphics;

use graphics::{ Context, Graphics };

pub struct Timeline {
    pub frames: u32,
    pub current_frame: u32,
    pub bounds: [u32; 4],
}

impl Timeline {
    pub fn new_frames_bounds(frames: u32, bounds: [u32; 4]) -> Timeline {
        Timeline {
            frames: frames,
            current_frame: 0,
            bounds: bounds,
        }
    }

    pub fn draw_timeline<G: Graphics>(&self, c: &Context, g: &mut G) {
        // Draw bounds to see where the control is.
        {
            use graphics::Rectangle;

            let bounds = [
                    self.bounds[0] as f64,
                    self.bounds[1] as f64,
                    self.bounds[2] as f64,
                    self.bounds[3] as f64
                ];
            Rectangle::new_border([0.0, 0.0, 1.0, 1.0], 0.5)
                .draw(bounds, &c.draw_state, c.transform, g);
        }

    }

    pub fn draw_drag<G: Graphics>(&self, c: &Context, g: &mut G) {

    }
}
<commit_msg>Draw sequence of squares<commit_after>extern crate graphics;

use graphics::{ Context, Graphics };

pub struct Timeline {
    pub frames: u32,
    pub current_frame: u32,
    pub bounds: [u32; 4],
}

impl Timeline {
    pub fn new_frames_bounds(frames: u32, bounds: [u32; 4]) -> Timeline {
        Timeline {
            frames: frames,
            current_frame: 0,
            bounds: bounds,
        }
    }

    pub fn draw_timeline<G: Graphics>(&self, c: &Context, g: &mut G) {
        let left_to_frame: f64 = 5.0;
        let top_to_frame: f64 = 10.0;
        let frame_width: f64 = 10.0;
        let frame_height: f64 = 10.0;
        let frame_offset_x: f64 = 5.0;

        // Draw bounds to see where the control is.
        {
            use graphics::Rectangle;

            let bounds = [
                    self.bounds[0] as f64,
                    self.bounds[1] as f64,
                    self.bounds[2] as f64,
                    self.bounds[3] as f64
                ];
            Rectangle::new_border([0.0, 0.0, 1.0, 1.0], 0.5)
                .draw(bounds, &c.draw_state, c.transform, g);
        }

        // Draw a sequence of squares for each frame.
        {
            use graphics::Rectangle;

            let rect = Rectangle::new_border([0.0, 0.0, 1.0, 1.0], 0.5);
            for i in 0..self.frames {
                let bounds = [
                    self.bounds[0] as f64 + left_to_frame +
                        i as f64 * (frame_width + frame_offset_x),
                    self.bounds[1] as f64 + top_to_frame,
                    frame_width,
                    frame_height
                ];
                rect.draw(bounds, &c.draw_state, c.transform, g);
            }
        }
    }

    pub fn draw_drag<G: Graphics>(&self, c: &Context, g: &mut G) {

    }
}
<|endoftext|>


<commit_before>#![feature(associated_types)]

use std::ops::Deref;

pub mod graph {
    use std::collections::HashMap;

    #[derive(Debug)]
    pub struct Graph {
        elements: i64,
        vertices: HashMap<i64, Box<Vertex>>,
    }

    impl Graph {
        pub fn new() -> Box<Graph> {
            let vertices: HashMap<i64, Box<Vertex>> = HashMap::new();
            Box::new(Graph{elements:0, vertices:vertices})
        }

        pub fn add_vertex(&mut self) -> VertexProxy {
            let new_id = self.elements + 1;
            self.elements += 1;
            let v = Vertex::new(new_id);

            let ptr: *const Box<Vertex> = &v as *const Box<Vertex>;

            self.vertices.insert(new_id, v);

            // return the proxy which knows it's own id
            VertexProxy{id:new_id, v: ptr}
        }
    }

    /*
    I'm not sure on this, but it feels reasonable.  a vertex can own it's out_edges.
    this should? make it easier to manage the memory?

    additionally, it should cut down on the number of "things" i have to traverse
    if a vertex has 10k edges (5k in and out 5k out) then doing something like

    g(v).outV()

    should be faster to iterate over

    the cost is a little code complexity but i think that won't be too bad
     */
    #[derive(Debug)]
    struct Vertex {
        id: i64,
        out_edges: Vec<Edge>,
        in_edges: *mut Vec<Edge>,
    }

    impl Vertex {
        pub fn new(id: i64) -> Box<Vertex> {

            let mut edges : Vec<Edge> = Vec::new();
            let edges_ptr :    *mut Vec<Edge> = &mut edges;
            let out_edges: Vec<Edge> = Vec::new();
            let vertex = Vertex{id:id, out_edges: out_edges, in_edges:edges_ptr};
            let mut v = Box::new(vertex);
            return v;
        }

        pub fn add_out_edge(&mut self, edge: Edge ) {
            self.out_edges.push(edge)
        }

        pub fn add_in_edge() {

        }

    }

    #[derive(Debug)]
    pub struct VertexProxy {
        id: i64,
        v: *const Box<Vertex>,
    }

    //let i: u32 = 1;
    //// explicit cast
    //let p_imm: *const u32 = &i as *const u32;
    //let mut m: u32 = 2;
    //// implicit coercion
    //let p_mut: *mut u32 = &mut m;
    //
    //unsafe {
    //let ref_imm: &u32 = &*p_imm;
    //let ref_mut: &mut u32 = &mut *p_mut;
    //}

    impl VertexProxy {
        pub fn add_edge(&self, to_vertex: &VertexProxy) {
            let in_vertex: &mut Box<Vertex>;
            let out_vertex: &mut Box<Vertex>;

            unsafe {
                in_vertex =  &mut *self.v;
                out_vertex = &mut *to_vertex.v;
            }
            // create the edge

            let mut e = Edge{from_vertex: self.v, to_vertex: to_vertex.v};
            in_vertex.add_out_edge(e);
        }
        pub fn query(self) {

        }
    }

    /*
    impl<T> Deref for DerefExample<T> {
        type Target = T;

        fn deref<'a>(&'a self) -> &'a T {
            &self.value
        }
    }
     */

    #[derive(Debug)]
    struct Edge {
        from_vertex: *const Box<Vertex>,
        to_vertex: *const Box<Vertex>
    }

    #[test]
    fn test_unsafe_vertex() {
        let mut g = Graph::new();
        let v1 = g.add_vertex();
        assert!(v1.id == 1);

        let v2 = g.add_vertex();
        assert!(v2.id == 2);
    }

    #[test]
    fn test_add_edge() {
        let mut g = Graph::new();
        let v1 = g.add_vertex();
        let v2 = g.add_vertex();
        v1.add_edge(&v2);

    }

}
<commit_msg>deref parens<commit_after>#![feature(associated_types)]

use std::ops::Deref;

pub mod graph {
    use std::collections::HashMap;

    #[derive(Debug)]
    pub struct Graph {
        elements: i64,
        vertices: HashMap<i64, Box<Vertex>>,
    }

    impl Graph {
        pub fn new() -> Box<Graph> {
            let vertices: HashMap<i64, Box<Vertex>> = HashMap::new();
            Box::new(Graph{elements:0, vertices:vertices})
        }

        pub fn add_vertex(&mut self) -> VertexProxy {
            let new_id = self.elements + 1;
            self.elements += 1;
            let v = Vertex::new(new_id);

            let ptr: *const Box<Vertex> = &v as *const Box<Vertex>;

            self.vertices.insert(new_id, v);

            // return the proxy which knows it's own id
            VertexProxy{id:new_id, v: ptr}
        }
    }

    /*
    I'm not sure on this, but it feels reasonable.  a vertex can own it's out_edges.
    this should? make it easier to manage the memory?

    additionally, it should cut down on the number of "things" i have to traverse
    if a vertex has 10k edges (5k in and out 5k out) then doing something like

    g(v).outV()

    should be faster to iterate over

    the cost is a little code complexity but i think that won't be too bad
     */
    #[derive(Debug)]
    struct Vertex {
        id: i64,
        out_edges: Vec<Edge>,
        in_edges: *mut Vec<Edge>,
    }

    impl Vertex {
        pub fn new(id: i64) -> Box<Vertex> {

            let mut edges : Vec<Edge> = Vec::new();
            let edges_ptr :    *mut Vec<Edge> = &mut edges;
            let out_edges: Vec<Edge> = Vec::new();
            let vertex = Vertex{id:id, out_edges: out_edges, in_edges:edges_ptr};
            let mut v = Box::new(vertex);
            return v;
        }

        pub fn add_out_edge(&mut self, edge: Edge ) {
            self.out_edges.push(edge)
        }

        pub fn add_in_edge() {

        }

    }

    #[derive(Debug)]
    pub struct VertexProxy {
        id: i64,
        v: *const Box<Vertex>,
    }

    //let i: u32 = 1;
    //// explicit cast
    //let p_imm: *const u32 = &i as *const u32;
    //let mut m: u32 = 2;
    //// implicit coercion
    //let p_mut: *mut u32 = &mut m;
    //
    //unsafe {
    //let ref_imm: &u32 = &*p_imm;
    //let ref_mut: &mut u32 = &mut *p_mut;
    //}

    impl VertexProxy {
        pub fn add_edge(&self, to_vertex: &VertexProxy) {
            let in_vertex: &mut Box<Vertex>;
            let out_vertex: &mut Box<Vertex>;

            unsafe {
                in_vertex =  &mut *(self.v);
                out_vertex = &mut *(to_vertex.v);
            }
            // create the edge

            let mut e = Edge{from_vertex: self.v, to_vertex: to_vertex.v};
            in_vertex.add_out_edge(e);
        }
        pub fn query(self) {

        }
    }

    /*
    impl<T> Deref for DerefExample<T> {
        type Target = T;

        fn deref<'a>(&'a self) -> &'a T {
            &self.value
        }
    }
     */

    #[derive(Debug)]
    struct Edge {
        from_vertex: *const Box<Vertex>,
        to_vertex: *const Box<Vertex>
    }

    #[test]
    fn test_unsafe_vertex() {
        let mut g = Graph::new();
        let v1 = g.add_vertex();
        assert!(v1.id == 1);

        let v2 = g.add_vertex();
        assert!(v2.id == 2);
    }

    #[test]
    fn test_add_edge() {
        let mut g = Graph::new();
        let v1 = g.add_vertex();
        let v2 = g.add_vertex();
        v1.add_edge(&v2);

    }

}
<|endoftext|>


<commit_before>#![crate_name = "bindgen"]
#![crate_type = "dylib"]

#![cfg_attr(feature = "clippy", feature(plugin))]
#![cfg_attr(feature = "clippy", plugin(clippy))]

// To avoid rather annoying warnings when matching with CXCursor_xxx as a
// constant.
#![allow(non_upper_case_globals)]

extern crate syntex_syntax as syntax;
extern crate aster;
extern crate quasi;
extern crate clang_sys;
extern crate libc;
extern crate regex;
#[macro_use]
extern crate log;

mod clangll;
mod clang;
mod ir;
mod parse;
mod regex_set;
mod codegen {
    include!(concat!(env!("OUT_DIR"), "/codegen.rs"));
}

use std::borrow::Borrow;
use std::io::{self, Write};
use std::fs::OpenOptions;
use std::path::Path;
use std::collections::HashSet;

use syntax::ast;
use syntax::codemap::{DUMMY_SP, Span};
use syntax::print::pprust;
use syntax::print::pp::eof;
use syntax::ptr::P;

use ir::context::BindgenContext;
use ir::item::{Item, ItemId};
use parse::{ClangItemParser, ParseError};
use regex_set::RegexSet;

#[derive(Debug,Default)]
pub struct Builder {
    options: BindgenOptions,
}

pub fn builder() -> Builder {
    Default::default()
}

impl Builder {
    pub fn header<T: Into<String>>(self, header: T) -> Builder {
        self.clang_arg(header)
    }

    pub fn match_pat<T: Into<String>>(mut self, arg: T) -> Builder {
        self.options.match_pat.insert(arg.into());
        self
    }

    pub fn hide_type<T: Into<String>>(mut self, arg: T) -> Builder {
        self.options.hidden_types.insert(arg.into());
        self
    }

    pub fn opaque_type<T: Into<String>>(mut self, arg: T) -> Builder {
        self.options.opaque_types.insert(arg.into());
        self
    }

    pub fn whitelisted_type<T: Borrow<str>>(mut self, arg: T) -> Builder {
        self.options.whitelisted_types.insert(&arg);
        self
    }

    pub fn whitelisted_function<T: Borrow<str>>(mut self, arg: T) -> Builder {
        self.options.whitelisted_functions.insert(&arg);
        self
    }

    pub fn whitelisted_var<T: Borrow<str>>(mut self, arg: T) -> Builder {
        self.options.whitelisted_vars.insert(&arg);
        self
    }

    pub fn raw_line<T: Into<String>>(mut self, arg: T) -> Builder {
        self.options.raw_lines.push(arg.into());
        self
    }

    pub fn clang_arg<T: Into<String>>(mut self, arg: T) -> Builder {
        self.options.clang_args.push(arg.into());
        self
    }

    pub fn link<T: Into<String>>(mut self, library: T) -> Builder {
        self.options.links.push((library.into(), LinkType::Default));
        self
    }

    pub fn link_static<T: Into<String>>(mut self, library: T) -> Builder {
        self.options.links.push((library.into(), LinkType::Static));
        self
    }

    pub fn link_framework<T: Into<String>>(mut self, library: T) -> Builder {
        self.options.links.push((library.into(), LinkType::Framework));
        self
    }

    pub fn dtor_attr<T: Into<String>>(mut self, attr: T) -> Builder {
        self.options.dtor_attrs.push(attr.into());
        self
    }

    pub fn forbid_unknown_types(mut self) -> Builder {
        self.options.fail_on_unknown_type = true;
        self
    }

    pub fn emit_builtins(mut self) -> Builder {
        self.options.builtins = true;
        self
    }

    pub fn no_bitfield_methods(mut self) -> Builder {
        self.options.gen_bitfield_methods = false;
        self
    }

    pub fn no_unstable_rust(mut self) -> Builder {
        self.options.unstable_rust = false;
        self
    }
    pub fn rust_enums(mut self, value: bool) -> Builder {
        self.options.rust_enums = value;
        self
    }

    pub fn rename_types(mut self, value: bool) -> Builder {
        self.options.rename_types = value;
        self
    }

    pub fn disable_class_constants(mut self) -> Builder {
        self.options.class_constants = false;
        self
    }

    pub fn generate(self) -> Result<Bindings, ()> {
        Bindings::generate(self.options, None)
    }
}

/// Deprecated - use a `Builder` instead
#[derive(Debug)]
pub struct BindgenOptions {
    pub match_pat: HashSet<String>,
    pub hidden_types: HashSet<String>,
    pub opaque_types: HashSet<String>,
    pub whitelisted_types: RegexSet,
    pub whitelisted_functions: RegexSet,
    pub whitelisted_vars: RegexSet,
    pub builtins: bool,
    pub rust_enums: bool,
    pub links: Vec<(String, LinkType)>,
    pub emit_ast: bool,
    pub ignore_functions: bool,
    pub ignore_methods: bool,
    pub gen_bitfield_methods: bool,
    pub fail_on_unknown_type: bool,
    pub enable_cxx_namespaces: bool,
    pub rename_types: bool,
    pub derive_debug: bool,
    /// Generate or not only stable rust.
    pub unstable_rust: bool,
    /// Whether to generate C++ class constants.
    pub class_constants: bool,
    /// Wether to generate names that are **directly** under namespaces.
    pub namespaced_constants: bool,
    /// Whether to use msvc mangling rules
    pub msvc_mangling: bool,
    pub override_enum_ty: String,
    pub raw_lines: Vec<String>,
    /// Attributes for a type with destructor
    pub dtor_attrs: Vec<String>,
    pub clang_args: Vec<String>,
}

impl Default for BindgenOptions {
    fn default() -> BindgenOptions {
        BindgenOptions {
            match_pat: Default::default(),
            hidden_types: Default::default(),
            opaque_types: Default::default(),
            whitelisted_types: Default::default(),
            whitelisted_functions: Default::default(),
            whitelisted_vars: Default::default(),
            builtins: false,
            rust_enums: true,
            links: vec![],
            emit_ast: false,
            ignore_functions: false,
            ignore_methods: false,
            gen_bitfield_methods: true,
            fail_on_unknown_type: true,
            rename_types: true,
            derive_debug: true,
            enable_cxx_namespaces: false,
            override_enum_ty: "".to_string(),
            unstable_rust: true,
            class_constants: true,
            namespaced_constants: true,
            msvc_mangling: false,
            raw_lines: vec![],
            dtor_attrs: vec![],
            clang_args: vec![],
        }
    }
}

#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub enum LinkType {
    Default,
    Static,
    Framework
}

#[derive(Debug, Clone)]
pub struct Bindings {
    module: ast::Mod,
    raw_lines: Vec<String>,
}

impl Bindings {
    /// Deprecated - use a `Builder` instead
    pub fn generate(options: BindgenOptions, span: Option<Span>) -> Result<Bindings, ()> {
        let span = span.unwrap_or(DUMMY_SP);

        let mut context = BindgenContext::new(options);
        parse(&mut context);

        let module = ast::Mod {
            inner: span,
            items: codegen::codegen(&mut context),
        };

        Ok(Bindings {
            module: module,
            raw_lines: context.options().raw_lines.clone(),
        })
    }

    pub fn into_ast(self) -> Vec<P<ast::Item>> {
        self.module.items
    }

    pub fn to_string(&self) -> String {
        let mut mod_str = vec![];
        {
            let ref_writer = Box::new(mod_str.by_ref()) as Box<Write>;
            self.write(ref_writer).expect("Could not write bindings to string");
        }
        String::from_utf8(mod_str).unwrap()
    }

    pub fn write_to_file<P: AsRef<Path>>(&self, path: P) -> io::Result<()> {
        let file = try!(OpenOptions::new().write(true).truncate(true).create(true).open(path));
        self.write(Box::new(file))
    }

    // https://github.com/Manishearth/rust-clippy/issues/740
    #[cfg_attr(feature = "clippy", allow(needless_lifetimes))]
    pub fn write<'a>(&self, mut writer: Box<Write + 'a>) -> io::Result<()> {
        try!(writer.write("/* automatically generated by rust-bindgen */\n\n".as_bytes()));

        for line in self.raw_lines.iter() {
            try!(writer.write(line.as_bytes()));
            try!(writer.write("\n".as_bytes()));
        }
        if !self.raw_lines.is_empty() {
            try!(writer.write("\n".as_bytes()));
        }

        let mut ps = pprust::rust_printer(writer);
        try!(ps.print_mod(&self.module, &[]));
        try!(ps.print_remaining_comments());
        try!(eof(&mut ps.s));
        ps.s.out.flush()
    }
}

/// Determines whether the given cursor is in any of the files matched by the
/// options.
fn filter_builtins(ctx: &BindgenContext, cursor: &clang::Cursor) -> bool {
    let (file, _, _, _) = cursor.location().location();

    match file.name() {
        None => ctx.options().builtins,
        Some(..) => true,
    }
}

pub fn parse_one(ctx: &mut BindgenContext,
                 cursor: clang::Cursor,
                 parent: Option<ItemId>,
                 children: &mut Vec<ItemId>) -> clangll::Enum_CXVisitorResult {
    if !filter_builtins(ctx, &cursor) {
        return CXChildVisit_Continue
    }

    use clangll::CXChildVisit_Continue;
    match Item::parse(cursor, parent, ctx) {
        Ok(id) => children.push(id),
        Err(ParseError::Continue) => {},
        Err(ParseError::Recurse) => {
            cursor.visit(|child, _| parse_one(ctx, *child, parent, children));
        }
    }
    CXChildVisit_Continue
}

fn parse(context: &mut BindgenContext) {
    use clang::Diagnostic;
    use clangll::*;

    for d in context.translation_unit().diags().iter() {
        let msg = d.format(Diagnostic::default_opts());
        let is_err = d.severity() >= CXDiagnostic_Error;
        println!("{}, err: {}", msg, is_err);
    }

    let cursor = context.translation_unit().cursor();
    if context.options().emit_ast {
        cursor.visit(|cur, _| clang::ast_dump(cur, 0));
    }

    let root = context.root_module();
    context.with_module(root, |context, children| {
        cursor.visit(|cursor, _| parse_one(context, *cursor, None, children))
    });

    assert!(context.current_module() == context.root_module(),
            "How did this happen?");
}
<commit_msg>Remove `match_pat` options and builder methods<commit_after>#![crate_name = "bindgen"]
#![crate_type = "dylib"]

#![cfg_attr(feature = "clippy", feature(plugin))]
#![cfg_attr(feature = "clippy", plugin(clippy))]

// To avoid rather annoying warnings when matching with CXCursor_xxx as a
// constant.
#![allow(non_upper_case_globals)]

extern crate syntex_syntax as syntax;
extern crate aster;
extern crate quasi;
extern crate clang_sys;
extern crate libc;
extern crate regex;
#[macro_use]
extern crate log;

mod clangll;
mod clang;
mod ir;
mod parse;
mod regex_set;
mod codegen {
    include!(concat!(env!("OUT_DIR"), "/codegen.rs"));
}

use std::borrow::Borrow;
use std::io::{self, Write};
use std::fs::OpenOptions;
use std::path::Path;
use std::collections::HashSet;

use syntax::ast;
use syntax::codemap::{DUMMY_SP, Span};
use syntax::print::pprust;
use syntax::print::pp::eof;
use syntax::ptr::P;

use ir::context::BindgenContext;
use ir::item::{Item, ItemId};
use parse::{ClangItemParser, ParseError};
use regex_set::RegexSet;

#[derive(Debug,Default)]
pub struct Builder {
    options: BindgenOptions,
}

pub fn builder() -> Builder {
    Default::default()
}

impl Builder {
    pub fn header<T: Into<String>>(self, header: T) -> Builder {
        self.clang_arg(header)
    }

    pub fn hide_type<T: Into<String>>(mut self, arg: T) -> Builder {
        self.options.hidden_types.insert(arg.into());
        self
    }

    pub fn opaque_type<T: Into<String>>(mut self, arg: T) -> Builder {
        self.options.opaque_types.insert(arg.into());
        self
    }

    pub fn whitelisted_type<T: Borrow<str>>(mut self, arg: T) -> Builder {
        self.options.whitelisted_types.insert(&arg);
        self
    }

    pub fn whitelisted_function<T: Borrow<str>>(mut self, arg: T) -> Builder {
        self.options.whitelisted_functions.insert(&arg);
        self
    }

    pub fn whitelisted_var<T: Borrow<str>>(mut self, arg: T) -> Builder {
        self.options.whitelisted_vars.insert(&arg);
        self
    }

    pub fn raw_line<T: Into<String>>(mut self, arg: T) -> Builder {
        self.options.raw_lines.push(arg.into());
        self
    }

    pub fn clang_arg<T: Into<String>>(mut self, arg: T) -> Builder {
        self.options.clang_args.push(arg.into());
        self
    }

    pub fn link<T: Into<String>>(mut self, library: T) -> Builder {
        self.options.links.push((library.into(), LinkType::Default));
        self
    }

    pub fn link_static<T: Into<String>>(mut self, library: T) -> Builder {
        self.options.links.push((library.into(), LinkType::Static));
        self
    }

    pub fn link_framework<T: Into<String>>(mut self, library: T) -> Builder {
        self.options.links.push((library.into(), LinkType::Framework));
        self
    }

    pub fn dtor_attr<T: Into<String>>(mut self, attr: T) -> Builder {
        self.options.dtor_attrs.push(attr.into());
        self
    }

    pub fn forbid_unknown_types(mut self) -> Builder {
        self.options.fail_on_unknown_type = true;
        self
    }

    pub fn emit_builtins(mut self) -> Builder {
        self.options.builtins = true;
        self
    }

    pub fn no_bitfield_methods(mut self) -> Builder {
        self.options.gen_bitfield_methods = false;
        self
    }

    pub fn no_unstable_rust(mut self) -> Builder {
        self.options.unstable_rust = false;
        self
    }
    pub fn rust_enums(mut self, value: bool) -> Builder {
        self.options.rust_enums = value;
        self
    }

    pub fn rename_types(mut self, value: bool) -> Builder {
        self.options.rename_types = value;
        self
    }

    pub fn disable_class_constants(mut self) -> Builder {
        self.options.class_constants = false;
        self
    }

    pub fn generate(self) -> Result<Bindings, ()> {
        Bindings::generate(self.options, None)
    }
}

/// Deprecated - use a `Builder` instead
#[derive(Debug)]
pub struct BindgenOptions {
    pub hidden_types: HashSet<String>,
    pub opaque_types: HashSet<String>,
    pub whitelisted_types: RegexSet,
    pub whitelisted_functions: RegexSet,
    pub whitelisted_vars: RegexSet,
    pub builtins: bool,
    pub rust_enums: bool,
    pub links: Vec<(String, LinkType)>,
    pub emit_ast: bool,
    pub ignore_functions: bool,
    pub ignore_methods: bool,
    pub gen_bitfield_methods: bool,
    pub fail_on_unknown_type: bool,
    pub enable_cxx_namespaces: bool,
    pub rename_types: bool,
    pub derive_debug: bool,
    /// Generate or not only stable rust.
    pub unstable_rust: bool,
    /// Whether to generate C++ class constants.
    pub class_constants: bool,
    /// Wether to generate names that are **directly** under namespaces.
    pub namespaced_constants: bool,
    /// Whether to use msvc mangling rules
    pub msvc_mangling: bool,
    pub override_enum_ty: String,
    pub raw_lines: Vec<String>,
    /// Attributes for a type with destructor
    pub dtor_attrs: Vec<String>,
    pub clang_args: Vec<String>,
}

impl Default for BindgenOptions {
    fn default() -> BindgenOptions {
        BindgenOptions {
            hidden_types: Default::default(),
            opaque_types: Default::default(),
            whitelisted_types: Default::default(),
            whitelisted_functions: Default::default(),
            whitelisted_vars: Default::default(),
            builtins: false,
            rust_enums: true,
            links: vec![],
            emit_ast: false,
            ignore_functions: false,
            ignore_methods: false,
            gen_bitfield_methods: true,
            fail_on_unknown_type: true,
            rename_types: true,
            derive_debug: true,
            enable_cxx_namespaces: false,
            override_enum_ty: "".to_string(),
            unstable_rust: true,
            class_constants: true,
            namespaced_constants: true,
            msvc_mangling: false,
            raw_lines: vec![],
            dtor_attrs: vec![],
            clang_args: vec![],
        }
    }
}

#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub enum LinkType {
    Default,
    Static,
    Framework
}

#[derive(Debug, Clone)]
pub struct Bindings {
    module: ast::Mod,
    raw_lines: Vec<String>,
}

impl Bindings {
    /// Deprecated - use a `Builder` instead
    pub fn generate(options: BindgenOptions, span: Option<Span>) -> Result<Bindings, ()> {
        let span = span.unwrap_or(DUMMY_SP);

        let mut context = BindgenContext::new(options);
        parse(&mut context);

        let module = ast::Mod {
            inner: span,
            items: codegen::codegen(&mut context),
        };

        Ok(Bindings {
            module: module,
            raw_lines: context.options().raw_lines.clone(),
        })
    }

    pub fn into_ast(self) -> Vec<P<ast::Item>> {
        self.module.items
    }

    pub fn to_string(&self) -> String {
        let mut mod_str = vec![];
        {
            let ref_writer = Box::new(mod_str.by_ref()) as Box<Write>;
            self.write(ref_writer).expect("Could not write bindings to string");
        }
        String::from_utf8(mod_str).unwrap()
    }

    pub fn write_to_file<P: AsRef<Path>>(&self, path: P) -> io::Result<()> {
        let file = try!(OpenOptions::new().write(true).truncate(true).create(true).open(path));
        self.write(Box::new(file))
    }

    // https://github.com/Manishearth/rust-clippy/issues/740
    #[cfg_attr(feature = "clippy", allow(needless_lifetimes))]
    pub fn write<'a>(&self, mut writer: Box<Write + 'a>) -> io::Result<()> {
        try!(writer.write("/* automatically generated by rust-bindgen */\n\n".as_bytes()));

        for line in self.raw_lines.iter() {
            try!(writer.write(line.as_bytes()));
            try!(writer.write("\n".as_bytes()));
        }
        if !self.raw_lines.is_empty() {
            try!(writer.write("\n".as_bytes()));
        }

        let mut ps = pprust::rust_printer(writer);
        try!(ps.print_mod(&self.module, &[]));
        try!(ps.print_remaining_comments());
        try!(eof(&mut ps.s));
        ps.s.out.flush()
    }
}

/// Determines whether the given cursor is in any of the files matched by the
/// options.
fn filter_builtins(ctx: &BindgenContext, cursor: &clang::Cursor) -> bool {
    let (file, _, _, _) = cursor.location().location();

    match file.name() {
        None => ctx.options().builtins,
        Some(..) => true,
    }
}

pub fn parse_one(ctx: &mut BindgenContext,
                 cursor: clang::Cursor,
                 parent: Option<ItemId>,
                 children: &mut Vec<ItemId>) -> clangll::Enum_CXVisitorResult {
    if !filter_builtins(ctx, &cursor) {
        return CXChildVisit_Continue
    }

    use clangll::CXChildVisit_Continue;
    match Item::parse(cursor, parent, ctx) {
        Ok(id) => children.push(id),
        Err(ParseError::Continue) => {},
        Err(ParseError::Recurse) => {
            cursor.visit(|child, _| parse_one(ctx, *child, parent, children));
        }
    }
    CXChildVisit_Continue
}

fn parse(context: &mut BindgenContext) {
    use clang::Diagnostic;
    use clangll::*;

    for d in context.translation_unit().diags().iter() {
        let msg = d.format(Diagnostic::default_opts());
        let is_err = d.severity() >= CXDiagnostic_Error;
        println!("{}, err: {}", msg, is_err);
    }

    let cursor = context.translation_unit().cursor();
    if context.options().emit_ast {
        cursor.visit(|cur, _| clang::ast_dump(cur, 0));
    }

    let root = context.root_module();
    context.with_module(root, |context, children| {
        cursor.visit(|cursor, _| parse_one(context, *cursor, None, children))
    });

    assert!(context.current_module() == context.root_module(),
            "How did this happen?");
}
<|endoftext|>


<commit_before>//#![crate_name="celix_rust"]
//#![feature(libc)]
#![allow(non_camel_case_types,non_snake_case)]

//! A bundle to test Celix and Rust interaction.
//!
//! TODO: Allow more Rust like usage, preferably through use as (more optimised) library.

extern crate libc;
use libc::{c_void,malloc};

use std::fmt;
use std::sync::mpsc::Sender;
use std::sync::mpsc;
use std::thread;
use std::time::Duration;
use std::mem::size_of;
use std::default::Default;

extern crate celix;
// #[macro_use]
// mod celix;
use celix::{celix_status_t,bundle_context_pt,CELIX_SUCCESS};
//const CELIX_SUCCESS: celix_status_t = 0;

// manifest!(SYMBOLIC_NAME = rust_celix);

/// Default thread count
const DEFAULT_THREADS: u64 = 4;

/// Data to be sent between Celix and this code.
///
/// `tx` is used to control the main worker thread: by sending `()`, the thread will stop.
#[repr(C)]
#[derive(Clone)]
pub struct uData {
	t1: i32,
	t2: i32,
	/// A `Sender` for closing the worker thread (cannot drop a dereference of a raw pointer safely!)
	tx: Option<Sender<()>>,
	work: *const Fn() -> i32
}

impl uData {
	pub fn work() {
		println!("Worker function called");
	}
}

impl Default for uData {
	fn default() -> uData {
		uData {
			t1:0,
			t2:0,
			tx:None,
			work:&(||{0})
		}
	}
}

impl fmt::Debug for uData {
	/// Allows formatting
	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
		write!(f, "
uData {{
	t1: {:?},
	t2: {:?}
}}", self.t1, self.t2)
	}
}

fn blah() -> i32 {
	println!("Working...");
	0
}

/// Create this bundle
#[no_mangle]
#[allow(unused_variables)]
// pub extern "C" fn bundleActivator_create(context_ptr: bundle_context_pt, userData: *mut *mut c_void) -> celix_status_t {
// 	println!("create rust");
// 	// println!("{}", SYMBOLIC_NAME);
// 	unsafe {
// 		*userData = malloc(size_of::<uData>()); // C style malloc because the function receives a pointer
// 		(*(*userData as *mut uData)).t1 = 12;
// 		(*(*userData as *mut uData)).t2 = 100;
// 		(*(*userData as *mut uData)).work = & (|| { println!("Working..."); 0 });
// 		(*(*userData as *mut uData)).work = &blah; // Both approaches work
// 	}
// 	CELIX_SUCCESS
// }

pub extern "C" fn bundleActivator_create(context_ptr: bundle_context_pt, userData:*mut *mut c_void ) -> celix_status_t {
	println!("create rust");
	let d = Box::into_raw(Box::new(uData {
		t1: 12,
		t2: 100,
		tx: None,
		work: &blah,
	}));
	unsafe { (*userData) = d as *mut c_void; }
	CELIX_SUCCESS
}

/// Start this bundle.
///
/// Create the main worker thread, and let that create it's own child threads.
#[no_mangle]
#[allow(unused_variables)]
pub extern "C" fn bundleActivator_start(userData: *mut c_void, context: bundle_context_pt) -> celix_status_t {
	println!("start rust");
	let d : *mut uData;
	d = userData as *mut uData;
	println!("casted d");
	unsafe {
		println!("{:?}", (*d));
		let (tx, rx) = mpsc::channel();
		println!("created channel");
		(*d).tx = Some(tx); // This seems to cause a SIGTRAP without compiler optimisations, will eventually have to find out why
		println!("assigned channel tx");
		(*(*d).work)();
		thread::spawn(move ||{
			println!("started thread");
			// Aditional threads should be created here to allow proper control over them.
			let (ltx,lrx) = mpsc::channel();
			let mut threads = vec![];
			let NTHREADS: u64 = match std::env::var("RUST_THREADS") {
				Ok(s) => match s.parse::<u64>() {
					Ok(i) => i,
					Err(_) => DEFAULT_THREADS,
				},
				Err(_) => DEFAULT_THREADS,
			};

			for i in 0..NTHREADS { // in a..b, b is exclusive, so 0..2 == [0,1]
				let ltx = ltx.clone();
				threads.push(thread::spawn(move || {
					loop {
						match ltx.send(()) {
							Err(SendError) => { // lrx has been dropped, so time to stop this thread
								println!("Stopping worker thread {}", i);
								return;
							},
							Ok(_) => {
								println!("worker thread {} working...", i);
								thread::sleep(Duration::new(0,100));
							},
						}
					}
				}));
			}
			loop {
				match rx.try_recv() {
					Ok(_)|Err(mpsc::TryRecvError::Disconnected) => {
						drop(lrx);
						for t in threads {
							let _ = t.join();
							println!("thread stopped");
						}
						println!("Terminated main worker thread");
						return;
					},
					Err(mpsc::TryRecvError::Empty) => {
						// println!("Working...");
						// thread::sleep(Duration::new(1,0));
					},
				}
			}
		});
	}
	println!("Hello {}", unsafe{(*d).t1});
	CELIX_SUCCESS
}

/// Stop this bundle
#[no_mangle]
#[allow(unused_variables)]
pub extern "C" fn bundleActivator_stop(userData: *mut c_void, context: bundle_context_pt) -> celix_status_t {
	println!("stop rust");
	let d : *const uData;
	d = userData as *const uData;
	unsafe {
		println!("{:?}", (*d));
		(*(*d).work)();
		match (*d).tx {
			Some(ref tx) => match tx.send(()) {
				Ok(_) => println!("Sent kill signal to worker thread..."),
				Err(_) => println!("Failed to send kill signal to worker thread..."),
			},
			None => panic!("Channel hasn't been created yet!"),
		}
	}
	println!("Goodbye {}", unsafe{(*d).t1});
	CELIX_SUCCESS
}

/// Destroy this bundle
#[no_mangle]
#[allow(unused_variables)]
pub extern "C" fn bundleActivator_destroy(userData: *mut c_void, context: bundle_context_pt) -> celix_status_t {
	println!("destroy rust");
	CELIX_SUCCESS
}
<commit_msg>test work<commit_after>//#![crate_name="celix_rust"]
//#![feature(libc)]
#![allow(non_camel_case_types,non_snake_case)]

//! A bundle to test Celix and Rust interaction.
//!
//! TODO: Allow more Rust like usage, preferably through use as (more optimised) library.

extern crate libc;
use libc::{c_void,malloc};

use std::fmt;
use std::sync::mpsc::Sender;
use std::sync::mpsc;
use std::thread;
use std::time::Duration;
use std::mem::size_of;
use std::default::Default;

extern crate celix;
// #[macro_use]
// mod celix;
use celix::{celix_status_t,bundle_context_pt,CELIX_SUCCESS};
//const CELIX_SUCCESS: celix_status_t = 0;

// manifest!(SYMBOLIC_NAME = rust_celix);

/// Default thread count
const DEFAULT_THREADS: u64 = 4;

/// Data to be sent between Celix and this code.
///
/// `tx` is used to control the main worker thread: by sending `()`, the thread will stop.
#[repr(C)]
#[derive(Clone)]
pub struct uData {
	t1: i32,
	t2: i32,
	/// A `Sender` for closing the worker thread (cannot drop a dereference of a raw pointer safely!)
	tx: Option<Sender<()>>,
	work: *const Fn() -> i32
}

impl uData {
	pub fn work() {
		println!("Worker function called");
	}
}

impl Default for uData {
	fn default() -> uData {
		uData {
			t1:0,
			t2:0,
			tx:None,
			work:&(||{0})
		}
	}
}

impl fmt::Debug for uData {
	/// Allows formatting
	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
		write!(f, "
uData {{
	t1: {:?},
	t2: {:?}
}}", self.t1, self.t2)
	}
}

fn blah() -> i32 {
	println!("Working...");
	0
}

/// Create this bundle
#[no_mangle]
#[allow(unused_variables)]
// pub extern "C" fn bundleActivator_create(context_ptr: bundle_context_pt, userData: *mut *mut c_void) -> celix_status_t {
// 	println!("create rust");
// 	// println!("{}", SYMBOLIC_NAME);
// 	unsafe {
// 		*userData = malloc(size_of::<uData>()); // C style malloc because the function receives a pointer
// 		(*(*userData as *mut uData)).t1 = 12;
// 		(*(*userData as *mut uData)).t2 = 100;
// 		(*(*userData as *mut uData)).work = & (|| { println!("Working..."); 0 });
// 		(*(*userData as *mut uData)).work = &blah; // Both approaches work
// 	}
// 	CELIX_SUCCESS
// }

pub extern "C" fn bundleActivator_create(context_ptr: bundle_context_pt, userData:*mut *mut c_void ) -> celix_status_t {
	println!("create rust");
	let d = Box::into_raw(Box::new(uData {
		t1: 12,
		t2: 100,
		tx: None,
		work: &||{
			println!("working...");
			0
		},
	}));
	unsafe { (*userData) = d as *mut c_void; }
	CELIX_SUCCESS
}

/// Start this bundle.
///
/// Create the main worker thread, and let that create it's own child threads.
#[no_mangle]
#[allow(unused_variables)]
pub extern "C" fn bundleActivator_start(userData: *mut c_void, context: bundle_context_pt) -> celix_status_t {
	println!("start rust");
	let d : *mut uData;
	d = userData as *mut uData;
	println!("casted d");
	unsafe {
		println!("{:?}", (*d));
		let (tx, rx) = mpsc::channel();
		println!("created channel");
		(*d).tx = Some(tx); // This seems to cause a SIGTRAP without compiler optimisations, will eventually have to find out why
		println!("assigned channel tx");
		(*(*d).work)();
		thread::spawn(move ||{
			println!("started thread");
			// Aditional threads should be created here to allow proper control over them.
			let (ltx,lrx) = mpsc::channel();
			let mut threads = vec![];
			let NTHREADS: u64 = match std::env::var("RUST_THREADS") {
				Ok(s) => match s.parse::<u64>() {
					Ok(i) => i,
					Err(_) => DEFAULT_THREADS,
				},
				Err(_) => DEFAULT_THREADS,
			};

			for i in 0..NTHREADS { // in a..b, b is exclusive, so 0..2 == [0,1]
				let ltx = ltx.clone();
				threads.push(thread::spawn(move || {
					loop {
						match ltx.send(()) {
							Err(SendError) => { // lrx has been dropped, so time to stop this thread
								println!("Stopping worker thread {}", i);
								return;
							},
							Ok(_) => {
								println!("worker thread {} working...", i);
								thread::sleep(Duration::new(0,100));
							},
						}
					}
				}));
			}
			loop {
				match rx.try_recv() {
					Ok(_)|Err(mpsc::TryRecvError::Disconnected) => {
						drop(lrx);
						for t in threads {
							let _ = t.join();
							println!("thread stopped");
						}
						println!("Terminated main worker thread");
						return;
					},
					Err(mpsc::TryRecvError::Empty) => {
						// println!("Working...");
						// thread::sleep(Duration::new(1,0));
					},
				}
			}
		});
	}
	println!("Hello {}", unsafe{(*d).t1});
	CELIX_SUCCESS
}

/// Stop this bundle
#[no_mangle]
#[allow(unused_variables)]
pub extern "C" fn bundleActivator_stop(userData: *mut c_void, context: bundle_context_pt) -> celix_status_t {
	println!("stop rust");
	let d : *const uData;
	d = userData as *const uData;
	unsafe {
		println!("{:?}", (*d));
		(*(*d).work)();
		match (*d).tx {
			Some(ref tx) => match tx.send(()) {
				Ok(_) => println!("Sent kill signal to worker thread..."),
				Err(_) => println!("Failed to send kill signal to worker thread..."),
			},
			None => panic!("Channel hasn't been created yet!"),
		}
	}
	println!("Goodbye {}", unsafe{(*d).t1});

	CELIX_SUCCESS
}

/// Destroy this bundle
#[no_mangle]
#[allow(unused_variables)]
pub extern "C" fn bundleActivator_destroy(userData: *mut c_void, context: bundle_context_pt) -> celix_status_t {
	println!("destroy rust");
	let _ = unsafe { Box::from_raw(userData as *mut uData) };
	CELIX_SUCCESS
}
<|endoftext|>


<commit_before>//! # The Redox OS Kernel, version 2
//!
//! The Redox OS Kernel is a hybrid kernel that supports X86_64 systems and
//! provides Unix-like syscalls for primarily Rust applications

//#![deny(warnings)]
#![feature(alloc)]
#![feature(asm)]
#![feature(collections)]
#![feature(const_fn)]
#![feature(core_intrinsics)]
#![feature(drop_types_in_const)]
#![feature(heap_api)]
#![feature(integer_atomics)]
#![feature(lang_items)]
#![feature(naked_functions)]
#![feature(never_type)]
#![feature(thread_local)]
#![feature(unique)]
#![no_std]

extern crate alloc_kernel as allocator;
pub extern crate x86;

extern crate alloc;
#[macro_use]
extern crate collections;

#[macro_use]
extern crate bitflags;
extern crate goblin;
extern crate spin;

use core::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering};
use scheme::FileHandle;

pub use consts::*;

#[macro_use]
/// Shared data structures
pub mod common;

/// Macros like print, println, and interrupt
#[macro_use]
pub mod macros;

/// Constants like memory locations
pub mod consts;

/// ACPI table parsing
mod acpi;

/// Context management
pub mod context;

/// Devices
pub mod device;

/// ELF file parsing
pub mod elf;

/// External functions
pub mod externs;

/// Global descriptor table
pub mod gdt;

/// Interrupt descriptor table
mod idt;

/// Interrupt instructions
pub mod interrupt;

/// Memory management
pub mod memory;

/// Paging
pub mod paging;

/// Panic
pub mod panic;

/// Schemes, filesystem handlers
pub mod scheme;

/// Initialization and start function
pub mod start;

/// Shutdown function
pub mod stop;

/// Synchronization primitives
pub mod sync;

/// Syscall handlers
pub mod syscall;

/// Time
pub mod time;

/// Tests
#[cfg(test)]
pub mod tests;

/// A unique number that identifies the current CPU - used for scheduling
#[thread_local]
static CPU_ID: AtomicUsize = ATOMIC_USIZE_INIT;

/// Get the current CPU's scheduling ID
#[inline(always)]
pub fn cpu_id() -> usize {
    CPU_ID.load(Ordering::Relaxed)
}

/// The count of all CPUs that can have work scheduled
static CPU_COUNT : AtomicUsize = ATOMIC_USIZE_INIT;

/// Get the number of CPUs currently active
#[inline(always)]
pub fn cpu_count() -> usize {
    CPU_COUNT.load(Ordering::Relaxed)
}

/// Initialize userspace by running the initfs:bin/init process
/// This function will also set the CWD to initfs:bin and open debug: as stdio
pub extern fn userspace_init() {
    assert_eq!(syscall::chdir(b"initfs:"), Ok(0));

    assert_eq!(syscall::open(b"debug:", syscall::flag::O_RDONLY).map(FileHandle::into), Ok(0));
    assert_eq!(syscall::open(b"debug:", syscall::flag::O_WRONLY).map(FileHandle::into), Ok(1));
    assert_eq!(syscall::open(b"debug:", syscall::flag::O_WRONLY).map(FileHandle::into), Ok(2));

    syscall::exec(b"/bin/init", &[]).expect("failed to execute init");

    panic!("init returned");
}

/// This is the kernel entry point for the primary CPU. The arch crate is responsible for calling this
#[no_mangle]
pub extern fn kmain(cpus: usize) {
    CPU_ID.store(0, Ordering::SeqCst);
    CPU_COUNT.store(cpus, Ordering::SeqCst);

    context::init();

    let pid = syscall::getpid();
    println!("BSP: {:?} {}", pid, cpus);

    match context::contexts_mut().spawn(userspace_init) {
        Ok(context_lock) => {
            let mut context = context_lock.write();
            context.status = context::Status::Runnable;
        },
        Err(err) => {
            panic!("failed to spawn userspace_init: {:?}", err);
        }
    }

    loop {
        unsafe {
            interrupt::disable();
            if context::switch() {
                interrupt::enable_and_nop();
            } else {
                // Enable interrupts, then halt CPU (to save power) until the next interrupt is actually fired.
                interrupt::enable_and_halt();
            }
        }
    }
}

/// This is the main kernel entry point for secondary CPUs
#[no_mangle]
pub extern fn kmain_ap(id: usize) {
    CPU_ID.store(id, Ordering::SeqCst);

    context::init();

    let pid = syscall::getpid();
    println!("AP {}: {:?}", id, pid);

    loop {
        unsafe {
            interrupt::disable();
            if context::switch() {
                interrupt::enable_and_nop();
            } else {
                // Enable interrupts, then halt CPU (to save power) until the next interrupt is actually fired.
                interrupt::enable_and_halt();
            }
        }
    }
}

/// Allow exception handlers to send signal to arch-independant kernel
#[no_mangle]
pub extern fn ksignal(signal: usize) {
    println!("SIGNAL {}, CPU {}, PID {:?}", signal, cpu_id(), context::context_id());
    {
        let contexts = context::contexts();
        if let Some(context_lock) = contexts.current() {
            let context = context_lock.read();
            println!("NAME {}", unsafe { ::core::str::from_utf8_unchecked(&context.name.lock()) });
        }
    }
    syscall::exit(signal & 0x7F);
}
<commit_msg>Fix shutdown by disabling APs<commit_after>//! # The Redox OS Kernel, version 2
//!
//! The Redox OS Kernel is a hybrid kernel that supports X86_64 systems and
//! provides Unix-like syscalls for primarily Rust applications

//#![deny(warnings)]
#![feature(alloc)]
#![feature(asm)]
#![feature(collections)]
#![feature(const_fn)]
#![feature(core_intrinsics)]
#![feature(drop_types_in_const)]
#![feature(heap_api)]
#![feature(integer_atomics)]
#![feature(lang_items)]
#![feature(naked_functions)]
#![feature(never_type)]
#![feature(thread_local)]
#![feature(unique)]
#![no_std]

extern crate alloc_kernel as allocator;
pub extern crate x86;

extern crate alloc;
#[macro_use]
extern crate collections;

#[macro_use]
extern crate bitflags;
extern crate goblin;
extern crate spin;

use core::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering};
use scheme::FileHandle;

pub use consts::*;

#[macro_use]
/// Shared data structures
pub mod common;

/// Macros like print, println, and interrupt
#[macro_use]
pub mod macros;

/// Constants like memory locations
pub mod consts;

/// ACPI table parsing
mod acpi;

/// Context management
pub mod context;

/// Devices
pub mod device;

/// ELF file parsing
pub mod elf;

/// External functions
pub mod externs;

/// Global descriptor table
pub mod gdt;

/// Interrupt descriptor table
mod idt;

/// Interrupt instructions
pub mod interrupt;

/// Memory management
pub mod memory;

/// Paging
pub mod paging;

/// Panic
pub mod panic;

/// Schemes, filesystem handlers
pub mod scheme;

/// Initialization and start function
pub mod start;

/// Shutdown function
pub mod stop;

/// Synchronization primitives
pub mod sync;

/// Syscall handlers
pub mod syscall;

/// Time
pub mod time;

/// Tests
#[cfg(test)]
pub mod tests;

/// A unique number that identifies the current CPU - used for scheduling
#[thread_local]
static CPU_ID: AtomicUsize = ATOMIC_USIZE_INIT;

/// Get the current CPU's scheduling ID
#[inline(always)]
pub fn cpu_id() -> usize {
    CPU_ID.load(Ordering::Relaxed)
}

/// The count of all CPUs that can have work scheduled
static CPU_COUNT : AtomicUsize = ATOMIC_USIZE_INIT;

/// Get the number of CPUs currently active
#[inline(always)]
pub fn cpu_count() -> usize {
    CPU_COUNT.load(Ordering::Relaxed)
}

/// Initialize userspace by running the initfs:bin/init process
/// This function will also set the CWD to initfs:bin and open debug: as stdio
pub extern fn userspace_init() {
    assert_eq!(syscall::chdir(b"initfs:"), Ok(0));

    assert_eq!(syscall::open(b"debug:", syscall::flag::O_RDONLY).map(FileHandle::into), Ok(0));
    assert_eq!(syscall::open(b"debug:", syscall::flag::O_WRONLY).map(FileHandle::into), Ok(1));
    assert_eq!(syscall::open(b"debug:", syscall::flag::O_WRONLY).map(FileHandle::into), Ok(2));

    syscall::exec(b"/bin/init", &[]).expect("failed to execute init");

    panic!("init returned");
}

/// This is the kernel entry point for the primary CPU. The arch crate is responsible for calling this
#[no_mangle]
pub extern fn kmain(cpus: usize) {
    CPU_ID.store(0, Ordering::SeqCst);
    CPU_COUNT.store(cpus, Ordering::SeqCst);

    context::init();

    let pid = syscall::getpid();
    println!("BSP: {:?} {}", pid, cpus);

    match context::contexts_mut().spawn(userspace_init) {
        Ok(context_lock) => {
            let mut context = context_lock.write();
            context.status = context::Status::Runnable;
        },
        Err(err) => {
            panic!("failed to spawn userspace_init: {:?}", err);
        }
    }

    loop {
        unsafe {
            interrupt::disable();
            if context::switch() {
                interrupt::enable_and_nop();
            } else {
                // Enable interrupts, then halt CPU (to save power) until the next interrupt is actually fired.
                interrupt::enable_and_halt();
            }
        }
    }
}

/// This is the main kernel entry point for secondary CPUs
#[no_mangle]
pub extern fn kmain_ap(id: usize) {
    loop {
        unsafe {
            interrupt::disable();
            interrupt::halt();
        }
    }
    /*
    CPU_ID.store(id, Ordering::SeqCst);

    context::init();

    let pid = syscall::getpid();
    println!("AP {}: {:?}", id, pid);

    loop {
        unsafe {
            interrupt::disable();
            if context::switch() {
                interrupt::enable_and_nop();
            } else {
                // Enable interrupts, then halt CPU (to save power) until the next interrupt is actually fired.
                interrupt::enable_and_halt();
            }
        }
    }
    */
}

/// Allow exception handlers to send signal to arch-independant kernel
#[no_mangle]
pub extern fn ksignal(signal: usize) {
    println!("SIGNAL {}, CPU {}, PID {:?}", signal, cpu_id(), context::context_id());
    {
        let contexts = context::contexts();
        if let Some(context_lock) = contexts.current() {
            let context = context_lock.read();
            println!("NAME {}", unsafe { ::core::str::from_utf8_unchecked(&context.name.lock()) });
        }
    }
    syscall::exit(signal & 0x7F);
}
<|endoftext|>


<commit_before>use rand::seq::SliceRandom;

/// Convenience function to generate a new petname from default word lists.
#[allow(dead_code)]
pub fn petname(words: u8, separator: &str) -> String {
    Petnames::default().generate_one(words, separator)
}

/// Word lists and the logic to combine them into _petnames_.
///
/// A _petname_ with `n` words will contain, in order:
///
///   * `n - 2` adverbs when `n >= 2`, otherwise 0 adverbs.
///   * 1 adjective when `n >= 2`, otherwise 0 adjectives.
///   * 1 name / noun when `n >= 1`, otherwise 0 names.
///
pub struct Petnames<'a> {
    pub adjectives: Vec<&'a str>,
    pub adverbs: Vec<&'a str>,
    pub names: Vec<&'a str>,
}

impl<'a> Petnames<'a> {
    /// Constructs a new `Petnames` from the default (small) word lists.
    pub fn default() -> Self {
        Self::small()
    }

    /// Constructs a new `Petnames` from the small word lists.
    pub fn small() -> Self {
        Self::init(
            include_str!("../words/small/adjectives.txt"),
            include_str!("../words/small/adverbs.txt"),
            include_str!("../words/small/names.txt"),
        )
    }

    /// Constructs a new `Petnames` from the medium word lists.
    pub fn medium() -> Self {
        Self::init(
            include_str!("../words/medium/adjectives.txt"),
            include_str!("../words/medium/adverbs.txt"),
            include_str!("../words/medium/names.txt"),
        )
    }

    /// Constructs a new `Petnames` from the large word lists.
    pub fn large() -> Self {
        Self::init(
            include_str!("../words/large/adjectives.txt"),
            include_str!("../words/large/adverbs.txt"),
            include_str!("../words/large/names.txt"),
        )
    }

    /// Constructs a new `Petnames` from the given word lists.
    ///
    /// The words are extracted from the given strings by splitting on whitespace.
    pub fn init(adjectives: &'a str, adverbs: &'a str, names: &'a str) -> Self {
        Self {
            adjectives: adjectives.split_whitespace().collect(),
            adverbs: adverbs.split_whitespace().collect(),
            names: names.split_whitespace().collect(),
        }
    }

    /// Keep words matching a predicate.
    ///
    /// # Examples
    ///
    /// ```rust
    /// let mut petnames = petname::Petnames::default();
    /// petnames.retain(|s| s.starts_with("b"));
    /// petnames.generate_one(2, ".");
    /// ```
    ///
    /// This is merely a convenience wrapper that applies the same predicate to
    /// the adjectives, adverbs, and names lists.
    ///
    pub fn retain<F>(&mut self, predicate: F)
    where
        F: Fn(&&str) -> bool,
    {
        self.adjectives.retain(&predicate);
        self.adverbs.retain(&predicate);
        self.names.retain(&predicate);
    }

    /// Calculate the cardinality of this `Petnames`.
    ///
    /// If this is low, names may be repeated by the generator with a higher
    /// frequency than your use-case may allow. If it is 0 (zero) the generator
    /// will panic (unless `words` is also zero).
    ///
    /// This can saturate. If the total possible combinations of words exceeds
    /// `u128::MAX` then this will return `u128::MAX`.
    #[allow(dead_code)]
    pub fn cardinality(&self, words: u8) -> u128 {
        let mut total: u128 = if words == 0 { 0 } else { 1 };
        for num in (0..words).rev() {
            total = total.saturating_mul(match num {
                0 => self.names.len() as u128,
                1 => self.adjectives.len() as u128,
                _ => self.adverbs.len() as u128,
            });
        }
        total
    }

    /// Generate a new petname.
    ///
    /// # Examples
    ///
    /// ```rust
    /// let mut rng = rand::thread_rng();
    /// petname::Petnames::default().generate(&mut rng, 7, ":");
    /// ```
    ///
    /// # Panics
    ///
    /// If a word list is empty.
    ///
    pub fn generate<RNG>(&self, rng: &mut RNG, words: u8, separator: &str) -> String
    where
        RNG: rand::Rng,
    {
        // Adverbs all the way, finishing with adjective then name.
        let mut parts = Vec::with_capacity(words as usize);
        for num in (0..words).rev() {
            parts.push(*match num {
                0 => self.names.choose(rng).unwrap(),
                1 => self.adjectives.choose(rng).unwrap(),
                _ => self.adverbs.choose(rng).unwrap(),
            });
        }
        parts.join(separator)
    }

    /// Generate a single new petname.
    ///
    /// This is like `generate` but uses `rand::thread_rng` as the random
    /// source. For efficiency use `generate` when creating multiple names, or
    /// when you want to use a custom source of randomness.
    pub fn generate_one(&self, words: u8, separator: &str) -> String {
        self.generate(&mut rand::thread_rng(), words, separator)
    }
}

impl<'a> Default for Petnames<'a> {
    fn default() -> Self {
        Self::default()
    }
}

#[cfg(test)]
mod tests {

    use super::{petname, Petnames};
    use rand;

    #[test]
    fn default_petnames_has_adjectives() {
        let petnames = Petnames::default();
        assert_ne!(petnames.adjectives.len(), 0);
    }

    #[test]
    fn default_petnames_has_adverbs() {
        let petnames = Petnames::default();
        assert_ne!(petnames.adverbs.len(), 0);
    }

    #[test]
    fn default_petnames_has_names() {
        let petnames = Petnames::default();
        assert_ne!(petnames.names.len(), 0);
    }

    #[test]
    fn default_petnames_has_non_zero_cardinality() {
        let petnames = Petnames::default();
        // This test will need to be adjusted when word lists change.
        assert_eq!(0, petnames.cardinality(0));
        assert_eq!(456, petnames.cardinality(1));
        assert_eq!(204744, petnames.cardinality(2));
        assert_eq!(53438184, petnames.cardinality(3));
        assert_eq!(13947366024, petnames.cardinality(4));
    }

    #[test]
    fn generate_uses_adverb_adjective_name() {
        let petnames = Petnames {
            adjectives: vec!["adjective"],
            adverbs: vec!["adverb"],
            names: vec!["name"],
        };
        assert_eq!(
            petnames.generate(&mut rand::thread_rng(), 3, "-"),
            "adverb-adjective-name"
        );
    }

    #[test]
    fn petname_renders_desired_number_of_words() {
        assert_eq!(petname(7, "-").split("-").count(), 7);
    }

    #[test]
    fn petname_renders_with_desired_separator() {
        assert_eq!(petname(7, "@").split("@").count(), 7);
    }
}
<commit_msg>Add Words, a type alias for a word list.<commit_after>use rand::seq::SliceRandom;

/// Convenience function to generate a new petname from default word lists.
#[allow(dead_code)]
pub fn petname(words: u8, separator: &str) -> String {
    Petnames::default().generate_one(words, separator)
}

/// A word list.
pub type Words<'a> = Vec<&'a str>;

/// Word lists and the logic to combine them into _petnames_.
///
/// A _petname_ with `n` words will contain, in order:
///
///   * `n - 2` adverbs when `n >= 2`, otherwise 0 adverbs.
///   * 1 adjective when `n >= 2`, otherwise 0 adjectives.
///   * 1 name / noun when `n >= 1`, otherwise 0 names.
///
pub struct Petnames<'a> {
    pub adjectives: Words<'a>,
    pub adverbs: Words<'a>,
    pub names: Words<'a>,
}

impl<'a> Petnames<'a> {
    /// Constructs a new `Petnames` from the default (small) word lists.
    pub fn default() -> Self {
        Self::small()
    }

    /// Constructs a new `Petnames` from the small word lists.
    pub fn small() -> Self {
        Self::init(
            include_str!("../words/small/adjectives.txt"),
            include_str!("../words/small/adverbs.txt"),
            include_str!("../words/small/names.txt"),
        )
    }

    /// Constructs a new `Petnames` from the medium word lists.
    pub fn medium() -> Self {
        Self::init(
            include_str!("../words/medium/adjectives.txt"),
            include_str!("../words/medium/adverbs.txt"),
            include_str!("../words/medium/names.txt"),
        )
    }

    /// Constructs a new `Petnames` from the large word lists.
    pub fn large() -> Self {
        Self::init(
            include_str!("../words/large/adjectives.txt"),
            include_str!("../words/large/adverbs.txt"),
            include_str!("../words/large/names.txt"),
        )
    }

    /// Constructs a new `Petnames` from the given word lists.
    ///
    /// The words are extracted from the given strings by splitting on whitespace.
    pub fn init(adjectives: &'a str, adverbs: &'a str, names: &'a str) -> Self {
        Self {
            adjectives: adjectives.split_whitespace().collect(),
            adverbs: adverbs.split_whitespace().collect(),
            names: names.split_whitespace().collect(),
        }
    }

    /// Keep words matching a predicate.
    ///
    /// # Examples
    ///
    /// ```rust
    /// let mut petnames = petname::Petnames::default();
    /// petnames.retain(|s| s.starts_with("b"));
    /// petnames.generate_one(2, ".");
    /// ```
    ///
    /// This is merely a convenience wrapper that applies the same predicate to
    /// the adjectives, adverbs, and names lists.
    ///
    pub fn retain<F>(&mut self, predicate: F)
    where
        F: Fn(&&str) -> bool,
    {
        self.adjectives.retain(&predicate);
        self.adverbs.retain(&predicate);
        self.names.retain(&predicate);
    }

    /// Calculate the cardinality of this `Petnames`.
    ///
    /// If this is low, names may be repeated by the generator with a higher
    /// frequency than your use-case may allow. If it is 0 (zero) the generator
    /// will panic (unless `words` is also zero).
    ///
    /// This can saturate. If the total possible combinations of words exceeds
    /// `u128::MAX` then this will return `u128::MAX`.
    #[allow(dead_code)]
    pub fn cardinality(&self, words: u8) -> u128 {
        let mut total: u128 = if words == 0 { 0 } else { 1 };
        for num in (0..words).rev() {
            total = total.saturating_mul(match num {
                0 => self.names.len() as u128,
                1 => self.adjectives.len() as u128,
                _ => self.adverbs.len() as u128,
            });
        }
        total
    }

    /// Generate a new petname.
    ///
    /// # Examples
    ///
    /// ```rust
    /// let mut rng = rand::thread_rng();
    /// petname::Petnames::default().generate(&mut rng, 7, ":");
    /// ```
    ///
    /// # Panics
    ///
    /// If a word list is empty.
    ///
    pub fn generate<RNG>(&self, rng: &mut RNG, words: u8, separator: &str) -> String
    where
        RNG: rand::Rng,
    {
        // Adverbs all the way, finishing with adjective then name.
        let mut parts = Vec::with_capacity(words as usize);
        for num in (0..words).rev() {
            parts.push(*match num {
                0 => self.names.choose(rng).unwrap(),
                1 => self.adjectives.choose(rng).unwrap(),
                _ => self.adverbs.choose(rng).unwrap(),
            });
        }
        parts.join(separator)
    }

    /// Generate a single new petname.
    ///
    /// This is like `generate` but uses `rand::thread_rng` as the random
    /// source. For efficiency use `generate` when creating multiple names, or
    /// when you want to use a custom source of randomness.
    pub fn generate_one(&self, words: u8, separator: &str) -> String {
        self.generate(&mut rand::thread_rng(), words, separator)
    }
}

impl<'a> Default for Petnames<'a> {
    fn default() -> Self {
        Self::default()
    }
}

#[cfg(test)]
mod tests {

    use super::{petname, Petnames};
    use rand;

    #[test]
    fn default_petnames_has_adjectives() {
        let petnames = Petnames::default();
        assert_ne!(petnames.adjectives.len(), 0);
    }

    #[test]
    fn default_petnames_has_adverbs() {
        let petnames = Petnames::default();
        assert_ne!(petnames.adverbs.len(), 0);
    }

    #[test]
    fn default_petnames_has_names() {
        let petnames = Petnames::default();
        assert_ne!(petnames.names.len(), 0);
    }

    #[test]
    fn default_petnames_has_non_zero_cardinality() {
        let petnames = Petnames::default();
        // This test will need to be adjusted when word lists change.
        assert_eq!(0, petnames.cardinality(0));
        assert_eq!(456, petnames.cardinality(1));
        assert_eq!(204744, petnames.cardinality(2));
        assert_eq!(53438184, petnames.cardinality(3));
        assert_eq!(13947366024, petnames.cardinality(4));
    }

    #[test]
    fn generate_uses_adverb_adjective_name() {
        let petnames = Petnames {
            adjectives: vec!["adjective"],
            adverbs: vec!["adverb"],
            names: vec!["name"],
        };
        assert_eq!(
            petnames.generate(&mut rand::thread_rng(), 3, "-"),
            "adverb-adjective-name"
        );
    }

    #[test]
    fn petname_renders_desired_number_of_words() {
        assert_eq!(petname(7, "-").split("-").count(), 7);
    }

    #[test]
    fn petname_renders_with_desired_separator() {
        assert_eq!(petname(7, "@").split("@").count(), 7);
    }
}
<|endoftext|>


<commit_before>//! strfmt crate

use std::fmt;
use std::fmt::Write;
use std::collections::HashMap;
use std::string::String;

#[cfg(test)]
mod tests;
mod types;
mod formatter;
mod fmtstr;

pub use types::{Result, FmtError};
pub use fmtstr::strfmt_map;
pub use formatter::Formatter;

/// rust-style format a string given a HashMap of the variables
pub fn strfmt<T: fmt::Display>(fmtstr: &str, vars: &HashMap<String, T>) -> Result<String> {
    let formatter = |fmt: Formatter| {
        let v = match vars.get(fmt.key) {
            Some(v) => v,
            None => {
                let mut msg = String::new();
                write!(msg, "Invalid key: {}", fmt.key).unwrap();
                return Err(FmtError::KeyError(msg));
            },
        };
        fmt.str(v.to_string().as_str())
    };
    strfmt_map(fmtstr, &formatter)
}

pub trait Format {
    fn format<D: fmt::Display>(&self, vars: &HashMap<String, D>) -> Result<String>;
}

impl Format for String {
    fn format<D: fmt::Display>(&self, vars: &HashMap<String, D>) -> Result<String> {
        strfmt(self.as_str(), vars)
    }
}

impl Format for str {
    fn format<D: fmt::Display>(&self, vars: &HashMap<String, D>) -> Result<String> {
        strfmt(self, vars)
    }
}
<commit_msg>forgot to export types<commit_after>//! strfmt crate

use std::fmt;
use std::fmt::Write;
use std::collections::HashMap;
use std::string::String;

#[cfg(test)]
mod tests;
mod types;
mod formatter;
mod fmtstr;

pub use types::{Result, FmtError, Alignment, Sign};
pub use fmtstr::strfmt_map;
pub use formatter::Formatter;

/// rust-style format a string given a HashMap of the variables
pub fn strfmt<T: fmt::Display>(fmtstr: &str, vars: &HashMap<String, T>) -> Result<String> {
    let formatter = |fmt: Formatter| {
        let v = match vars.get(fmt.key) {
            Some(v) => v,
            None => {
                let mut msg = String::new();
                write!(msg, "Invalid key: {}", fmt.key).unwrap();
                return Err(FmtError::KeyError(msg));
            },
        };
        fmt.str(v.to_string().as_str())
    };
    strfmt_map(fmtstr, &formatter)
}

pub trait Format {
    fn format<D: fmt::Display>(&self, vars: &HashMap<String, D>) -> Result<String>;
}

impl Format for String {
    fn format<D: fmt::Display>(&self, vars: &HashMap<String, D>) -> Result<String> {
        strfmt(self.as_str(), vars)
    }
}

impl Format for str {
    fn format<D: fmt::Display>(&self, vars: &HashMap<String, D>) -> Result<String> {
        strfmt(self, vars)
    }
}
<|endoftext|>


<commit_before>#![warn(bad_style)]
// #![warn(missing_docs)]
#![warn(unused)]
#![warn(unused_extern_crates)]
#![warn(unused_import_braces)]
#![warn(unused_qualifications)]
#![warn(unused_results)]

use oauth_client::{self as oauth, Token};
use serde::{Deserialize, Serialize};
use std::borrow::Cow;
use std::collections::HashMap;

type Result<T> = std::result::Result<T, failure::Error>;

mod api_twitter_oauth {
    pub const REQUEST_TOKEN: &str = "https://api.twitter.com/oauth/request_token";
    pub const AUTHORIZE: &str = "https://api.twitter.com/oauth/authorize";
    pub const ACCESS_TOKEN: &str = "https://api.twitter.com/oauth/access_token";
}

mod api_twitter_soft {
    pub const UPDATE_STATUS: &str = "https://api.twitter.com/1.1/statuses/update.json";
    pub const HOME_TIMELINE: &str = "https://api.twitter.com/1.1/statuses/home_timeline.json";
}

#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct Tweet {
    pub created_at: String,
    pub text: String,
}

impl Tweet {
    pub fn parse_timeline(json_string: String) -> Result<Vec<Tweet>> {
        let conf = serde_json::from_str(&json_string)?;
        Ok(conf)
    }
}

fn split_query(query: &str) -> HashMap<Cow<'_, str>, Cow<'_, str>> {
    let mut param = HashMap::new();
    for q in query.split('&') {
        let mut s = q.splitn(2, '=');
        let k = s.next().unwrap();
        let v = s.next().unwrap();
        let _ = param.insert(k.into(), v.into());
    }
    param
}

pub fn get_request_token(consumer: &Token<'_>) -> Result<Token<'static>> {
    let bytes = oauth::get(api_twitter_oauth::REQUEST_TOKEN, consumer, None, None)?;
    let resp = String::from_utf8(bytes)?;
    let param = split_query(&resp);
    let token = Token::new(
        param.get("oauth_token").unwrap().to_string(),
        param.get("oauth_token_secret").unwrap().to_string(),
    );
    Ok(token)
}

pub fn get_authorize_url(request: &Token<'_>) -> String {
    format!(
        "{}?oauth_token={}",
        api_twitter_oauth::AUTHORIZE,
        request.key
    )
}

pub fn get_access_token(
    consumer: &Token<'_>,
    request: &Token<'_>,
    pin: &str,
) -> Result<Token<'static>> {
    let mut param = HashMap::new();
    let _ = param.insert("oauth_verifier".into(), pin.into());
    let bytes = oauth::get(
        api_twitter_oauth::ACCESS_TOKEN,
        consumer,
        Some(request),
        Some(&param),
    )?;
    let resp = String::from_utf8(bytes)?;
    let param = split_query(&resp);
    let token = Token::new(
        param.get("oauth_token").unwrap().to_string(),
        param.get("oauth_token_secret").unwrap().to_string(),
    );
    Ok(token)
}

/// function to update the status
/// This function takes as arguments the consumer key, the access key, and the status (obviously)
pub fn update_status(consumer: &Token<'_>, access: &Token<'_>, status: &str) -> Result<()> {
    let mut param = HashMap::new();
    let _ = param.insert("status".into(), status.into());
    let _ = oauth::post(
        api_twitter_soft::UPDATE_STATUS,
        consumer,
        Some(access),
        Some(&param),
    )?;
    Ok(())
}

pub fn get_last_tweets(consumer: &Token<'_>, access: &Token<'_>) -> Result<Vec<Tweet>> {
    let bytes = oauth::get(
        api_twitter_soft::HOME_TIMELINE,
        consumer,
        Some(access),
        None,
    )?;
    let last_tweets_json = String::from_utf8(bytes)?;
    let ts = Tweet::parse_timeline(last_tweets_json)?;
    Ok(ts)
}
<commit_msg>reduce heap allocation<commit_after>#![warn(bad_style)]
// #![warn(missing_docs)]
#![warn(unused)]
#![warn(unused_extern_crates)]
#![warn(unused_import_braces)]
#![warn(unused_qualifications)]
#![warn(unused_results)]

use oauth_client::{self as oauth, Token};
use serde::{Deserialize, Serialize};
use std::{borrow::Cow, collections::HashMap, str};

type Result<T> = std::result::Result<T, failure::Error>;

mod api_twitter_oauth {
    pub const REQUEST_TOKEN: &str = "https://api.twitter.com/oauth/request_token";
    pub const AUTHORIZE: &str = "https://api.twitter.com/oauth/authorize";
    pub const ACCESS_TOKEN: &str = "https://api.twitter.com/oauth/access_token";
}

mod api_twitter_soft {
    pub const UPDATE_STATUS: &str = "https://api.twitter.com/1.1/statuses/update.json";
    pub const HOME_TIMELINE: &str = "https://api.twitter.com/1.1/statuses/home_timeline.json";
}

#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct Tweet {
    pub created_at: String,
    pub text: String,
}

impl Tweet {
    pub fn parse_timeline(json_str: impl AsRef<str>) -> Result<Vec<Tweet>> {
        let tweets = serde_json::from_str(json_str.as_ref())?;
        Ok(tweets)
    }
}

fn split_query(query: &str) -> HashMap<Cow<'_, str>, Cow<'_, str>> {
    let mut param = HashMap::new();
    for q in query.split('&') {
        let mut s = q.splitn(2, '=');
        let k = s.next().unwrap();
        let v = s.next().unwrap();
        let _ = param.insert(k.into(), v.into());
    }
    param
}

pub fn get_request_token(consumer: &Token<'_>) -> Result<Token<'static>> {
    let bytes = oauth::get(api_twitter_oauth::REQUEST_TOKEN, consumer, None, None)?;
    let resp = str::from_utf8(&bytes)?;
    let param = split_query(&resp);
    let token = Token::new(
        param.get("oauth_token").unwrap().to_string(),
        param.get("oauth_token_secret").unwrap().to_string(),
    );
    Ok(token)
}

pub fn get_authorize_url(request: &Token<'_>) -> String {
    format!(
        "{}?oauth_token={}",
        api_twitter_oauth::AUTHORIZE,
        request.key
    )
}

pub fn get_access_token(
    consumer: &Token<'_>,
    request: &Token<'_>,
    pin: &str,
) -> Result<Token<'static>> {
    let mut param = HashMap::new();
    let _ = param.insert("oauth_verifier".into(), pin.into());
    let bytes = oauth::get(
        api_twitter_oauth::ACCESS_TOKEN,
        consumer,
        Some(request),
        Some(&param),
    )?;
    let resp = str::from_utf8(&bytes)?;
    let param = split_query(&resp);
    let token = Token::new(
        param.get("oauth_token").unwrap().to_string(),
        param.get("oauth_token_secret").unwrap().to_string(),
    );
    Ok(token)
}

/// function to update the status
/// This function takes as arguments the consumer key, the access key, and the status (obviously)
pub fn update_status(consumer: &Token<'_>, access: &Token<'_>, status: &str) -> Result<()> {
    let mut param = HashMap::new();
    let _ = param.insert("status".into(), status.into());
    let _ = oauth::post(
        api_twitter_soft::UPDATE_STATUS,
        consumer,
        Some(access),
        Some(&param),
    )?;
    Ok(())
}

pub fn get_last_tweets(consumer: &Token<'_>, access: &Token<'_>) -> Result<Vec<Tweet>> {
    let bytes = oauth::get(
        api_twitter_soft::HOME_TIMELINE,
        consumer,
        Some(access),
        None,
    )?;
    let last_tweets_json = str::from_utf8(&bytes)?;
    let ts = Tweet::parse_timeline(&last_tweets_json)?;
    Ok(ts)
}
<|endoftext|>


<commit_before>extern crate rustc_serialize;
extern crate redis;

use std::str;
use std::cell::Cell;
use std::thread;
use std::ops::{Deref, Drop};
use std::convert::From;
use rustc_serialize::{json, Decodable, Encodable};
use redis::{Value, RedisResult, ErrorKind, Commands};

pub trait TaskDecodable where Self: Sized {
    fn decode_task(value: &Value) -> RedisResult<Self>;
}

pub trait TaskEncodable {
    fn encode_task(&self) -> Vec<u8>;
}

impl<T: Decodable> TaskDecodable for T {
    fn decode_task(value: &Value) -> RedisResult<T> {
        match value {
            &Value::Data(ref v) => {
                let s = try!(str::from_utf8(&v));
                Ok(try!(json::decode(&s).map_err(|_| (ErrorKind::TypeError, "JSON decode failed"))))

            },
            v @ _ => {
                println!("what do we have here: {:?}", v);
                try!(Err((ErrorKind::TypeError, "Can only decode from a string")))
            }
        }
    }
}

impl<T: Encodable> TaskEncodable for T {
    fn encode_task(&self) -> Vec<u8> {
        json::encode(self).unwrap().into_bytes()
    }
}

pub struct TaskGuard<'a, T: 'a> {
    task: T,
    worker: &'a Queue
}

impl<'a, T> TaskGuard<'a, T> {
    pub fn stop(&self) {
        self.worker.stop();
    }

    pub fn inner(&self) -> &T {
        &self.task
    }
}

impl<'a, T> Deref for TaskGuard<'a, T> {
    type Target = T;

    fn deref(&self) -> &T {
        &self.task
    }
}

impl<'a, T> Drop for TaskGuard<'a, T> {
    fn drop(&mut self) {
        // Pop job from backup queue
        let backup = &self.worker.backup_queue[..];
        let _ : () = self.worker.client.lpop(backup).expect("LPOP from backup queue failed");
    }
}

pub struct Queue {
    queue_name: String,
    backup_queue: String,
    stopped: Cell<bool>,
    pub client: redis::Connection,
}

impl Queue {
    pub fn new(name: String, client: redis::Connection) -> Queue {
        let backup_queue = [thread::current().name().unwrap_or("default".into()), "1"].join(":");
        Queue {
            queue_name: name,
            backup_queue: backup_queue,
            client: client,
            stopped: Cell::new(false),
        }
    }

    pub fn stop(&self) {
        self.stopped.set(true);
    }

    pub fn is_stopped(&self) -> bool {
        self.stopped.get()
    }

    pub fn queue(&self) -> &str {
        &self.queue_name
    }

    pub fn backup_queue(&self) -> &str {
        &self.backup_queue
    }

    pub fn push<T: TaskEncodable>(&self, task: T) {
        let _ : () = self.client.lpush(self.queue(), task.encode_task()).expect("LPUSH failed to enqueue task");
    }

    pub fn next<T: TaskDecodable>(&self) -> Option<RedisResult<TaskGuard<T>>> {
        if self.stopped.get() {
            return None;
        }

        let v;
        {
            let qname = &self.queue_name[..];
            let backup = &self.backup_queue[..];

            v = match self.client.brpoplpush(qname, backup, 0) {
                Ok(v) => v,
                Err(_) => {
                    return Some(Err(From::from((ErrorKind::TypeError, "next failed"))));
                }
            };
        }

        let v = match v {
            v @ Value::Data(_) => v,
            _ => {
                return Some(Err(From::from((ErrorKind::TypeError, "Not a 2-item Bulk reply"))));
            }
        };

        let task = T::decode_task(&v).unwrap();

        Some(Ok(TaskGuard{task: task, worker: self}))
    }
}

#[cfg(test)]
mod test {
    extern crate redis;

    use redis::Commands;
    use super::*;

    #[derive(RustcDecodable, RustcEncodable)]
    struct Job {
        id: u64
    }

    #[test]
    fn decodes_job() {
        let client = redis::Client::open("redis://127.0.0.1/").unwrap();
        let con = client.get_connection().unwrap();

        let _ : () = con.rpush("default", "{\"id\":42}").unwrap();

        let worker = Queue::new("default".into(), con);
        let j = worker.next::<Job>().unwrap().unwrap();
        assert_eq!(42, j.id);
    }

    #[test]
    fn releases_job() {
        let client = redis::Client::open("redis://127.0.0.1/").unwrap();
        let con = client.get_connection().unwrap();
        let worker = Queue::new("default".into(), con);
        let bqueue = worker.backup_queue();

        let client = redis::Client::open("redis://127.0.0.1/").unwrap();
        let con = client.get_connection().unwrap();

        let _ : () = con.lpush("default", "{\"id\":42}").unwrap();

        {
            let j = worker.next::<Job>().unwrap().unwrap();
            assert_eq!(42, j.id);
            let in_backup : Vec<String> = con.lrange(bqueue, 0, -1).unwrap();
            assert_eq!(1, in_backup.len());
            assert_eq!("{\"id\":42}", in_backup[0]);
        }

        let in_backup : Vec<String> = con.lrange(bqueue, 0, -1).unwrap();
        assert_eq!(0, in_backup.len());
    }

    #[test]
    fn can_be_stopped() {
        let client = redis::Client::open("redis://127.0.0.1/").unwrap();
        let con = client.get_connection().unwrap();
        let _ : () = con.del("stopper").unwrap();
        let _ : () = con.lpush("stopper", "{\"id\":1}").unwrap();
        let _ : () = con.lpush("stopper", "{\"id\":2}").unwrap();
        let _ : () = con.lpush("stopper", "{\"id\":3}").unwrap();

        let len : u32 = con.llen("stopper").unwrap();
        assert_eq!(3, len);

        let worker = Queue::new("stopper".into(), con);
        while let Some(task) = worker.next::<Job>() {
            let task = task.unwrap();
            task.stop();
        }

        let client = redis::Client::open("redis://127.0.0.1/").unwrap();
        let con = client.get_connection().unwrap();
        let len : u32 = con.llen("stopper").unwrap();
        assert_eq!(2, len);
    }

    #[test]
    fn can_enqueu() {
        let client = redis::Client::open("redis://127.0.0.1/").unwrap();
        let con = client.get_connection().unwrap();
        let _ : () = con.del("enqueue").unwrap();

        let worker = Queue::new("enqueue".into(), con);

        let client = redis::Client::open("redis://127.0.0.1/").unwrap();
        let con = client.get_connection().unwrap();
        let len : u32 = con.llen("enqueue").unwrap();
        assert_eq!(0, len);

        worker.push(Job{id: 53});

        let con = client.get_connection().unwrap();
        let len : u32 = con.llen("enqueue").unwrap();
        assert_eq!(1, len);

        let j = worker.next::<Job>().unwrap().unwrap();
        assert_eq!(53, j.id);
    }
}
<commit_msg>feat: Get the current size of the queue<commit_after>extern crate rustc_serialize;
extern crate redis;

use std::str;
use std::cell::Cell;
use std::thread;
use std::ops::{Deref, Drop};
use std::convert::From;
use rustc_serialize::{json, Decodable, Encodable};
use redis::{Value, RedisResult, ErrorKind, Commands};

pub trait TaskDecodable where Self: Sized {
    fn decode_task(value: &Value) -> RedisResult<Self>;
}

pub trait TaskEncodable {
    fn encode_task(&self) -> Vec<u8>;
}

impl<T: Decodable> TaskDecodable for T {
    fn decode_task(value: &Value) -> RedisResult<T> {
        match value {
            &Value::Data(ref v) => {
                let s = try!(str::from_utf8(&v));
                Ok(try!(json::decode(&s).map_err(|_| (ErrorKind::TypeError, "JSON decode failed"))))

            },
            v @ _ => {
                println!("what do we have here: {:?}", v);
                try!(Err((ErrorKind::TypeError, "Can only decode from a string")))
            }
        }
    }
}

impl<T: Encodable> TaskEncodable for T {
    fn encode_task(&self) -> Vec<u8> {
        json::encode(self).unwrap().into_bytes()
    }
}

pub struct TaskGuard<'a, T: 'a> {
    task: T,
    worker: &'a Queue
}

impl<'a, T> TaskGuard<'a, T> {
    pub fn stop(&self) {
        self.worker.stop();
    }

    pub fn inner(&self) -> &T {
        &self.task
    }
}

impl<'a, T> Deref for TaskGuard<'a, T> {
    type Target = T;

    fn deref(&self) -> &T {
        &self.task
    }
}

impl<'a, T> Drop for TaskGuard<'a, T> {
    fn drop(&mut self) {
        // Pop job from backup queue
        let backup = &self.worker.backup_queue[..];
        let _ : () = self.worker.client.lpop(backup).expect("LPOP from backup queue failed");
    }
}

pub struct Queue {
    queue_name: String,
    backup_queue: String,
    stopped: Cell<bool>,
    pub client: redis::Connection,
}

impl Queue {
    pub fn new(name: String, client: redis::Connection) -> Queue {
        let backup_queue = [thread::current().name().unwrap_or("default".into()), "1"].join(":");
        Queue {
            queue_name: name,
            backup_queue: backup_queue,
            client: client,
            stopped: Cell::new(false),
        }
    }

    pub fn stop(&self) {
        self.stopped.set(true);
    }

    pub fn is_stopped(&self) -> bool {
        self.stopped.get()
    }

    pub fn queue(&self) -> &str {
        &self.queue_name
    }

    pub fn backup_queue(&self) -> &str {
        &self.backup_queue
    }

    pub fn size(&self) -> u64 {
        self.client.llen(self.queue()).unwrap_or(0)
    }

    pub fn push<T: TaskEncodable>(&self, task: T) {
        let _ : () = self.client.lpush(self.queue(), task.encode_task()).expect("LPUSH failed to enqueue task");
    }

    pub fn next<T: TaskDecodable>(&self) -> Option<RedisResult<TaskGuard<T>>> {
        if self.stopped.get() {
            return None;
        }

        let v;
        {
            let qname = &self.queue_name[..];
            let backup = &self.backup_queue[..];

            v = match self.client.brpoplpush(qname, backup, 0) {
                Ok(v) => v,
                Err(_) => {
                    return Some(Err(From::from((ErrorKind::TypeError, "next failed"))));
                }
            };
        }

        let v = match v {
            v @ Value::Data(_) => v,
            _ => {
                return Some(Err(From::from((ErrorKind::TypeError, "Not a proper reply"))));
            }
        };

        let task = T::decode_task(&v).unwrap();

        Some(Ok(TaskGuard{task: task, worker: self}))
    }
}

#[cfg(test)]
mod test {
    extern crate redis;

    use redis::Commands;
    use super::*;

    #[derive(RustcDecodable, RustcEncodable)]
    struct Job {
        id: u64
    }

    #[test]
    fn decodes_job() {
        let client = redis::Client::open("redis://127.0.0.1/").unwrap();
        let con = client.get_connection().unwrap();
        let con2 = client.get_connection().unwrap();
        let worker = Queue::new("default".into(), con2);

        let _ : () = con.rpush(worker.queue(), "{\"id\":42}").unwrap();

        let j = worker.next::<Job>().unwrap().unwrap();
        assert_eq!(42, j.id);
    }

    #[test]
    fn releases_job() {
        let client = redis::Client::open("redis://127.0.0.1/").unwrap();
        let con = client.get_connection().unwrap();
        let con2 = client.get_connection().unwrap();
        let worker = Queue::new("default".into(), con2);
        let bqueue = worker.backup_queue();

        let _ : () = con.del(bqueue).unwrap();
        let _ : () = con.lpush("default", "{\"id\":42}").unwrap();

        {
            let j = worker.next::<Job>().unwrap().unwrap();
            assert_eq!(42, j.id);
            let in_backup : Vec<String> = con.lrange(bqueue, 0, -1).unwrap();
            assert_eq!(1, in_backup.len());
            assert_eq!("{\"id\":42}", in_backup[0]);
        }

        let in_backup : u32 = con.llen(bqueue).unwrap();
        assert_eq!(0, in_backup);
    }

    #[test]
    fn can_be_stopped() {
        let client = redis::Client::open("redis://127.0.0.1/").unwrap();
        let con = client.get_connection().unwrap();
        let con2 = client.get_connection().unwrap();
        let worker = Queue::new("stopper".into(), con2);

        let _ : () = con.del(worker.queue()).unwrap();
        let _ : () = con.lpush(worker.queue(), "{\"id\":1}").unwrap();
        let _ : () = con.lpush(worker.queue(), "{\"id\":2}").unwrap();
        let _ : () = con.lpush(worker.queue(), "{\"id\":3}").unwrap();

        assert_eq!(3, worker.size());

        while let Some(task) = worker.next::<Job>() {
            let task = task.unwrap();
            task.stop();
        }

        assert_eq!(2, worker.size());
    }

    #[test]
    fn can_enqueu() {
        let client = redis::Client::open("redis://127.0.0.1/").unwrap();
        let con = client.get_connection().unwrap();
        let _ : () = con.del("enqueue").unwrap();

        let worker = Queue::new("enqueue".into(), con);

        assert_eq!(0, worker.size());

        worker.push(Job{id: 53});

        assert_eq!(1, worker.size());

        let j = worker.next::<Job>().unwrap().unwrap();
        assert_eq!(53, j.id);
    }
}
<|endoftext|>


<commit_before>#![feature(proc_macro)]
#![allow(dead_code)]

#[macro_use]
extern crate serde_derive;

extern crate serde_json;

#[macro_use]
extern crate tera;

extern crate iron;
extern crate router;

extern crate serde;

/// # Examples
///
/// Building a template from a context.
/// ```rust
/// fn main() {
///     let mut router = Router::new();
///     router.get("/user", user_handler, "user");
///
///     let mut chain = Chain::new(router);
///     let teng = TeraEngine::new("src/examples/templates/**/*");
///     chain.link_after(teng);
///
///     Iron::new(chain).http("localhost:5000").unwrap();
/// }
///
/// fn user_handler(_: &mut Request) -> IronResult<Response> {
///     let mut resp = Response::new();
///
///     let mut context = Context::new();
///     context.add("username", &"Bob");
///     context.add("numbers", &vec![1, 2, 3]);
///     context.add("bio", &"<script>alert('pwnd');</script>");
///
///     resp.set_mut(Template::new("users/profile.html", TemplateMode::from_context(context)))
///         .set_mut(status::Ok);
///     Ok(resp)
/// }
/// ```
/// # Examples
///
/// Note that serialize requires serde.
/// ```rust
/// #[derive(Serialize)]
/// struct Product {
///     name: String,
///     value: i32,
/// }
///
/// fn produce_handler(_: &mut Request) -> IronResult<Response> {
///     let mut resp = Response::new();
///
///     // Using serialized values
///     let product = Product {
///         name: "Foo".into(),
///         value: 42,
///     };
///     resp.set_mut(Template::new("product.html", TemplateMode::from_serial(&product)))
///         .set_mut(status::Ok);
///     Ok(resp)
/// }
/// ```

use iron::prelude::*;
use iron::{AfterMiddleware, typemap, status};
use iron::modifier::Modifier;
use iron::headers::ContentType;

use tera::{Tera, Context};

use serde::Serialize;
use serde_json::{Value, to_value};

/// There are 2 main ways to pass data to generate a template.
#[derive(Clone)]
pub enum TemplateMode {
    /// TeraContext constructor takes a `Context`
    TeraContext(Context),
    /// Serialized constructor takes a `Value` from `serde_json`
    Serialized(Value),
}

/// TemplateMode should only ever be created from these smart constructors,
/// not with the enums type constructors.
impl TemplateMode {
    pub fn from_context(context: Context) -> TemplateMode {
        TemplateMode::TeraContext(context)
    }
    pub fn from_serial<S: Serialize>(serialized: S) -> TemplateMode {
        TemplateMode::Serialized(to_value(serialized))
    }
}

/// Our template holds a name (path to template) and a mode (constructed with `from_context` or `from_serial`)
#[derive(Clone)]
pub struct Template {
    mode: TemplateMode,
    name: String,
}

impl Template {
    pub fn new(name: &str, mode: TemplateMode) -> Template {
        Template {
            name: name.into(),
            mode: mode,
        }
    }
}

/// TeraEngine holds the Tera struct so that it can be used by many handlers without explicitly passing
pub struct TeraEngine {
    pub tera: Tera,
}

/// `compile_templates!` is used to parse the contents of a dir for all templates.
impl TeraEngine {
    pub fn new(dir: &str) -> TeraEngine {
        TeraEngine { tera: compile_templates!(dir) }
    }
}

impl typemap::Key for TeraEngine {
    type Value = Template;
}

impl Modifier<Response> for Template {
    fn modify(self, resp: &mut Response) {
        resp.extensions.insert::<TeraEngine>(self);
    }
}

/// The middleware implementation for TeraEngine
impl AfterMiddleware for TeraEngine {
    /// This is where all the magic happens. We extract `TeraEngine` from Iron's `Response`,
    /// determine what `TemplateMode` we should render in, and pass the appropriate values to
    /// tera's render methods.
    fn after(&self, _: &mut Request, mut resp: Response) -> IronResult<Response> {
        let wrapper = resp.extensions.remove::<TeraEngine>().and_then(|t| {
            match t.mode {
                TemplateMode::TeraContext(context) => Some(self.tera.render(&t.name, context)),
                TemplateMode::Serialized(value) => Some(self.tera.value_render(&t.name, &value)),
            }
        });
        match wrapper {
            Some(result) => {
                result.map_err(|e| IronError::new(e, status::InternalServerError))
                    .and_then(|page| {
                        if !resp.headers.has::<ContentType>() {
                            resp.headers.set(ContentType::html());
                        }
                        resp.set_mut(page);
                        Ok(resp)
                    })
            }
            None => Ok(resp),
        }
    }

    fn catch(&self, req: &mut Request, mut err: IronError) -> IronResult<Response> {
        err.response = self.after(req, err.response)?;
        Err(err)
    }
}

#[cfg(test)]
mod tests {
    use super::{TeraEngine, Template, TemplateMode};
    use iron::prelude::*;
    use tera::{Tera, Context};

    #[derive(Serialize)]
    struct Product {
        name: String,
        value: i32,
    }

    fn test_resp() -> IronResult<Response> {
        let resp = Response::new();

        let mut context = Context::new();
        context.add("username", &"Foo");
        context.add("bio", &"Bar");
        context.add("numbers", &vec![1, 2, 3]);

        Ok(resp.set(Template::new("users/foo.html", TemplateMode::from_context(context))))
    }

    #[test]
    fn example() {
        let mut resp = test_resp().ok().expect("response expected");

        match resp.get::<TeraEngine>() {
            Ok(h) => {
                assert_eq!(h.name.unwrap(), "users/profile.html".to_string());
                assert_eq!(h.value
                               .as_object()
                               .unwrap()
                               .get(&"Foo".to_string())
                               .unwrap()
                               .as_string()
                               .unwrap(),
                           "Bar");
            }
            _ => panic!("template expected"),
        }
        // let teng = TeraEngine::new("src/test_template/**/*");
        // // Context option 1
        // let mut context = Context::new();
        // context.add("firstname", &"Foo");
        // context.add("lastname", &"Bar");
        //
        // let t = Template::new("index", TemplateMode::TeraContext(context));
        //
        // // Context option 2
        // let mut c2 = Context::new();
        // c2.add("firstname", &"Foo");
        // c2.add("lastname", &"Bar");
        //
        // let t4 = Template::new("index", TemplateMode::from_context(c2));
        //
        // // Using serialized values
        // let product = Product {
        //     name: "Foo".into(),
        //     value: 42,
        // };
        // // option 2
        // let t2 = Template::new("index", TemplateMode::from_serial(&product));
    }
}
<commit_msg>fixed docs<commit_after>//! # Examples
//!
//! Building a template from a context.
//! ```rust
//! fn main() {
//!     let mut router = Router::new();
//!     router.get("/user", user_handler, "user");
//!
//!     let mut chain = Chain::new(router);
//!     let teng = TeraEngine::new("src/examples/templates/**/*");
//!     chain.link_after(teng);
//!
//!     Iron::new(chain).http("localhost:5000").unwrap();
//! }
//!
//! fn user_handler(_: &mut Request) -> IronResult<Response> {
//!     let mut resp = Response::new();
//!
//!     let mut context = Context::new();
//!     context.add("username", &"Bob");
//!     context.add("numbers", &vec![1, 2, 3]);
//!     context.add("bio", &"<script>alert('pwnd');</script>");
//!
//!     resp.set_mut(Template::new("users/profile.html", TemplateMode::from_context(context)))
//!         .set_mut(status::Ok);
//!     Ok(resp)
//! }
//! ```
//! # Examples
//!
//! Note that serialize requires serde.
//! ```rust
//! #[derive(Serialize)]
//! struct Product {
//!     name: String,
//!     value: i32,
//! }
//!
//! fn produce_handler(_: &mut Request) -> IronResult<Response> {
//!     let mut resp = Response::new();
//!
//!     // Using serialized values
//!     let product = Product {
//!         name: "Foo".into(),
//!         value: 42,
//!     };
//!     resp.set_mut(Template::new("product.html", TemplateMode::from_serial(&product)))
//!         .set_mut(status::Ok);
//!     Ok(resp)
//! }
//! ```

#![feature(proc_macro)]
#![allow(dead_code)]

#[macro_use]
extern crate serde_derive;

extern crate serde_json;

#[macro_use]
extern crate tera;

extern crate iron;
extern crate router;

extern crate serde;

use iron::prelude::*;
use iron::{AfterMiddleware, typemap, status};
use iron::modifier::Modifier;
use iron::headers::ContentType;

use tera::{Tera, Context};

use serde::Serialize;
use serde_json::{Value, to_value};

/// There are 2 main ways to pass data to generate a template.
#[derive(Clone)]
pub enum TemplateMode {
    /// TeraContext constructor takes a `Context`
    TeraContext(Context),
    /// Serialized constructor takes a `Value` from `serde_json`
    Serialized(Value),
}

/// TemplateMode should only ever be created from these smart constructors,
/// not with the enums type constructors.
impl TemplateMode {
    pub fn from_context(context: Context) -> TemplateMode {
        TemplateMode::TeraContext(context)
    }
    pub fn from_serial<S: Serialize>(serialized: S) -> TemplateMode {
        TemplateMode::Serialized(to_value(serialized))
    }
}

/// Our template holds a name (path to template) and a mode (constructed with `from_context` or `from_serial`)
#[derive(Clone)]
pub struct Template {
    mode: TemplateMode,
    name: String,
}

impl Template {
    pub fn new(name: &str, mode: TemplateMode) -> Template {
        Template {
            name: name.into(),
            mode: mode,
        }
    }
}

/// TeraEngine holds the Tera struct so that it can be used by many handlers without explicitly passing
pub struct TeraEngine {
    pub tera: Tera,
}

/// `compile_templates!` is used to parse the contents of a dir for all templates.
impl TeraEngine {
    pub fn new(dir: &str) -> TeraEngine {
        TeraEngine { tera: compile_templates!(dir) }
    }
}

impl typemap::Key for TeraEngine {
    type Value = Template;
}

impl Modifier<Response> for Template {
    fn modify(self, resp: &mut Response) {
        resp.extensions.insert::<TeraEngine>(self);
    }
}

/// The middleware implementation for TeraEngine
impl AfterMiddleware for TeraEngine {
    /// This is where all the magic happens. We extract `TeraEngine` from Iron's `Response`,
    /// determine what `TemplateMode` we should render in, and pass the appropriate values to
    /// tera's render methods.
    fn after(&self, _: &mut Request, mut resp: Response) -> IronResult<Response> {
        let wrapper = resp.extensions.remove::<TeraEngine>().and_then(|t| {
            match t.mode {
                TemplateMode::TeraContext(context) => Some(self.tera.render(&t.name, context)),
                TemplateMode::Serialized(value) => Some(self.tera.value_render(&t.name, &value)),
            }
        });
        match wrapper {
            Some(result) => {
                result.map_err(|e| IronError::new(e, status::InternalServerError))
                    .and_then(|page| {
                        if !resp.headers.has::<ContentType>() {
                            resp.headers.set(ContentType::html());
                        }
                        resp.set_mut(page);
                        Ok(resp)
                    })
            }
            None => Ok(resp),
        }
    }

    fn catch(&self, req: &mut Request, mut err: IronError) -> IronResult<Response> {
        err.response = self.after(req, err.response)?;
        Err(err)
    }
}

#[cfg(test)]
mod tests {
    use super::{TeraEngine, Template, TemplateMode};
    use iron::prelude::*;
    use tera::{Tera, Context};

    #[derive(Serialize)]
    struct Product {
        name: String,
        value: i32,
    }

    fn test_resp() -> IronResult<Response> {
        let resp = Response::new();

        let mut context = Context::new();
        context.add("username", &"Foo");
        context.add("bio", &"Bar");
        context.add("numbers", &vec![1, 2, 3]);

        Ok(resp.set(Template::new("users/foo.html", TemplateMode::from_context(context))))
    }

    #[test]
    fn example() {
        let mut resp = test_resp().ok().expect("response expected");

        match resp.get::<TeraEngine>() {
            Ok(h) => {
                assert_eq!(h.name.unwrap(), "users/profile.html".to_string());
                assert_eq!(h.value
                               .as_object()
                               .unwrap()
                               .get(&"Foo".to_string())
                               .unwrap()
                               .as_string()
                               .unwrap(),
                           "Bar");
            }
            _ => panic!("template expected"),
        }
        // let teng = TeraEngine::new("src/test_template/**/*");
        // // Context option 1
        // let mut context = Context::new();
        // context.add("firstname", &"Foo");
        // context.add("lastname", &"Bar");
        //
        // let t = Template::new("index", TemplateMode::TeraContext(context));
        //
        // // Context option 2
        // let mut c2 = Context::new();
        // c2.add("firstname", &"Foo");
        // c2.add("lastname", &"Bar");
        //
        // let t4 = Template::new("index", TemplateMode::from_context(c2));
        //
        // // Using serialized values
        // let product = Product {
        //     name: "Foo".into(),
        //     value: 42,
        // };
        // // option 2
        // let t2 = Template::new("index", TemplateMode::from_serial(&product));
    }
}
<|endoftext|>