<commit_before>#![feature(plugin_registrar, macro_rules, globs)]

extern crate rustc;
extern crate rustc_driver;
extern crate syntax;

use std::io::Command;
use std::io::fs::PathExtensions;
use std::os;
use std::str;
use std::sync::{Once, ONCE_INIT};

use rustc::plugin::Registry;
use syntax::abi;
use syntax::ast;
use syntax::attr;
use syntax::ptr::P;
use syntax::codemap::Span;
use syntax::ext::base::{ExtCtxt, DummyResult};
use syntax::ext::base::MacResult;
use syntax::ext::build::AstBuilder;
use syntax::fold::Folder;
use syntax::parse::parser::Parser;
use syntax::parse::token;
use syntax::parse::token::{special_idents, InternedString};
use syntax::print::pprust;
use syntax::util::small_vector::SmallVector;

use self::State::*;
use self::SystemDeps::*;
use self::Favor::*;

struct LibInfo {
    lib: String,
    state: State,
    deps: Vec<(String, bool)>, // (name, static)
    locs: Vec<Path>,
}

struct MacItems {
    items: Vec<P<ast::Item>>,
}

#[deriving(Copy)]
enum State { Dynamic, Static(SystemDeps) }
#[deriving(Copy)]
enum SystemDeps { SystemDynamic, SystemStatic }
#[deriving(Copy)]
enum Favor { FavorDynamic, FavorStatic }

#[plugin_registrar]
pub fn plugin_registrar(reg: &mut Registry) {
    reg.register_macro("link_config", expand_link_config);
}

fn expand_link_config(ecx: &mut ExtCtxt, span: Span,
                      tts: &[ast::TokenTree]) -> Box<MacResult+'static> {
    macro_rules! try_dummy( ($e:expr) => (
        match $e { Ok(s) => s, Err(()) => return DummyResult::any(span) }
    ) )

    let mut parser = ecx.new_parser_from_tts(tts);
    let (pkg, sp) = try_dummy!(parse_string(ecx, &mut parser));
    let mut favor_dynamic = FavorDynamic;
    let mut dylib_state = Some(Dynamic);
    let mut static_state = Some(Static(SystemDynamic));
    if parser.eat(&token::Comma) && parser.eat(&token::OpenDelim(token::Bracket)) {
        while !parser.eat(&token::CloseDelim(token::Bracket)) {
            parser.eat(&token::Comma);
            let (modifier, sp) = try_dummy!(parse_string(ecx, &mut parser));
            match modifier.as_slice() {
                "only_static" => {
                    dylib_state = None;
                    favor_dynamic = FavorStatic;
                }
                "only_dylib" => {
                    static_state = None;
                    favor_dynamic = FavorDynamic;
                }
                "system_static" => static_state = Some(Static(SystemStatic)),
                "favor_static" => favor_dynamic = FavorStatic,
                s => ecx.span_err(sp, format!("unknown modifier: `{}`",
                                              s).as_slice()),
            }
        }
    }
    if !parser.eat(&token::Eof) {
        ecx.span_err(parser.span, "only one string literal allowed");
        return DummyResult::any(span);
    }

    let dyn = try_dummy!(system_pkgconfig(ecx, sp, pkg.as_slice(), dylib_state));
    let statik = try_dummy!(system_pkgconfig(ecx, sp, pkg.as_slice(), static_state));

    let mut items = Vec::new();
    match dyn {
        Some(info) => items.push(block(ecx, sp, &info, favor_dynamic)),
        None => {}
    }
    match statik {
        Some(info) => items.push(block(ecx, sp, &info, favor_dynamic)),
        None => {}
    }
    box MacItems { items: items } as Box<MacResult>
}

fn system_pkgconfig(ecx: &mut ExtCtxt, sp: Span, pkg: &str,
                    state: Option<State>) -> Result<Option<LibInfo>, ()> {
    let state = match state {
        Some(state) => state,
        None => return Ok(None),
    };
    add_cargo_pkg_config_paths();

    let mut cmd = Command::new("pkg-config");
    cmd.arg(pkg).arg("--libs").env("PKG_CONFIG_ALLOW_SYSTEM_LIBS", "1");
    match state {
        Static(..) => { cmd.arg("--static"); }
        Dynamic => {}
    }
    let out = match cmd.output() {
        Ok(out) => out,
        Err(e) => {
            ecx.span_err(sp, format!("could not run pkg-config: {}", e).as_slice());
            return Err(())
        }
    };
    let stdout = str::from_utf8(out.output.as_slice()).unwrap();
    let stderr = str::from_utf8(out.error.as_slice()).unwrap();
    if !out.status.success() {
        let mut msg = format!("pkg-config did not exit successfully: {}",
                              out.status);
        if stdout.len() > 0 {
            msg.push_str("\n--- stdout\n");
            msg.push_str(stdout);
        }
        if stderr.len() > 0 {
            msg.push_str("\n--- stderr\n");
            msg.push_str(stderr);
        }
        ecx.span_err(sp, msg.as_slice());
        return Err(())
    }

    let mut libs = Vec::new();
    let mut locs = Vec::new();
    for arg in stdout.split(' ').filter(|l| !l.is_empty()) {
        if arg.starts_with("-l") {
            libs.push(arg.slice_from(2));
        } else if arg.starts_with("-L") {
            locs.push(Path::new(arg.slice_from(2).to_string()));
        }
    }

    let allow_static = match state {
        Static(..) => true,
        _ => false,
    };
    let allow_static_system = match state {
        Static(SystemStatic) => true,
        _ => false,
    };

    let cargo_locs = cargo_native_dirs();
    let libs = libs.into_iter().map(|lib| {
        let mut candidates = cargo_locs.iter().chain(locs.iter());
        (lib.to_string(), allow_static && candidates.any(|base| {
            (allow_static_system || !base.as_vec().starts_with(b"/usr")) &&
                (base.join(format!("lib{}.a", lib)).exists() ||
                 base.join(format!("{}.lib", lib)).exists() ||
                 base.join(format!("lib{}.lib", lib)).exists())
        }))
    }).collect();
    Ok(Some(LibInfo {
        lib: pkg.to_string(),
        deps: libs,
        locs: locs,
        state: state,
    }))
}

fn block(ecx: &mut ExtCtxt, sp: Span, info: &LibInfo,
         favor: Favor) -> P<ast::Item> {
    let lib = token::intern_and_get_ident(info.lib.as_slice());
    let s = match favor {
        FavorDynamic => InternedString::new("statik"),
        FavorStatic => InternedString::new("dylib"),
    };
    let cfg = ecx.meta_name_value(sp, s, ast::LitStr(lib, ast::CookedStr));
    let cfg = match (info.state, favor) {
        (Static(..), FavorDynamic) |
        (Dynamic, FavorStatic) => cfg,
        (Dynamic, FavorDynamic) |
        (Static(..), FavorStatic) => {
            ecx.meta_list(sp, InternedString::new("not"), vec![cfg])
        }
    };
    let cfg = ecx.meta_list(sp, InternedString::new("cfg"), vec![cfg]);

    let attrs = vec![ecx.attribute(sp, cfg)].into_iter();
    let attrs = attrs.chain(info.deps.iter().map(|&(ref l, statik)| {
        // Build #[link(name = <l>)]
        let l = token::intern_and_get_ident(l.as_slice());
        let mut items = Vec::new();
        items.push(ecx.meta_name_value(sp, InternedString::new("name"),
                                       ast::LitStr(l, ast::CookedStr)));
        if statik {
            let l = InternedString::new("static");
            items.push(ecx.meta_name_value(sp, InternedString::new("kind"),
                                           ast::LitStr(l, ast::CookedStr)));
        }
        let list = ecx.meta_list(sp, InternedString::new("link"), items);
        ecx.attribute(sp, list)
    }));
    let attrs = attrs.chain(info.locs.iter().map(|l| {
        let l = token::intern_and_get_ident(format!("-L{}", l.display()).as_slice());
        let args = ecx.meta_name_value(sp, InternedString::new("link_args"),
                                       ast::LitStr(l, ast::CookedStr));
        ecx.attribute(sp, args)
    }));
    let attrs = attrs.map(|attr| {
        attr::mark_used(&attr);
        attr
    });

    ecx.item(sp, special_idents::invalid, attrs.collect(),
             ast::ItemForeignMod(ast::ForeignMod {
        abi: abi::C,
        view_items: Vec::new(),
        items: Vec::new(),
    }))
}

fn parse_string(ecx: &mut ExtCtxt,
                parser: &mut Parser) -> Result<(String, Span), ()> {
    let entry = ecx.expander().fold_expr(parser.parse_expr());
    match entry.node {
        ast::ExprLit(ref lit) => {
            match lit.node {
                ast::LitStr(ref s, _) => return Ok((s.to_string(), entry.span)),
                _ => {}
            }
        }
        _ => {}
    }
    ecx.span_err(entry.span, format!(
        "expected string literal but got `{}`",
        pprust::expr_to_string(&*entry)).as_slice());
    Err(())
}

impl MacResult for MacItems {
    fn make_items(self: Box<MacItems>) -> Option<SmallVector<P<ast::Item>>> {
        Some(self.items.into_iter().collect())
    }
}

// lol hax
fn cargo_native_dirs() -> Vec<Path> {
    match rustc_driver::handle_options(os::args()) {
        Some(matches) => {
            matches.opt_strs("L").into_iter().filter_map(|s| {
                if s.as_slice().contains("native") {
                    Some(Path::new(s))
                } else {
                    None
                }
            }).collect()
        }
        None => Vec::new()
    }
}

fn add_cargo_pkg_config_paths() {
    static mut DONE: Once = ONCE_INIT;
    unsafe { DONE.doit(add_cargo_pkg_config_paths) }

    fn add_cargo_pkg_config_paths() {
        let path = os::getenv_as_bytes("PKG_CONFIG_PATH").unwrap_or(Vec::new());
        let mut pkg_config_path = os::split_paths(path.as_slice());
        pkg_config_path.push_all(cargo_native_dirs().as_slice());
        let pkg_config_path = os::join_paths(pkg_config_path.as_slice())
                                 .unwrap();
        os::setenv("PKG_CONFIG_PATH", pkg_config_path.as_slice());
    }
}
<commit_msg>Fixes build against rustc 0.13.0-nightly cc19e3380 2014-12-20<commit_after>#![feature(plugin_registrar, macro_rules, globs)]

extern crate rustc;
extern crate rustc_driver;
extern crate syntax;

use std::io::Command;
use std::io::fs::PathExtensions;
use std::os;
use std::str;
use std::sync::{Once, ONCE_INIT};

use rustc::plugin::Registry;
use syntax::abi;
use syntax::ast;
use syntax::attr;
use syntax::ptr::P;
use syntax::codemap::Span;
use syntax::ext::base::{ExtCtxt, DummyResult};
use syntax::ext::base::MacResult;
use syntax::ext::build::AstBuilder;
use syntax::fold::Folder;
use syntax::parse::parser::Parser;
use syntax::parse::token;
use syntax::parse::token::{special_idents, InternedString};
use syntax::print::pprust;
use syntax::util::small_vector::SmallVector;

use self::State::*;
use self::SystemDeps::*;
use self::Favor::*;

struct LibInfo {
    lib: String,
    state: State,
    deps: Vec<(String, bool)>, // (name, static)
    locs: Vec<Path>,
}

struct MacItems {
    items: Vec<P<ast::Item>>,
}

#[deriving(Copy)]
enum State { Dynamic, Static(SystemDeps) }
#[deriving(Copy)]
enum SystemDeps { SystemDynamic, SystemStatic }
#[deriving(Copy)]
enum Favor { FavorDynamic, FavorStatic }

#[plugin_registrar]
pub fn plugin_registrar(reg: &mut Registry) {
    reg.register_macro("link_config", expand_link_config);
}

fn expand_link_config(ecx: &mut ExtCtxt, span: Span,
                      tts: &[ast::TokenTree]) -> Box<MacResult+'static> {
    macro_rules! try_dummy( ($e:expr) => (
        match $e { Ok(s) => s, Err(()) => return DummyResult::any(span) }
    ) );

    let mut parser = ecx.new_parser_from_tts(tts);
    let (pkg, sp) = try_dummy!(parse_string(ecx, &mut parser));
    let mut favor_dynamic = FavorDynamic;
    let mut dylib_state = Some(Dynamic);
    let mut static_state = Some(Static(SystemDynamic));
    if parser.eat(&token::Comma) && parser.eat(&token::OpenDelim(token::Bracket)) {
        while !parser.eat(&token::CloseDelim(token::Bracket)) {
            parser.eat(&token::Comma);
            let (modifier, sp) = try_dummy!(parse_string(ecx, &mut parser));
            match modifier.as_slice() {
                "only_static" => {
                    dylib_state = None;
                    favor_dynamic = FavorStatic;
                }
                "only_dylib" => {
                    static_state = None;
                    favor_dynamic = FavorDynamic;
                }
                "system_static" => static_state = Some(Static(SystemStatic)),
                "favor_static" => favor_dynamic = FavorStatic,
                s => ecx.span_err(sp, format!("unknown modifier: `{}`",
                                              s).as_slice()),
            }
        }
    }
    if !parser.eat(&token::Eof) {
        ecx.span_err(parser.span, "only one string literal allowed");
        return DummyResult::any(span);
    }

    let dyn = try_dummy!(system_pkgconfig(ecx, sp, pkg.as_slice(), dylib_state));
    let statik = try_dummy!(system_pkgconfig(ecx, sp, pkg.as_slice(), static_state));

    let mut items = Vec::new();
    match dyn {
        Some(info) => items.push(block(ecx, sp, &info, favor_dynamic)),
        None => {}
    }
    match statik {
        Some(info) => items.push(block(ecx, sp, &info, favor_dynamic)),
        None => {}
    }
    box MacItems { items: items } as Box<MacResult>
}

fn system_pkgconfig(ecx: &mut ExtCtxt, sp: Span, pkg: &str,
                    state: Option<State>) -> Result<Option<LibInfo>, ()> {
    let state = match state {
        Some(state) => state,
        None => return Ok(None),
    };
    add_cargo_pkg_config_paths();

    let mut cmd = Command::new("pkg-config");
    cmd.arg(pkg).arg("--libs").env("PKG_CONFIG_ALLOW_SYSTEM_LIBS", "1");
    match state {
        Static(..) => { cmd.arg("--static"); }
        Dynamic => {}
    }
    let out = match cmd.output() {
        Ok(out) => out,
        Err(e) => {
            ecx.span_err(sp, format!("could not run pkg-config: {}", e).as_slice());
            return Err(())
        }
    };
    let stdout = str::from_utf8(out.output.as_slice()).unwrap();
    let stderr = str::from_utf8(out.error.as_slice()).unwrap();
    if !out.status.success() {
        let mut msg = format!("pkg-config did not exit successfully: {}",
                              out.status);
        if stdout.len() > 0 {
            msg.push_str("\n--- stdout\n");
            msg.push_str(stdout);
        }
        if stderr.len() > 0 {
            msg.push_str("\n--- stderr\n");
            msg.push_str(stderr);
        }
        ecx.span_err(sp, msg.as_slice());
        return Err(())
    }

    let mut libs = Vec::new();
    let mut locs = Vec::new();
    for arg in stdout.split(' ').filter(|l| !l.is_empty()) {
        if arg.starts_with("-l") {
            libs.push(arg.slice_from(2));
        } else if arg.starts_with("-L") {
            locs.push(Path::new(arg.slice_from(2).to_string()));
        }
    }

    let allow_static = match state {
        Static(..) => true,
        _ => false,
    };
    let allow_static_system = match state {
        Static(SystemStatic) => true,
        _ => false,
    };

    let cargo_locs = cargo_native_dirs();
    let libs = libs.into_iter().map(|lib| {
        let mut candidates = cargo_locs.iter().chain(locs.iter());
        (lib.to_string(), allow_static && candidates.any(|base| {
            (allow_static_system || !base.as_vec().starts_with(b"/usr")) &&
                (base.join(format!("lib{}.a", lib)).exists() ||
                 base.join(format!("{}.lib", lib)).exists() ||
                 base.join(format!("lib{}.lib", lib)).exists())
        }))
    }).collect();
    Ok(Some(LibInfo {
        lib: pkg.to_string(),
        deps: libs,
        locs: locs,
        state: state,
    }))
}

fn block(ecx: &mut ExtCtxt, sp: Span, info: &LibInfo,
         favor: Favor) -> P<ast::Item> {
    let lib = token::intern_and_get_ident(info.lib.as_slice());
    let s = match favor {
        FavorDynamic => InternedString::new("statik"),
        FavorStatic => InternedString::new("dylib"),
    };
    let cfg = ecx.meta_name_value(sp, s, ast::LitStr(lib, ast::CookedStr));
    let cfg = match (info.state, favor) {
        (Static(..), FavorDynamic) |
        (Dynamic, FavorStatic) => cfg,
        (Dynamic, FavorDynamic) |
        (Static(..), FavorStatic) => {
            ecx.meta_list(sp, InternedString::new("not"), vec![cfg])
        }
    };
    let cfg = ecx.meta_list(sp, InternedString::new("cfg"), vec![cfg]);

    let attrs = vec![ecx.attribute(sp, cfg)].into_iter();
    let attrs = attrs.chain(info.deps.iter().map(|&(ref l, statik)| {
        // Build #[link(name = <l>)]
        let l = token::intern_and_get_ident(l.as_slice());
        let mut items = Vec::new();
        items.push(ecx.meta_name_value(sp, InternedString::new("name"),
                                       ast::LitStr(l, ast::CookedStr)));
        if statik {
            let l = InternedString::new("static");
            items.push(ecx.meta_name_value(sp, InternedString::new("kind"),
                                           ast::LitStr(l, ast::CookedStr)));
        }
        let list = ecx.meta_list(sp, InternedString::new("link"), items);
        ecx.attribute(sp, list)
    }));
    let attrs = attrs.chain(info.locs.iter().map(|l| {
        let l = token::intern_and_get_ident(format!("-L{}", l.display()).as_slice());
        let args = ecx.meta_name_value(sp, InternedString::new("link_args"),
                                       ast::LitStr(l, ast::CookedStr));
        ecx.attribute(sp, args)
    }));
    let attrs = attrs.map(|attr| {
        attr::mark_used(&attr);
        attr
    });

    ecx.item(sp, special_idents::invalid, attrs.collect(),
             ast::ItemForeignMod(ast::ForeignMod {
        abi: abi::C,
        view_items: Vec::new(),
        items: Vec::new(),
    }))
}

fn parse_string(ecx: &mut ExtCtxt,
                parser: &mut Parser) -> Result<(String, Span), ()> {
    let entry = ecx.expander().fold_expr(parser.parse_expr());
    match entry.node {
        ast::ExprLit(ref lit) => {
            match lit.node {
                ast::LitStr(ref s, _) => return Ok((s.to_string(), entry.span)),
                _ => {}
            }
        }
        _ => {}
    }
    ecx.span_err(entry.span, format!(
        "expected string literal but got `{}`",
        pprust::expr_to_string(&*entry)).as_slice());
    Err(())
}

impl MacResult for MacItems {
    fn make_items(self: Box<MacItems>) -> Option<SmallVector<P<ast::Item>>> {
        Some(self.items.into_iter().collect())
    }
}

// lol hax
fn cargo_native_dirs() -> Vec<Path> {
    match rustc_driver::handle_options(os::args()) {
        Some(matches) => {
            matches.opt_strs("L").into_iter().filter_map(|s| {
                if s.as_slice().contains("native") {
                    Some(Path::new(s))
                } else {
                    None
                }
            }).collect()
        }
        None => Vec::new()
    }
}

fn add_cargo_pkg_config_paths() {
    static mut DONE: Once = ONCE_INIT;
    unsafe { DONE.doit(add_cargo_pkg_config_paths) }

    fn add_cargo_pkg_config_paths() {
        let path = os::getenv_as_bytes("PKG_CONFIG_PATH").unwrap_or(Vec::new());
        let mut pkg_config_path = os::split_paths(path.as_slice());
        pkg_config_path.push_all(cargo_native_dirs().as_slice());
        let pkg_config_path = os::join_paths(pkg_config_path.as_slice())
                                 .unwrap();
        os::setenv("PKG_CONFIG_PATH", pkg_config_path.as_slice());
    }
}
<|endoftext|>


<commit_before>use std::collections::HashMap;

struct LSystem {
    alphabet: Vec<char>,
    constants: Vec<char>,
    start: String,
    rules: HashMap<char, String>,
}

impl LSystem {
    /// Some guarantees of a LSystem:
    /// 1. Every char in start is in alphabet
    /// 2. Given a rule X -> Y, X and Y are in alphabet
    /// 3. Each char in alphabet has a rule that maps it to something else
    ///   -> by default a char maps to itself, but this can be overwriten with
    ///   the `push` method
    /// See https://en.wikipedia.org/wiki/L-system for more details

    pub fn new(start: String) -> LSystem {
        // push chars in start to alphabet
        // and make them map to themselves in a rule
        let mut alphabet: Vec<char> = Vec::new();
        let mut rules: HashMap<char, String> = HashMap::new();
        for c in start.chars() {
            if !alphabet.contains(&c) {
                alphabet.push(c);
                rules.insert(c, c.to_string());
            }
        }

        LSystem {
            alphabet: alphabet,
            constants: Vec::new(),
            start: start,
            rules: rules,
        }
    }

    pub fn to_string(&self) -> String {
        self.start.clone()
    }

    /// Iterate to the next LSystem string, following all rules
    pub fn next(&mut self) -> LSystem {
        let mut next = String::from("");
        for c in self.start.chars() {
            next.push_str(self.get(c));
        }

        LSystem {
            alphabet: self.alphabet.clone(),
            constants: self.constants.clone(),
            start: next,
            rules: self.rules.clone(),
        }
    }

    /// Add a character to the alphabet with the default 'identity rule'
    pub fn add(&mut self, c: char) {
        if !self.alphabet.contains(&c) {
            self.alphabet.push(c);
            self.rules.insert(c, c.to_string());
        }
    }

    /// Helper function for push
    fn overwrite_rule(&mut self, key: &char, value: &String) {
        *self.rules.get_mut(key).unwrap() = value.to_owned();
    }

    /// Add a constant to the LSystem
    /// Constants always map to themselves and cannot be changed
    pub fn add_constant(&mut self, c: char) {
        self.add(c);
        self.constants.push(c);
    }

    /// Add a new rule to the LSystem
    /// If the values in the rule do not exist, they are added
    pub fn push(&mut self, rule: HashMap<char, String>) {
        for (key, value) in &rule {
            // Make sure key is not a constant
            if !self.constants.contains(&key) {
                for c in value.chars() {
                    self.add(c);
                }
                if !self.rules.contains_key(key) {
                    self.add(*key);
                }
                self.overwrite_rule(key, value);
            }
        }
    }

    /// Returns the rule for which key maps to
    pub fn get(&self, key: char) -> &String {
        &self.rules[&key]
    }
}

#[cfg(test)]
mod tests {
    use std::collections::HashMap;
    use LSystem;

    #[test]
    fn test_new_should_have_correct_alphabet() {
        let lsys: LSystem = LSystem::new("AB".to_string());
        assert!(lsys.alphabet.contains(&'A'));
    }

    #[test]
    fn test_new_should_have_correct_start() {
        let lsys: LSystem = LSystem::new("AB".to_string());
        assert_eq!(lsys.start, "AB");
    }

    #[test]
    fn test_new_should_not_have_duplicate_alphabet_chars() {
        let lsys: LSystem = LSystem::new("AA".to_string());
        assert_eq!(lsys.alphabet.len(), 1);
    }

    #[test]
    fn test_new_should_add_default_rules() {
        let lsys: LSystem = LSystem::new("A".to_string());
        assert_eq!(*lsys.get('A'), "A");
    }

    #[test]
    fn test_add_should_add_to_alphabet() {
        let mut lsys: LSystem = LSystem::new("A".to_string());
        lsys.add('B');
        assert!(lsys.alphabet.contains(&'B'));
    }

    #[test]
    fn test_add_should_add_default_rule() {
        let mut lsys: LSystem = LSystem::new("A".to_string());
        lsys.add('B');
        assert_eq!(*lsys.get('B'), "B");
    }

    #[test]
    fn test_add_constant_should_add_to_constants() {
        let mut lsys: LSystem = LSystem::new("A".to_string());
        lsys.add_constant('B');
        assert!(lsys.constants.contains(&'B'));
    }

    #[test]
    fn test_add_constant_should_add_to_alphabet() {
        let mut lsys: LSystem = LSystem::new("A".to_string());
        lsys.add_constant('B');
        assert!(lsys.alphabet.contains(&'B'));
    }

    #[test]
    fn test_add_constant_should_add_default_rule() {
        let mut lsys: LSystem = LSystem::new("A".to_string());
        lsys.add_constant('B');
        assert_eq!(*lsys.get('B'), "B");
    }

    #[test]
    fn test_push_should_overwrite_existing_rule() {
        let mut lsys: LSystem = LSystem::new("A".to_string());
        let mut rule: HashMap<char, String> = HashMap::new();
        rule.insert('A', "B".to_string());
        lsys.push(rule);
        assert_eq!(*lsys.get('A'), "B");
    }

    #[test]
    fn test_push_should_add_to_alphabet() {
        let mut lsys: LSystem = LSystem::new("A".to_string());
        let mut rule: HashMap<char, String> = HashMap::new();
        rule.insert('A', "B".to_string());
        lsys.push(rule);
        assert!(lsys.alphabet.contains(&'B'));
    }

    #[test]
    fn test_push_should_add_default_rules_for_new_chars() {
        let mut lsys: LSystem = LSystem::new("A".to_string());
        let mut rule: HashMap<char, String> = HashMap::new();
        rule.insert('A', "B".to_string());
        lsys.push(rule);
        assert_eq!(*lsys.get('B'), "B");
    }

    #[test]
    fn test_push_should_not_overwrite_constants() {
        let mut lsys: LSystem = LSystem::new("A".to_string());
        lsys.add_constant('A');
        let mut rule: HashMap<char, String> = HashMap::new();
        rule.insert('A', "B".to_string());
        lsys.push(rule);
        assert_eq!(*lsys.get('A'), "A");
    }

    #[test]
    fn test_push_should_work_with_multiple_rules() {
        let mut lsys: LSystem = LSystem::new("A".to_string());
        let mut rule: HashMap<char, String> = HashMap::new();
        rule.insert('A', "AB".to_string());
        rule.insert('B', "A".to_string());
        lsys.push(rule);
        assert_eq!(*lsys.get('B'), "A");
        assert_eq!(*lsys.get('A'), "AB");
    }

    #[test]
    fn test_next_with_simple_rules_should_have_correct_start() {
        let mut lsys: LSystem = LSystem::new("A".to_string());
        let mut rule: HashMap<char, String> = HashMap::new();
        rule.insert('A', "B".to_string());
        lsys.push(rule);
        let next: LSystem = lsys.next();
        assert_eq!(next.start, "B");
    }

    #[test]
    fn test_next_with_complex_rules_should_have_correct_start() {
        let mut lsys: LSystem = LSystem::new("AB".to_string());
        let mut rule: HashMap<char, String> = HashMap::new();
        rule.insert('A', "AB".to_string());
        rule.insert('B', "A".to_string());
        lsys.push(rule);
        let next: LSystem = lsys.next();
        assert_eq!(next.start, "ABA");
    }

    #[test]
    fn test_next_should_work_in_chains() {
        let mut lsys: LSystem = LSystem::new("AB".to_string());
        let mut rule: HashMap<char, String> = HashMap::new();
        rule.insert('A', "AB".to_string());
        rule.insert('B', "A".to_string());
        lsys.push(rule);
        let next: LSystem = lsys.next().next();
        assert_eq!(next.start, "ABAAB");
    }

    #[test]
    fn test_to_string_should_return_start_string() {
        let lsys: LSystem = LSystem::new("AB".to_string());
        assert_eq!(lsys.to_string(), "AB");
    }
}
<commit_msg>Made LSystem struct public<commit_after>use std::collections::HashMap;

pub struct LSystem {
    alphabet: Vec<char>,
    constants: Vec<char>,
    start: String,
    rules: HashMap<char, String>,
}

impl LSystem {
    /// Some guarantees of a LSystem:
    /// 1. Every char in start is in alphabet
    /// 2. Given a rule X -> Y, X and Y are in alphabet
    /// 3. Each char in alphabet has a rule that maps it to something else
    ///   -> by default a char maps to itself, but this can be overwriten with
    ///   the `push` method
    /// See https://en.wikipedia.org/wiki/L-system for more details

    pub fn new(start: String) -> LSystem {
        // push chars in start to alphabet
        // and make them map to themselves in a rule
        let mut alphabet: Vec<char> = Vec::new();
        let mut rules: HashMap<char, String> = HashMap::new();
        for c in start.chars() {
            if !alphabet.contains(&c) {
                alphabet.push(c);
                rules.insert(c, c.to_string());
            }
        }

        LSystem {
            alphabet: alphabet,
            constants: Vec::new(),
            start: start,
            rules: rules,
        }
    }

    pub fn to_string(&self) -> String {
        self.start.clone()
    }

    /// Iterate to the next LSystem string, following all rules
    pub fn next(&mut self) -> LSystem {
        let mut next = String::from("");
        for c in self.start.chars() {
            next.push_str(self.get(c));
        }

        LSystem {
            alphabet: self.alphabet.clone(),
            constants: self.constants.clone(),
            start: next,
            rules: self.rules.clone(),
        }
    }

    /// Add a character to the alphabet with the default 'identity rule'
    pub fn add(&mut self, c: char) {
        if !self.alphabet.contains(&c) {
            self.alphabet.push(c);
            self.rules.insert(c, c.to_string());
        }
    }

    /// Helper function for push
    fn overwrite_rule(&mut self, key: &char, value: &String) {
        *self.rules.get_mut(key).unwrap() = value.to_owned();
    }

    /// Add a constant to the LSystem
    /// Constants always map to themselves and cannot be changed
    pub fn add_constant(&mut self, c: char) {
        self.add(c);
        self.constants.push(c);
    }

    /// Add a new rule to the LSystem
    /// If the values in the rule do not exist, they are added
    pub fn push(&mut self, rule: HashMap<char, String>) {
        for (key, value) in &rule {
            // Make sure key is not a constant
            if !self.constants.contains(&key) {
                for c in value.chars() {
                    self.add(c);
                }
                if !self.rules.contains_key(key) {
                    self.add(*key);
                }
                self.overwrite_rule(key, value);
            }
        }
    }

    /// Returns the rule for which key maps to
    pub fn get(&self, key: char) -> &String {
        &self.rules[&key]
    }
}

#[cfg(test)]
mod tests {
    use std::collections::HashMap;
    use LSystem;

    #[test]
    fn test_new_should_have_correct_alphabet() {
        let lsys: LSystem = LSystem::new("AB".to_string());
        assert!(lsys.alphabet.contains(&'A'));
    }

    #[test]
    fn test_new_should_have_correct_start() {
        let lsys: LSystem = LSystem::new("AB".to_string());
        assert_eq!(lsys.start, "AB");
    }

    #[test]
    fn test_new_should_not_have_duplicate_alphabet_chars() {
        let lsys: LSystem = LSystem::new("AA".to_string());
        assert_eq!(lsys.alphabet.len(), 1);
    }

    #[test]
    fn test_new_should_add_default_rules() {
        let lsys: LSystem = LSystem::new("A".to_string());
        assert_eq!(*lsys.get('A'), "A");
    }

    #[test]
    fn test_add_should_add_to_alphabet() {
        let mut lsys: LSystem = LSystem::new("A".to_string());
        lsys.add('B');
        assert!(lsys.alphabet.contains(&'B'));
    }

    #[test]
    fn test_add_should_add_default_rule() {
        let mut lsys: LSystem = LSystem::new("A".to_string());
        lsys.add('B');
        assert_eq!(*lsys.get('B'), "B");
    }

    #[test]
    fn test_add_constant_should_add_to_constants() {
        let mut lsys: LSystem = LSystem::new("A".to_string());
        lsys.add_constant('B');
        assert!(lsys.constants.contains(&'B'));
    }

    #[test]
    fn test_add_constant_should_add_to_alphabet() {
        let mut lsys: LSystem = LSystem::new("A".to_string());
        lsys.add_constant('B');
        assert!(lsys.alphabet.contains(&'B'));
    }

    #[test]
    fn test_add_constant_should_add_default_rule() {
        let mut lsys: LSystem = LSystem::new("A".to_string());
        lsys.add_constant('B');
        assert_eq!(*lsys.get('B'), "B");
    }

    #[test]
    fn test_push_should_overwrite_existing_rule() {
        let mut lsys: LSystem = LSystem::new("A".to_string());
        let mut rule: HashMap<char, String> = HashMap::new();
        rule.insert('A', "B".to_string());
        lsys.push(rule);
        assert_eq!(*lsys.get('A'), "B");
    }

    #[test]
    fn test_push_should_add_to_alphabet() {
        let mut lsys: LSystem = LSystem::new("A".to_string());
        let mut rule: HashMap<char, String> = HashMap::new();
        rule.insert('A', "B".to_string());
        lsys.push(rule);
        assert!(lsys.alphabet.contains(&'B'));
    }

    #[test]
    fn test_push_should_add_default_rules_for_new_chars() {
        let mut lsys: LSystem = LSystem::new("A".to_string());
        let mut rule: HashMap<char, String> = HashMap::new();
        rule.insert('A', "B".to_string());
        lsys.push(rule);
        assert_eq!(*lsys.get('B'), "B");
    }

    #[test]
    fn test_push_should_not_overwrite_constants() {
        let mut lsys: LSystem = LSystem::new("A".to_string());
        lsys.add_constant('A');
        let mut rule: HashMap<char, String> = HashMap::new();
        rule.insert('A', "B".to_string());
        lsys.push(rule);
        assert_eq!(*lsys.get('A'), "A");
    }

    #[test]
    fn test_push_should_work_with_multiple_rules() {
        let mut lsys: LSystem = LSystem::new("A".to_string());
        let mut rule: HashMap<char, String> = HashMap::new();
        rule.insert('A', "AB".to_string());
        rule.insert('B', "A".to_string());
        lsys.push(rule);
        assert_eq!(*lsys.get('B'), "A");
        assert_eq!(*lsys.get('A'), "AB");
    }

    #[test]
    fn test_next_with_simple_rules_should_have_correct_start() {
        let mut lsys: LSystem = LSystem::new("A".to_string());
        let mut rule: HashMap<char, String> = HashMap::new();
        rule.insert('A', "B".to_string());
        lsys.push(rule);
        let next: LSystem = lsys.next();
        assert_eq!(next.start, "B");
    }

    #[test]
    fn test_next_with_complex_rules_should_have_correct_start() {
        let mut lsys: LSystem = LSystem::new("AB".to_string());
        let mut rule: HashMap<char, String> = HashMap::new();
        rule.insert('A', "AB".to_string());
        rule.insert('B', "A".to_string());
        lsys.push(rule);
        let next: LSystem = lsys.next();
        assert_eq!(next.start, "ABA");
    }

    #[test]
    fn test_next_should_work_in_chains() {
        let mut lsys: LSystem = LSystem::new("AB".to_string());
        let mut rule: HashMap<char, String> = HashMap::new();
        rule.insert('A', "AB".to_string());
        rule.insert('B', "A".to_string());
        lsys.push(rule);
        let next: LSystem = lsys.next().next();
        assert_eq!(next.start, "ABAAB");
    }

    #[test]
    fn test_to_string_should_return_start_string() {
        let lsys: LSystem = LSystem::new("AB".to_string());
        assert_eq!(lsys.to_string(), "AB");
    }
}
<|endoftext|>


<commit_before>#![warn(missing_docs)]

extern crate hyper;
extern crate mime;
extern crate mime_guess;
extern crate mustache;
extern crate rustc_serialize;
extern crate term;
extern crate time;

use std::io;
use std::fs;
use std::fs::File;
use std::net::ToSocketAddrs;
use std::path::PathBuf;

use hyper::header::ContentType as HyperContentType;
use hyper::uri::RequestUri as HyperRequestUri;
use hyper::server::Server as HyperServer;

use service::log::LogProvider;

pub mod input;
pub mod output;
pub mod route;
pub mod service;

/// Starts a server with the given router.
///
/// # Parameters
///
/// - `router`: The list of routes that are handled dynamically. You are encouraged to use the
///             `router!` macro to build a router.
///
/// - `static_files`: A path to the directory containing the static files to serve.
///
/// - `services`: Configuration for the various services accessible in the dynamic routes.
///
/// # Example
///
/// ```no_run
/// # #[macro_use] extern crate rouille;
/// # fn main() {
/// # fn handler(_: rouille::input::Ignore) -> rouille::output::PlainTextOutput { panic!() }
/// use rouille::service::StaticServices;
/// use rouille::service::TemplatesCache;
///
/// let router = router! {
///     GET "/" => handler as fn(_) -> _
/// };
///
/// let services = StaticServices {
///     templates: TemplatesCache::new("./templates"),
///     .. Default::default()
/// };
///
/// rouille::start("0.0.0.0:8000", router, "static", services);
/// # }
/// ```
///
pub fn start<T, P>(addr: T, router: route::Router, static_files: P,
                   services: service::StaticServices)
                   where T: ToSocketAddrs, P: Into<PathBuf>
{
    let handler = RequestHandler {
        router: router,
        static_files: static_files.into(),
        static_services: services,
    };

    let server = HyperServer::http(addr).unwrap();
    let _ = server.handle(handler).unwrap();
}

struct RequestHandler {
    router: route::Router,
    static_files: PathBuf,
    static_services: service::StaticServices,
}

impl hyper::server::Handler for RequestHandler {
    fn handle<'a, 'k>(&'a self, request: hyper::server::request::Request<'a, 'k>,
                      response: hyper::server::response::Response<'a, hyper::net::Fresh>)
    {
        let time_before = time::precise_time_ns();
        let (method, uri) = (request.method.clone(), request.uri.clone());

        // handling static files
        if let HyperRequestUri::AbsolutePath(ref url) = request.uri {
            let possible_file = self.static_files.join(&url[1..]);      // TODO: this is a dirty hack to remove the leading `/`

            // FIXME (SECURITY): check with `relative_from` that we're still in `self.static_files`
            //                   once the function is stable

            if fs::metadata(&possible_file).map(|d| d.is_file()).ok().unwrap_or(false) {
                if let Ok(mut file) = File::open(&possible_file) {
                    let mut response = response;
                    let mime = mime_guess::guess_mime_type(&possible_file);
                    response.headers_mut().set(HyperContentType(mime));

                    if let Ok(mut response) = response.start() {
                        let _ = io::copy(&mut file, &mut response);
                    }

                    let time_after = time::precise_time_ns();
                    self.static_services.logs.log_request(&method, &uri, time_after - time_before);
                    return;
                }
            }
        }

        for route in self.router.routes.iter() {
            if !route.matches(&request) {
                continue;
            }

            match route.handler {
                route::Handler::Static(_) => unimplemented!(),
                route::Handler::Dynamic(ref handler) => {
                    handler.call(request, response, &self.static_services);
                    break;
                },
            }
        }

        let time_after = time::precise_time_ns();
        self.static_services.logs.log_request(&method, &uri, time_after - time_before);
    }
}
<commit_msg>Now adding charset=utf8 for text content types<commit_after>#![warn(missing_docs)]

extern crate hyper;
extern crate mime;
extern crate mime_guess;
extern crate mustache;
extern crate rustc_serialize;
extern crate term;
extern crate time;

use std::io;
use std::fs;
use std::fs::File;
use std::net::ToSocketAddrs;
use std::path::PathBuf;

use hyper::mime::Mime as HyperMime;
use hyper::mime::TopLevel as HyperMimeTopLevel;
use hyper::mime::Attr as HyperMimeAttr;
use hyper::mime::Value as HyperMimeValue;
use hyper::header::ContentType as HyperContentType;
use hyper::uri::RequestUri as HyperRequestUri;
use hyper::server::Server as HyperServer;

use service::log::LogProvider;

pub mod input;
pub mod output;
pub mod route;
pub mod service;

/// Starts a server with the given router.
///
/// # Parameters
///
/// - `router`: The list of routes that are handled dynamically. You are encouraged to use the
///             `router!` macro to build a router.
///
/// - `static_files`: A path to the directory containing the static files to serve.
///
/// - `services`: Configuration for the various services accessible in the dynamic routes.
///
/// # Example
///
/// ```no_run
/// # #[macro_use] extern crate rouille;
/// # fn main() {
/// # fn handler(_: rouille::input::Ignore) -> rouille::output::PlainTextOutput { panic!() }
/// use rouille::service::StaticServices;
/// use rouille::service::TemplatesCache;
///
/// let router = router! {
///     GET "/" => handler as fn(_) -> _
/// };
///
/// let services = StaticServices {
///     templates: TemplatesCache::new("./templates"),
///     .. Default::default()
/// };
///
/// rouille::start("0.0.0.0:8000", router, "static", services);
/// # }
/// ```
///
pub fn start<T, P>(addr: T, router: route::Router, static_files: P,
                   services: service::StaticServices)
                   where T: ToSocketAddrs, P: Into<PathBuf>
{
    let handler = RequestHandler {
        router: router,
        static_files: static_files.into(),
        static_services: services,
    };

    let server = HyperServer::http(addr).unwrap();
    let _ = server.handle(handler).unwrap();
}

struct RequestHandler {
    router: route::Router,
    static_files: PathBuf,
    static_services: service::StaticServices,
}

impl hyper::server::Handler for RequestHandler {
    fn handle<'a, 'k>(&'a self, request: hyper::server::request::Request<'a, 'k>,
                      response: hyper::server::response::Response<'a, hyper::net::Fresh>)
    {
        let time_before = time::precise_time_ns();
        let (method, uri) = (request.method.clone(), request.uri.clone());

        // handling static files
        if let HyperRequestUri::AbsolutePath(ref url) = request.uri {
            let possible_file = self.static_files.join(&url[1..]);      // TODO: this is a dirty hack to remove the leading `/`

            // FIXME (SECURITY): check with `relative_from` that we're still in `self.static_files`
            //                   once the function is stable

            if fs::metadata(&possible_file).map(|d| d.is_file()).ok().unwrap_or(false) {
                if let Ok(mut file) = File::open(&possible_file) {
                    let mut response = response;

                    let mut mime = mime_guess::guess_mime_type(&possible_file);

                    // adding `charset=utf8` if starting with `text/`
                    if let HyperMime(HyperMimeTopLevel::Text, _, _) = mime {
                        let HyperMime(_, _, ref mut params) = mime;
                        if params.is_empty() { *params = vec![(HyperMimeAttr::Charset, HyperMimeValue::Utf8)]; }
                    }
                    response.headers_mut().set(HyperContentType(mime));

                    if let Ok(mut response) = response.start() {
                        let _ = io::copy(&mut file, &mut response);
                    }

                    let time_after = time::precise_time_ns();
                    self.static_services.logs.log_request(&method, &uri, time_after - time_before);
                    return;
                }
            }
        }

        for route in self.router.routes.iter() {
            if !route.matches(&request) {
                continue;
            }

            match route.handler {
                route::Handler::Static(_) => unimplemented!(),
                route::Handler::Dynamic(ref handler) => {
                    handler.call(request, response, &self.static_services);
                    break;
                },
            }
        }

        let time_after = time::precise_time_ns();
        self.static_services.logs.log_request(&method, &uri, time_after - time_before);
    }
}
<|endoftext|>


<commit_before>#![feature(core_intrinsics)]
#![feature(stmt_expr_attributes)]

extern crate rand;
#[cfg(unix)] extern crate libc;
#[cfg(windows)] extern crate winapi;
#[cfg(windows)] extern crate kernel32;
#[cfg(all(unix, test))] extern crate nix;

mod alloc;

pub use alloc::{ unprotected_mprotect, malloc, allocarray, free };

// -- memcmp --

/// Constant time memcmp.
pub unsafe fn memcmp<T>(b1: *const T, b2: *const T, len: usize) -> i32 {
    let b1 = b1 as *const u8;
    let b2 = b2 as *const u8;
    let mut d = 0;
    for i in 0..len as isize {
        d |= *b1.offset(i) ^ *b2.offset(i);
    }
    (1 & (d as i32 - 1) >> 8) - 1
}

// -- memset / memzero --

/// General memset.
#[cfg(not(HAVE_MEMSET_S))]
pub unsafe fn memset<T>(s: *mut T, c: i32, n: usize) {
    let s = s as *mut u8;
    let mut i = 0;
    while i < n {
        *s.offset(i as isize) = c as u8;
        i += 1;
    }
}

/// Call memset_s.
#[cfg(HAVE_MEMSET_S)]
pub unsafe fn memset<T>(s: *mut T, c: i32, n: usize) {
    extern {
        fn memset_s(s: *mut libc::c_void, smax: libc::size_t, c: libc::c_int, n: libc::size_t) -> libc::c_int;
    }
    memset_s(s as libc::c_void, n, c, n);
}

/// General memzero.
#[cfg(all(unix, not(HAVE_EXPLICIT_BZERO)))]
pub unsafe fn memzero<T>(dest: *mut T, n: usize) {
    memset(dest, 0, n);
}

/// Call explicit_bzero.
#[cfg(all(unix, HAVE_EXPLICIT_BZERO))]
pub unsafe fn memzero<T>(dest: *mut T, n: usize) {
    extern {
        fn explicit_bzero(s: *mut libc::c_void, n: libc::size_t);
    }
    explicit_bzero(dest as *mut libc::c_void, n);
}

/// call SecureZeroMemory.
#[cfg(windows)]
pub unsafe fn memzero<T>(s: *mut T, n: usize) {
    extern "system" {
        fn RtlSecureZeroMemory(ptr: winapi::PVOID, cnt: winapi::SIZE_T);
    }
    RtlSecureZeroMemory(s as winapi::PVOID, n as winapi::SIZE_T);
}

// -- mlock / munlock --

#[cfg(target_os = "linux")]
unsafe fn dontdump<T>(addr: *mut T, len: usize) {
    libc::madvise(addr as *mut libc::c_void, len, libc::MADV_DONTDUMP);
}

#[cfg(target_os = "linux")]
unsafe fn dodump<T>(addr: *mut T, len: usize) {
    libc::madvise(addr as *mut libc::c_void, len, libc::MADV_DODUMP);
}

#[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
unsafe fn dontdump<T>(addr: *mut T, len: usize) {
    libc::madvise(addr as *mut libc::c_void, len, libc::MADV_NOCORE);
}

#[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
unsafe fn dodump<T>(addr: *mut T, len: usize) {
    libc::madvise(addr as *mut libc::c_void, len, libc::MADV_CORE);
}

#[cfg(not(any(target_os = "linux", target_os = "freebsd", target_os = "dragonfly")))]
fn dontdump<T>(_addr: *mut T, _len: usize) { }

#[cfg(not(any(target_os = "linux", target_os = "freebsd", target_os = "dragonfly")))]
fn dodump<T>(_addr: *mut T, _len: usize) { }

/// Unix mlock.
#[cfg(unix)]
pub unsafe fn mlock<T>(addr: *mut T, len: usize) -> bool {
    dontdump(addr, len);
    libc::mlock(addr as *mut libc::c_void, len) == 0
}

/// Windows VirtualLock.
#[cfg(windows)]
pub unsafe fn mlock<T>(addr: *mut T, len: usize) -> bool {
    kernel32::VirtualLock(addr as winapi::LPVOID, len as winapi::SIZE_T) != 0
}

/// Unix munlock.
#[cfg(unix)]
pub unsafe fn munlock<T>(addr: *mut T, len: usize) -> bool {
    memzero(addr, len);
    dodump(addr, len);
    libc::munlock(addr as *mut libc::c_void, len) == 0
}

/// Windows VirtualUnlock.
#[cfg(windows)]
pub unsafe fn munlock<T>(addr: *mut T, len: usize) -> bool {
    memzero(addr, len);
    kernel32::VirtualUnlock(addr as winapi::LPVOID, len as winapi::SIZE_T) != 0
}

// -- mprotect --

/// Prot enum.
#[derive(Debug, Clone, PartialEq)]
pub enum Prot {
    #[cfg(unix)] NoAccess = libc::PROT_NONE as isize,
    #[cfg(unix)] ReadOnly = libc::PROT_READ as isize,
    #[cfg(unix)] WriteOnly = libc::PROT_WRITE as isize,
    #[cfg(unix)] ReadWrite = (libc::PROT_READ | libc::PROT_WRITE) as isize,
    #[cfg(unix)] Execute = libc::PROT_EXEC as isize,
    #[cfg(unix)] ReadExec = (libc::PROT_READ | libc::PROT_EXEC) as isize,
    #[cfg(unix)] WriteExec = (libc::PROT_WRITE | libc::PROT_EXEC) as isize,
    #[cfg(unix)] ReadWriteExec = (libc::PROT_READ | libc::PROT_WRITE | libc::PROT_EXEC) as isize,

    #[cfg(windows)] NoAccess = winapi::PAGE_NOACCESS as isize,
    #[cfg(windows)] ReadOnly = winapi::PAGE_READONLY as isize,
    #[cfg(windows)] ReadWrite = winapi::PAGE_READWRITE as isize,
    #[cfg(windows)] WriteCopy = winapi::PAGE_WRITECOPY as isize,
    #[cfg(windows)] Execute = winapi::PAGE_EXECUTE as isize,
    #[cfg(windows)] ReadExec = winapi::PAGE_EXECUTE_READ as isize,
    #[cfg(windows)] ReadWriteExec = winapi::PAGE_EXECUTE_READWRITE as isize,
    #[cfg(windows)] WriteCopyExec = winapi::PAGE_EXECUTE_WRITECOPY as isize,
    #[cfg(windows)] Guard = winapi::PAGE_GUARD as isize,
    #[cfg(windows)] NoCache = winapi::PAGE_NOCACHE as isize,
    #[cfg(windows)] WriteCombine = winapi::PAGE_WRITECOMBINE as isize,
    #[cfg(windows)] RevertToFileMap = winapi::PAGE_REVERT_TO_FILE_MAP as isize,
    #[cfg(windows)] TargetsNoUpdate = winapi::PAGE_TARGETS_NO_UPDATE as isize,

    // winapi::PAGE_REVERT_TO_FILE_MAP == winapi::PAGE_TARGETS_NO_UPDATE
    // #[cfg(windows)] TargetsInvalid = winapi::PAGE_TARGETS_INVALID as isize,
}

/// Unix mprotect.
#[cfg(unix)]
pub unsafe fn mprotect<T>(ptr: *mut T, len: usize, prot: Prot) -> bool {
    libc::mprotect(ptr as *mut libc::c_void, len, prot as libc::c_int) == 0
}

/// Windows VirtualProtect.
#[cfg(windows)]
pub unsafe fn mprotect<T>(ptr: *mut T, len: usize, prot: Prot) -> bool {
    kernel32::VirtualProtect(
        ptr as winapi::LPVOID,
        len as winapi::SIZE_T,
        prot as winapi::DWORD,
        std::ptr::null_mut()
    ) != 0
}
<commit_msg>fix cfg(windows)<commit_after>#![feature(core_intrinsics)]
#![feature(stmt_expr_attributes)]

extern crate rand;
#[cfg(unix)] extern crate libc;
#[cfg(windows)] extern crate winapi;
#[cfg(windows)] extern crate kernel32;
#[cfg(all(unix, test))] extern crate nix;

mod alloc;

pub use alloc::{ unprotected_mprotect, malloc, allocarray, free };

// -- memcmp --

/// Constant time memcmp.
pub unsafe fn memcmp<T>(b1: *const T, b2: *const T, len: usize) -> i32 {
    let b1 = b1 as *const u8;
    let b2 = b2 as *const u8;
    let mut d = 0;
    for i in 0..len as isize {
        d |= *b1.offset(i) ^ *b2.offset(i);
    }
    (1 & (d as i32 - 1) >> 8) - 1
}

// -- memset / memzero --

/// General memset.
#[cfg(not(HAVE_MEMSET_S))]
pub unsafe fn memset<T>(s: *mut T, c: i32, n: usize) {
    let s = s as *mut u8;
    let mut i = 0;
    while i < n {
        *s.offset(i as isize) = c as u8;
        i += 1;
    }
}

/// Call memset_s.
#[cfg(HAVE_MEMSET_S)]
pub unsafe fn memset<T>(s: *mut T, c: i32, n: usize) {
    extern {
        fn memset_s(s: *mut libc::c_void, smax: libc::size_t, c: libc::c_int, n: libc::size_t) -> libc::c_int;
    }
    memset_s(s as libc::c_void, n, c, n);
}

/// General memzero.
#[cfg(all(unix, not(HAVE_EXPLICIT_BZERO)))]
pub unsafe fn memzero<T>(dest: *mut T, n: usize) {
    memset(dest, 0, n);
}

/// Call explicit_bzero.
#[cfg(all(unix, HAVE_EXPLICIT_BZERO))]
pub unsafe fn memzero<T>(dest: *mut T, n: usize) {
    extern {
        fn explicit_bzero(s: *mut libc::c_void, n: libc::size_t);
    }
    explicit_bzero(dest as *mut libc::c_void, n);
}

/// call SecureZeroMemory.
#[cfg(windows)]
pub unsafe fn memzero<T>(s: *mut T, n: usize) {
    extern "system" {
        fn RtlSecureZeroMemory(ptr: winapi::PVOID, cnt: winapi::SIZE_T);
    }
    RtlSecureZeroMemory(s as winapi::PVOID, n as winapi::SIZE_T);
}

// -- mlock / munlock --

#[cfg(target_os = "linux")]
unsafe fn dontdump<T>(addr: *mut T, len: usize) {
    libc::madvise(addr as *mut libc::c_void, len, libc::MADV_DONTDUMP);
}

#[cfg(target_os = "linux")]
unsafe fn dodump<T>(addr: *mut T, len: usize) {
    libc::madvise(addr as *mut libc::c_void, len, libc::MADV_DODUMP);
}

#[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
unsafe fn dontdump<T>(addr: *mut T, len: usize) {
    libc::madvise(addr as *mut libc::c_void, len, libc::MADV_NOCORE);
}

#[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
unsafe fn dodump<T>(addr: *mut T, len: usize) {
    libc::madvise(addr as *mut libc::c_void, len, libc::MADV_CORE);
}

#[cfg(not(any(target_os = "linux", target_os = "freebsd", target_os = "dragonfly")))]
fn dontdump<T>(_addr: *mut T, _len: usize) { }

#[cfg(not(any(target_os = "linux", target_os = "freebsd", target_os = "dragonfly")))]
fn dodump<T>(_addr: *mut T, _len: usize) { }

/// Unix mlock.
#[cfg(unix)]
pub unsafe fn mlock<T>(addr: *mut T, len: usize) -> bool {
    dontdump(addr, len);
    libc::mlock(addr as *mut libc::c_void, len) == 0
}

/// Windows VirtualLock.
#[cfg(windows)]
pub unsafe fn mlock<T>(addr: *mut T, len: usize) -> bool {
    kernel32::VirtualLock(addr as winapi::LPVOID, len as winapi::SIZE_T) != 0
}

/// Unix munlock.
#[cfg(unix)]
pub unsafe fn munlock<T>(addr: *mut T, len: usize) -> bool {
    memzero(addr, len);
    dodump(addr, len);
    libc::munlock(addr as *mut libc::c_void, len) == 0
}

/// Windows VirtualUnlock.
#[cfg(windows)]
pub unsafe fn munlock<T>(addr: *mut T, len: usize) -> bool {
    memzero(addr, len);
    kernel32::VirtualUnlock(addr as winapi::LPVOID, len as winapi::SIZE_T) != 0
}

// -- mprotect --

/// Prot enum.
#[derive(Debug, Clone, PartialEq)]
pub enum Prot {
    #[cfg(unix)] NoAccess = libc::PROT_NONE as isize,
    #[cfg(unix)] ReadOnly = libc::PROT_READ as isize,
    #[cfg(unix)] WriteOnly = libc::PROT_WRITE as isize,
    #[cfg(unix)] ReadWrite = (libc::PROT_READ | libc::PROT_WRITE) as isize,
    #[cfg(unix)] Execute = libc::PROT_EXEC as isize,
    #[cfg(unix)] ReadExec = (libc::PROT_READ | libc::PROT_EXEC) as isize,
    #[cfg(unix)] WriteExec = (libc::PROT_WRITE | libc::PROT_EXEC) as isize,
    #[cfg(unix)] ReadWriteExec = (libc::PROT_READ | libc::PROT_WRITE | libc::PROT_EXEC) as isize,

    #[cfg(windows)] NoAccess = winapi::PAGE_NOACCESS as isize,
    #[cfg(windows)] ReadOnly = winapi::PAGE_READONLY as isize,
    #[cfg(windows)] ReadWrite = winapi::PAGE_READWRITE as isize,
    #[cfg(windows)] WriteCopy = winapi::PAGE_WRITECOPY as isize,
    #[cfg(windows)] Execute = winapi::PAGE_EXECUTE as isize,
    #[cfg(windows)] ReadExec = winapi::PAGE_EXECUTE_READ as isize,
    #[cfg(windows)] ReadWriteExec = winapi::PAGE_EXECUTE_READWRITE as isize,
    #[cfg(windows)] WriteCopyExec = winapi::PAGE_EXECUTE_WRITECOPY as isize,
    #[cfg(windows)] Guard = winapi::PAGE_GUARD as isize,
    #[cfg(windows)] NoCache = winapi::PAGE_NOCACHE as isize,
    #[cfg(windows)] WriteCombine = winapi::PAGE_WRITECOMBINE as isize,
    #[cfg(windows)] RevertToFileMap = winapi::PAGE_REVERT_TO_FILE_MAP as isize,
    #[cfg(windows)] TargetsNoUpdate = winapi::PAGE_TARGETS_NO_UPDATE as isize,

    // winapi::PAGE_REVERT_TO_FILE_MAP == winapi::PAGE_TARGETS_NO_UPDATE
    // #[cfg(windows)] TargetsInvalid = winapi::PAGE_TARGETS_INVALID as isize,
}

/// Unix mprotect.
#[cfg(unix)]
pub unsafe fn mprotect<T>(ptr: *mut T, len: usize, prot: Prot) -> bool {
    libc::mprotect(ptr as *mut libc::c_void, len, prot as libc::c_int) == 0
}

/// Windows VirtualProtect.
#[cfg(windows)]
pub unsafe fn mprotect<T>(ptr: *mut T, len: usize, prot: Prot) -> bool {
    let mut old = std::mem::uninitialized();
    kernel32::VirtualProtect(
        ptr as winapi::LPVOID,
        len as winapi::SIZE_T,
        prot as winapi::DWORD,
        &mut old as winapi::PDWORD
    ) != 0
}
<|endoftext|>


<commit_before>//
//  SOS: the Stupid Operating System
//  by Hawk Weisman (hi@hawkweisman.me)
//
//  Copyright (c) 2015 Hawk Weisman
//  Released under the terms of the MIT license. See `LICENSE` in the root
//  directory of this repository for more information.
//
//! SOS: the Stupid Operating System
//!
//! SOS is a simple, tiny toy OS implemented in Rust.
//!
//! I'm writing this mostly for fun, to learn more about OS design and kernel //! hacking, so don't expect anything new or exciting out of this project.

#![crate_name = "sos_kernel"]
#![crate_type = "staticlib"]
#![feature(asm)]
#![feature(no_std, lang_items)]
#![feature(const_fn, unique, core_str_ext, core_slice_ext)]
#![feature(slice_patterns)]
#![feature(iter_cmp)]
#![no_std]

extern crate rlibc;
extern crate spin;

pub mod arch;
#[macro_use]
pub mod io;
pub mod util;
pub mod panic;
pub mod multiboot;

use arch::cpu;

/// Kernel main loop
///
/// The kernel main loop expects to be passed the address of a valid
/// Multiboot 2 info struct. It's the bootloader's responsibility to ensure
/// that this is passed in the correct register as expected by the calling
/// convention (`edi` on x86). If this isn't there, you can expect to have a
/// bad problem and not go to space today.
#[no_mangle]
pub extern fn kernel_main(multiboot_addr: usize) {
    io::term::CONSOLE.lock().clear();

    println!("Hello from the kernel!");

    // Unpack multiboot tag
    let boot_info = unsafe { multiboot::Info::from(multiboot_addr) };
    let mmap_tag // Extract the memory map tag from the multiboot info
        = boot_info.mem_map()
                   .expect("Memory map tag required!");

    println!("Detected memory areas:");
    for a in mmap_tag.entries() {
        println!("     start: 0x{:x}     end: 0x{:x}"
                , a.base, a.length );
    }

    let elf_sections_tag // Extract ELF sections tag from the multiboot info
        = boot_info.elf64_sections()
                   .expect("Elf-sections tag required!");

    println!("Detected kernel sections:");
    for section in elf_sections_tag.sections() {
    println!( "     addr: 0x{:x}     size: 0x{:x}     flags: 0x{:x}"
            , section.address
            , section.length
            , section.flags );
    }

    let kernel_begin
        = elf_sections_tag.sections()
                          .map(|s| s.address).min()
                          .expect("Could not find kernel start section!\
                                   \nSomething is deeply wrong.");
    let kernel_end
        = elf_sections_tag.sections()
                        .map(|s| s.address).max()
                        .expect("Could not find kernel end section!\
                                \nSomething is deeply wrong.");

    println!( "Kernel begins at 0x{:x} and ends at 0x{:x}"
             , kernel_begin, kernel_end );

    let multiboot_end = multiboot_addr + boot_info.length as usize;

    println!( "Multiboot info begins at 0x{:x} and ends at 0x{:x}"
             , multiboot_addr, multiboot_end);

    println!("Intializing interrupts...");
    cpu::interrupts::initialize();

    loop { }
}
<commit_msg>Kernel prints things slightly prettier now<commit_after>//
//  SOS: the Stupid Operating System
//  by Hawk Weisman (hi@hawkweisman.me)
//
//  Copyright (c) 2015 Hawk Weisman
//  Released under the terms of the MIT license. See `LICENSE` in the root
//  directory of this repository for more information.
//
//! SOS: the Stupid Operating System
//!
//! SOS is a simple, tiny toy OS implemented in Rust.
//!
//! I'm writing this mostly for fun, to learn more about OS design and kernel //! hacking, so don't expect anything new or exciting out of this project.

#![crate_name = "sos_kernel"]
#![crate_type = "staticlib"]
#![feature(asm)]
#![feature(no_std, lang_items)]
#![feature(const_fn, unique, core_str_ext, core_slice_ext)]
#![feature(slice_patterns)]
#![feature(iter_cmp)]
#![no_std]

extern crate rlibc;
extern crate spin;

pub mod arch;
#[macro_use]
pub mod io;
pub mod util;
pub mod panic;
pub mod multiboot;

use arch::cpu;

/// Kernel main loop
///
/// The kernel main loop expects to be passed the address of a valid
/// Multiboot 2 info struct. It's the bootloader's responsibility to ensure
/// that this is passed in the correct register as expected by the calling
/// convention (`edi` on x86). If this isn't there, you can expect to have a
/// bad problem and not go to space today.
#[no_mangle]
pub extern fn kernel_main(multiboot_addr: usize) {
    io::term::CONSOLE.lock().clear();

    println!("Hello from the kernel!");

    // Unpack multiboot tag
    let boot_info = unsafe { multiboot::Info::from(multiboot_addr) };
    let mmap_tag // Extract the memory map tag from the multiboot info
        = boot_info.mem_map()
                   .expect("Memory map tag required!");

    println!("Detected memory areas:");
    for a in mmap_tag.entries() {
        println!("     start: {:#08x}, end: {:#08x}"
                , a.base, a.length );
    }

    let elf_sections_tag // Extract ELF sections tag from the multiboot info
        = boot_info.elf64_sections()
                   .expect("Elf-sections tag required!");

    println!("Detected kernel sections:");
    for section in elf_sections_tag.sections() {
    println!( "     address: {:#08x}, size: {:#08x}, flags: {:#08x}"
            , section.address
            , section.length
            , section.flags );
    }

    let kernel_begin
        = elf_sections_tag.sections()
                          .map(|s| s.address).min()
                          .expect("Could not find kernel start section!\
                                   \nSomething is deeply wrong.");
    let kernel_end
        = elf_sections_tag.sections()
                        .map(|s| s.address).max()
                        .expect("Could not find kernel end section!\
                                \nSomething is deeply wrong.");

    println!( "Kernel begins at {:#x} and ends at {:#x}."
             , kernel_begin, kernel_end );

    let multiboot_end = multiboot_addr + boot_info.length as usize;

    println!( "Multiboot info begins at {:#x} and ends at {:#x}."
             , multiboot_addr, multiboot_end);

    println!("Intializing interrupts...");
    cpu::interrupts::initialize();

    loop { }
}
<|endoftext|>


<commit_before>use std::fmt;

mod kleisli;
pub use kleisli::Kleisli;

pub mod extra;

mod pipe;
pub use pipe::*;

enum Void {}

/// Represents a conduit, i.e. a sequence of await/yield actions.
///
/// - `I` is the type of values the conduit consumes from upstream.
/// - `O` is the type of values the conduit passes downstream.
/// - `A` is the return type of the conduit.
pub enum ConduitM<'a, I, O, A> {
    /// The case `Pure(a)` means that the conduit contains requires further action and just returns the result `a`.
    Pure(Box<A>),
    /// The case `Await(k)` means that the conduit waits for a value of type `I`, and the remaining (suspended) program is given by the kleisli arrow `k`.
    Await(Kleisli<'a, Option<I>, I, O, A>),
    /// The case `Yield(o, k)` means that the conduit yields a value of type `O`, and the remaining (suspended) program is given by the kleisli arrow `k`.
    Yield(Box<O>, Kleisli<'a, (), I, O, A>)
}

/// Provides a stream of output values,
/// without consuming any input or producing a final result.
pub type Source<'a, O> = ConduitM<'a, (), O, ()>;

impl<'a, O> ConduitM<'a, (), O, ()> {

    /// Generalize a `Source` by universally quantifying the input type.
    pub fn to_producer<I>(self) -> ConduitM<'a, I, O, ()> where O: 'static {
        match self {
            ConduitM::Pure(x) => ConduitM::Pure(x),
            ConduitM::Await(k) => k.run(Some(())).to_producer(),
            ConduitM::Yield(o, k) => ConduitM::Yield(o, Kleisli::new().append(move |_| {
                k.run(()).to_producer()
            }))
        }
    }

    /// Pulls data from the source and pushes it into the sink.
    ///
    /// # Example
    ///
    /// ```rust
    /// use plumbum::{Source, Sink, consume, produce};
    ///
    /// let src = produce(42);
    ///
    /// let sink = consume().map(|x| 1 + x.unwrap_or(0));
    ///
    /// assert_eq!(src.connect(sink), 43);
    /// ```
    pub fn connect<B>(mut self, mut sink: Sink<'a, O, B>) -> B where O: 'static {
        loop {
            let (next_src, next_sink) = match sink {
                ConduitM::Pure(b_box) => {
                    return *b_box;
                },
                ConduitM::Await(k_sink) => {
                    match self {
                        ConduitM::Pure(x) => {
                            (ConduitM::Pure(x), k_sink.run(None))
                        },
                        ConduitM::Await(k_src) => {
                            (k_src.run(Some(())), ConduitM::Await(k_sink))
                        },
                        ConduitM::Yield(a_box, k_src) => {
                            (k_src.run(()), k_sink.run(Some(*a_box)))
                        }
                    }
                },
                ConduitM::Yield(_, _) => unreachable!()
            };
            self = next_src;
            sink = next_sink;
        }
    }

}

/// Consumes a stream of input values and produces a stream of output values,
/// without producing a final result.
pub type Conduit<'a, I, O> = ConduitM<'a, I, O, ()>;

impl<'a, I, O> ConduitM<'a, I, O, ()> {
    /// Combines two Conduits together into a new Conduit.
    ///
    /// # Example
    ///
    /// ```rust
    /// use plumbum::{Source, Sink, consume, produce};
    ///
    /// let src = produce(42);
    ///
    /// let conduit = consume().and_then(|x| produce(1 + x.unwrap_or(0)));
    ///
    /// let sink = consume().map(|x| 1 + x.unwrap_or(0));
    ///
    /// assert_eq!(src.fuse(conduit).connect(sink), 44);
    /// ```
    pub fn fuse<C, R>(self, other: ConduitM<'a, O, C, R>) -> ConduitM<'a, I, C, R>
        where I: 'static, O: 'static, C: 'static, R: 'a {
        match other {
            ConduitM::Pure(r) => ConduitM::Pure(r),
            ConduitM::Yield(c, k) => ConduitM::Yield(c, Kleisli::new().append(move |_| {
                self.fuse(k.run(()))
            })),
            ConduitM::Await(k_right) => match self {
                ConduitM::Pure(_) => ConduitM::fuse(().into(), k_right.run(None)),
                ConduitM::Yield(b, k_left) => k_left.run(()).fuse(k_right.run(Some(*b))),
                ConduitM::Await(k_left) => ConduitM::Await(Kleisli::new().append(move |a| {
                    k_left.run(a).fuse(ConduitM::Await(k_right))
                }))
            }
        }
    }
}

/// Consumes a stream of input values and produces a final result,
/// without producing any output.
pub type Sink<'a, I, A> = ConduitM<'a, I, Void, A>;

impl<'a, I, A> ConduitM<'a, I, Void, A> {
    /// Generalize a `Sink` by universally quantifying the output type.
    pub fn to_consumer<O>(self) -> ConduitM<'a, I, O, A> {
        unsafe { std::mem::transmute(self) }
    }
}

impl<'a, I, O, A> ConduitM<'a, I, O, A> {

    fn and_then_boxed<B, F>(self, js: F) -> ConduitM<'a, I, O, B>
        where F: 'a + FnOnce(Box<A>) -> ConduitM<'a, I, O, B> {
        match self {
            ConduitM::Pure(a) => js(a),
            ConduitM::Await(is) => ConduitM::Await(kleisli::append_boxed(is, js)),
            ConduitM::Yield(o, is) => ConduitM::Yield(o, kleisli::append_boxed(is, js))
        }
    }

    /// Appends a continuation to a conduit. Which means,
    /// given a function from `A` to `ConduitM<I, O, B>`,
    /// passes the return value of the conduit to the function,
    /// and returns the resulting program.
    pub fn and_then<B, F>(self, js: F) -> ConduitM<'a, I, O, B>
        where F: 'a + FnOnce(A) -> ConduitM<'a, I, O, B> {
        match self {
            ConduitM::Pure(a) => js(*a),
            ConduitM::Await(is) => ConduitM::Await(is.append(js)),
            ConduitM::Yield(o, is) => ConduitM::Yield(o, is.append(js))
        }
    }

    /// Modifies the return value of the conduit.
    /// Seen differently, it lifts a function from
    /// `A` to `B` into a function from `ConduitM<I, O, A>`
    /// to `ConduitM<I, O, B>`.
    pub fn map<B, F>(self, f: F) -> ConduitM<'a, I, O, B>
        where F: 'a + FnOnce(A) -> B {
        self.and_then(move |a| f(a).into())
    }

}

impl<'a, I, O, A: PartialEq> PartialEq for ConduitM<'a, I, O, A> {
    fn eq(&self, other: &ConduitM<'a, I, O, A>) -> bool {
        match (self, other) {
            (&ConduitM::Pure(ref a), &ConduitM::Pure(ref b)) => a == b,
            _ => false
        }
    }
}

impl<'a, I, O, A: fmt::Debug> fmt::Debug for ConduitM<'a, I, O, A> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            &ConduitM::Pure(ref a) => write!(f, "Pure({:?})", a),
            &ConduitM::Await(_) => write!(f, "Await(..)"),
            &ConduitM::Yield(_, _) => write!(f, "Yield(..)")
        }
    }
}

impl<'a, I, O, A> From<A> for ConduitM<'a, I, O, A> {
    fn from(a: A) -> ConduitM<'a, I, O, A> {
        ConduitM::Pure(Box::new(a))
    }
}

/// Wait for a single input value from upstream.
///
/// If no data is available, returns `None`.
/// Once it returns `None`, subsequent calls will also return `None`.
pub fn consume<'a, I, O>() -> ConduitM<'a, I, O, Option<I>> {
    ConduitM::Await(Kleisli::new())
}

/// Send a value downstream to the next component to consume.
///
/// If the downstream component terminates, this call will never return control.
pub fn produce<'a, I, O>(o: O) -> ConduitM<'a, I, O, ()> {
    ConduitM::Yield(Box::new(o), Kleisli::new())
}
<commit_msg>rename type params<commit_after>use std::fmt;

mod kleisli;
pub use kleisli::Kleisli;

pub mod extra;

mod pipe;
pub use pipe::*;

enum Void {}

/// Represents a conduit, i.e. a sequence of await/yield actions.
///
/// - `I` is the type of values the conduit consumes from upstream.
/// - `O` is the type of values the conduit passes downstream.
/// - `A` is the return type of the conduit.
pub enum ConduitM<'a, I, O, A> {
    /// The case `Pure(a)` means that the conduit contains requires further action and just returns the result `a`.
    Pure(Box<A>),
    /// The case `Await(k)` means that the conduit waits for a value of type `I`, and the remaining (suspended) program is given by the kleisli arrow `k`.
    Await(Kleisli<'a, Option<I>, I, O, A>),
    /// The case `Yield(o, k)` means that the conduit yields a value of type `O`, and the remaining (suspended) program is given by the kleisli arrow `k`.
    Yield(Box<O>, Kleisli<'a, (), I, O, A>)
}

/// Provides a stream of output values,
/// without consuming any input or producing a final result.
pub type Source<'a, O> = ConduitM<'a, (), O, ()>;

impl<'a, O> ConduitM<'a, (), O, ()> {

    /// Generalize a `Source` by universally quantifying the input type.
    pub fn to_producer<I>(self) -> ConduitM<'a, I, O, ()> where O: 'static {
        match self {
            ConduitM::Pure(x) => ConduitM::Pure(x),
            ConduitM::Await(k) => k.run(Some(())).to_producer(),
            ConduitM::Yield(o, k) => ConduitM::Yield(o, Kleisli::new().append(move |_| {
                k.run(()).to_producer()
            }))
        }
    }

    /// Pulls data from the source and pushes it into the sink.
    ///
    /// # Example
    ///
    /// ```rust
    /// use plumbum::{Source, Sink, consume, produce};
    ///
    /// let src = produce(42);
    ///
    /// let sink = consume().map(|x| 1 + x.unwrap_or(0));
    ///
    /// assert_eq!(src.connect(sink), 43);
    /// ```
    pub fn connect<A>(mut self, mut sink: Sink<'a, O, A>) -> A where O: 'static {
        loop {
            let (next_src, next_sink) = match sink {
                ConduitM::Pure(b_box) => {
                    return *b_box;
                },
                ConduitM::Await(k_sink) => {
                    match self {
                        ConduitM::Pure(x) => {
                            (ConduitM::Pure(x), k_sink.run(None))
                        },
                        ConduitM::Await(k_src) => {
                            (k_src.run(Some(())), ConduitM::Await(k_sink))
                        },
                        ConduitM::Yield(a_box, k_src) => {
                            (k_src.run(()), k_sink.run(Some(*a_box)))
                        }
                    }
                },
                ConduitM::Yield(_, _) => unreachable!()
            };
            self = next_src;
            sink = next_sink;
        }
    }

}

/// Consumes a stream of input values and produces a stream of output values,
/// without producing a final result.
pub type Conduit<'a, I, O> = ConduitM<'a, I, O, ()>;

impl<'a, I, O> ConduitM<'a, I, O, ()> {
    /// Combines two Conduits together into a new Conduit.
    ///
    /// # Example
    ///
    /// ```rust
    /// use plumbum::{Source, Sink, consume, produce};
    ///
    /// let src = produce(42);
    ///
    /// let conduit = consume().and_then(|x| produce(1 + x.unwrap_or(0)));
    ///
    /// let sink = consume().map(|x| 1 + x.unwrap_or(0));
    ///
    /// assert_eq!(src.fuse(conduit).connect(sink), 44);
    /// ```
    pub fn fuse<P, A>(self, other: ConduitM<'a, O, P, A>) -> ConduitM<'a, I, P, A>
        where I: 'static, O: 'static, P: 'static, A: 'a {
        match other {
            ConduitM::Pure(r) => ConduitM::Pure(r),
            ConduitM::Yield(c, k) => ConduitM::Yield(c, Kleisli::new().append(move |_| {
                self.fuse(k.run(()))
            })),
            ConduitM::Await(k_right) => match self {
                ConduitM::Pure(_) => ConduitM::fuse(().into(), k_right.run(None)),
                ConduitM::Yield(b, k_left) => k_left.run(()).fuse(k_right.run(Some(*b))),
                ConduitM::Await(k_left) => ConduitM::Await(Kleisli::new().append(move |a| {
                    k_left.run(a).fuse(ConduitM::Await(k_right))
                }))
            }
        }
    }
}

/// Consumes a stream of input values and produces a final result,
/// without producing any output.
pub type Sink<'a, I, A> = ConduitM<'a, I, Void, A>;

impl<'a, I, A> ConduitM<'a, I, Void, A> {
    /// Generalize a `Sink` by universally quantifying the output type.
    pub fn to_consumer<O>(self) -> ConduitM<'a, I, O, A> {
        unsafe { std::mem::transmute(self) }
    }
}

impl<'a, I, O, A> ConduitM<'a, I, O, A> {

    fn and_then_boxed<B, F>(self, js: F) -> ConduitM<'a, I, O, B>
        where F: 'a + FnOnce(Box<A>) -> ConduitM<'a, I, O, B> {
        match self {
            ConduitM::Pure(a) => js(a),
            ConduitM::Await(is) => ConduitM::Await(kleisli::append_boxed(is, js)),
            ConduitM::Yield(o, is) => ConduitM::Yield(o, kleisli::append_boxed(is, js))
        }
    }

    /// Appends a continuation to a conduit. Which means,
    /// given a function from `A` to `ConduitM<I, O, B>`,
    /// passes the return value of the conduit to the function,
    /// and returns the resulting program.
    pub fn and_then<B, F>(self, js: F) -> ConduitM<'a, I, O, B>
        where F: 'a + FnOnce(A) -> ConduitM<'a, I, O, B> {
        match self {
            ConduitM::Pure(a) => js(*a),
            ConduitM::Await(is) => ConduitM::Await(is.append(js)),
            ConduitM::Yield(o, is) => ConduitM::Yield(o, is.append(js))
        }
    }

    /// Modifies the return value of the conduit.
    /// Seen differently, it lifts a function from
    /// `A` to `B` into a function from `ConduitM<I, O, A>`
    /// to `ConduitM<I, O, B>`.
    pub fn map<B, F>(self, f: F) -> ConduitM<'a, I, O, B>
        where F: 'a + FnOnce(A) -> B {
        self.and_then(move |a| f(a).into())
    }

}

impl<'a, I, O, A: PartialEq> PartialEq for ConduitM<'a, I, O, A> {
    fn eq(&self, other: &ConduitM<'a, I, O, A>) -> bool {
        match (self, other) {
            (&ConduitM::Pure(ref a), &ConduitM::Pure(ref b)) => a == b,
            _ => false
        }
    }
}

impl<'a, I, O, A: fmt::Debug> fmt::Debug for ConduitM<'a, I, O, A> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            &ConduitM::Pure(ref a) => write!(f, "Pure({:?})", a),
            &ConduitM::Await(_) => write!(f, "Await(..)"),
            &ConduitM::Yield(_, _) => write!(f, "Yield(..)")
        }
    }
}

impl<'a, I, O, A> From<A> for ConduitM<'a, I, O, A> {
    fn from(a: A) -> ConduitM<'a, I, O, A> {
        ConduitM::Pure(Box::new(a))
    }
}

/// Wait for a single input value from upstream.
///
/// If no data is available, returns `None`.
/// Once it returns `None`, subsequent calls will also return `None`.
pub fn consume<'a, I, O>() -> ConduitM<'a, I, O, Option<I>> {
    ConduitM::Await(Kleisli::new())
}

/// Send a value downstream to the next component to consume.
///
/// If the downstream component terminates, this call will never return control.
pub fn produce<'a, I, O>(o: O) -> ConduitM<'a, I, O, ()> {
    ConduitM::Yield(Box::new(o), Kleisli::new())
}
<|endoftext|>


<commit_before>use std::collections::HashMap;

pub fn puzzle(input: &str) -> String {
    String::from("no")
}

pub struct Column {
    freqs: HashMap<char, u32>,
}

impl Column {
    fn add_char(&mut self, ch: char) {
        let count = self.freqs.entry(ch).or_insert(0);
        *count += 1;
    }

    fn most_common_char(&self) -> char {
        let mut f: Vec<(&char, &u32)> = self.freqs.iter().collect();
        f.sort_by(|a, b| b.1.cmp(&a.1));
        *f[0].0
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use std::collections::HashMap;

    #[test]
    fn most_common_char_seen_in_column() {
        let mut c = Column { freqs: HashMap::new() };
        c.add_char('a');
        c.add_char('b');
        c.add_char('a');
        assert_eq!(c.most_common_char(), 'a');
    }
}
<commit_msg>Ok, processing the input into cols and cols into answer<commit_after>use std::collections::HashMap;

pub fn puzzle(input: &str) -> String {
    let mut lines = input.lines();
    let first_line = lines.next().expect("There were no lines!");

    let mut columns: Vec<Column> = first_line.chars().map(|ch| {
        let mut c = Column { freqs: HashMap::new() };
        c.add_char(ch);
        c
    }).collect();

    for line in lines {
        for (i, ch) in line.chars().enumerate() {
            columns[i].add_char(ch);
        }
    }

    let mut answer = String::new();
    for col in columns {
        answer.push(col.most_common_char())
    }
    answer
}

pub struct Column {
    freqs: HashMap<char, u32>,
}

impl Column {
    fn add_char(&mut self, ch: char) {
        let count = self.freqs.entry(ch).or_insert(0);
        *count += 1;
    }

    fn most_common_char(&self) -> char {
        let mut f: Vec<(&char, &u32)> = self.freqs.iter().collect();
        f.sort_by(|a, b| b.1.cmp(&a.1));
        *f[0].0
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use std::collections::HashMap;

    #[test]
    fn most_common_char_seen_in_column() {
        let mut c = Column { freqs: HashMap::new() };
        c.add_char('a');
        c.add_char('b');
        c.add_char('a');
        assert_eq!(c.most_common_char(), 'a');
    }

    #[test]
    fn sample() {
        let input = "\
eedadn
drvtee
eandsr
raavrd
atevrs
tsrnev
sdttsa
rasrtv
nssdts
ntnada
svetve
tesnvt
vntsnd
vrdear
dvrsen
enarar";
        assert_eq!(puzzle(input), String::from("easter"));
    }
}
<|endoftext|>


<commit_before>#![feature(plugin_registrar, box_syntax, rustc_private, custom_derive, quote, plugin, custom_attribute)]

#[macro_use]
extern crate rustc;
extern crate rustc_front;
extern crate rustc_plugin;
#[macro_use]
extern crate syntax;
extern crate syntax_ext;

use rustc_plugin::Registry;
use syntax::parse::token::intern;
use syntax::ext::base::MultiDecorator;

#[plugin_registrar]
pub fn plugin_registrar(reg: &mut Registry) {
    reg.register_syntax_extension(intern("derive_From"), MultiDecorator(box expand_derive_from));
}

use syntax::ast::{VariantData, ItemKind, MetaItem};
use syntax::codemap::Span;
use syntax::ext::base::{Annotatable, ExtCtxt};
use syntax::ext::build::AstBuilder;

/// Provides the hook to expand `#[derive(From)]` into an implementation of `From`
fn expand_derive_from(cx: &mut ExtCtxt, span: Span, _: &MetaItem,
                          item: &Annotatable, push: &mut FnMut(Annotatable)) {

    // Get the that is wrapped by the newtype and do some checks
    let old_type_opt = match *item {
        Annotatable::Item(ref x) => {
            match x.node {
                ItemKind::Struct(VariantData::Tuple(ref y, _), _) => {
                    if y.len() == 1 {
                        Some((x.ident, y[0].node.ty.clone()))
                    }
                    else {
                        None
                    }
                }
                _ => None,
            }
        },
        _ => None,
    };

    let (ident, old_type) = match old_type_opt {
        Some(x) => x,
        None => {
            cx.span_bug(span, "only newtype structs can use `derive(From)`");
        }
    };

    let code = quote_item!(cx,
        impl ::std::convert::From<$old_type> for $ident {
            fn from(a: $old_type) -> $ident {
                $ident(a)
            }
        }
    ).unwrap();

    push(Annotatable::Item(code));
}
<commit_msg>Split main function into two parts<commit_after>#![feature(plugin_registrar, box_syntax, rustc_private, custom_derive, quote, plugin, custom_attribute)]

#[macro_use]
extern crate rustc;
extern crate rustc_front;
extern crate rustc_plugin;
#[macro_use]
extern crate syntax;
extern crate syntax_ext;

use rustc_plugin::Registry;
use syntax::parse::token::intern;
use syntax::ext::base::MultiDecorator;

#[plugin_registrar]
pub fn plugin_registrar(reg: &mut Registry) {
    reg.register_syntax_extension(intern("derive_From"), MultiDecorator(box expand_derive_from));
}

use syntax::ast::{Ident, Ty, VariantData, ItemKind, MetaItem};
use syntax::codemap::Span;
use syntax::ext::base::{Annotatable, ExtCtxt};
use syntax::ext::build::AstBuilder;
use syntax::ptr::P;

/// Provides the hook to expand `#[derive(From)]` into an implementation of `From`
fn expand_derive_from(cx: &mut ExtCtxt, span: Span, _: &MetaItem,
                          item: &Annotatable, push: &mut FnMut(Annotatable)) {

    // Get the that is wrapped by the newtype and do some checks
    let failed = match *item {
        Annotatable::Item(ref x) => {
            match x.node {
                ItemKind::Struct(VariantData::Tuple(ref y, _), _) => {
                    if y.len() == 1 {
                        newtype_from(cx, x.ident, y[0].node.ty.clone(), push);
                        false
                    }
                    else {
                        true
                    }
                },
                _ => true,
            }
        },
        _ => true,
    };

    if failed {
        cx.span_bug(span, "only newtype structs can use `derive(From)`");
    }
}

fn newtype_from(cx: &mut ExtCtxt, ident: Ident, old_type: P<Ty>,
                push: &mut FnMut(Annotatable)) {
    let code = quote_item!(cx,
        impl ::std::convert::From<$old_type> for $ident {
            fn from(a: $old_type) -> $ident {
                $ident(a)
            }
        }
    ).unwrap();

    push(Annotatable::Item(code));
}
<|endoftext|>


<commit_before>//!
//! ```
//! use sxd_document::Package;
//! let package = Package::new();
//! let doc = package.as_document();
//!
//! let hello = doc.create_element("hello");
//! hello.set_attribute_value("planet", "Earth");
//! let comment = doc.create_comment("What about other planets?");
//! let text = doc.create_text("Greetings, Earthlings!");
//!
//! hello.append_child(comment);
//! hello.append_child(text);
//! doc.root().append_child(hello);
//! ```
//!
//! ### Memory and ownership
//!
//! The `Package` struct is responsible for owning every node in the
//! document. Strings are interned, allowing repeated text to consume
//! less memory. This is very useful for documents containing lots of
//! the same attributes and tag names.
//!
//! The flip side of this decision is that allocated nodes and strings
//! are not deallocated until the entire `Package` is dropped. This is
//! a reasonable decision for two common cases: building up an XML
//! document and reading an XML document. You may wish to perform
//! large modifications to your data *before* creating a document.
//!
//! ### Namespaces, QNames, and Prefixes
//!
//! The names of elements and attributes may use namespaces. XML
//! namespacing uses URIs to uniquely distinguish items with the same
//! local name. A qualified name (`QName`) combines this optional URI
//! with the local name.
//!
//! When an XML document is represented as text, namespaces are given
//! a shorthand reference known as a prefix. Prefix names are
//! non-authoritative, and only the URI can be used to namespace a
//! name.
//!
//! Elements and attributes may specify a *preferred prefix*, which is
//! an indication of what the user would like to be used as a
//! prefix. There are times where the preferred prefix would cause a
//! conflict, and so an autogenerated prefix will be used instead.
//!
//! ### Design decisions
//!
//! Try to leverage the type system as much as possible.

#![cfg_attr(feature = "unstable", feature(core))]
#![cfg_attr(feature = "unstable", feature(test))]

extern crate typed_arena;

#[macro_use]
extern crate peresil;

use std::fmt;

mod str_ext;
mod string_pool;
mod raw;
mod str;

#[doc(hidden)]
pub mod thindom;
pub mod dom;
pub mod parser;
pub mod writer;

pub use str::XmlChar;

/// A prefixed name. This represents what is found in the string form
/// of an XML document, and does not apply any namespace mapping.
#[derive(Debug,Copy,Clone,PartialEq,Eq,PartialOrd,Ord)]
pub struct PrefixedName<'a> {
    prefix: Option<&'a str>,
    local_part: &'a str,
}

impl<'a> PrefixedName<'a> {
    /// Create a `PrefixedName` without a prefix
    pub fn new(local_part: &str) -> PrefixedName {
        PrefixedName::with_prefix(None, local_part)
    }

    /// Create a `PrefixedName` without an optional prefix
    pub fn with_prefix(prefix: Option<&'a str>, local_part: &'a str) -> PrefixedName<'a> {
        PrefixedName {
            prefix: prefix,
            local_part: local_part,
        }
    }

    pub fn prefix(&self) -> Option<&str> { self.prefix }
    pub fn local_part(&self) -> &str { self.local_part }
}

/// A namespace-qualified name. This represents the name of an element
/// or attribute *after* the prefix has been mapped to a specific
/// namespace.
#[derive(Debug,Copy,Clone,PartialEq)]
pub struct QName<'s> {
    namespace_uri: Option<&'s str>,
    local_part: &'s str,
}

impl<'s> QName<'s> {
    /// Create a `QName` without a namespace
    pub fn new(local_part: &'s str) -> QName<'s> {
        QName::with_namespace_uri(None, local_part)
    }

    /// Create a `QName` with an optional namespace
    pub fn with_namespace_uri(namespace_uri: Option<&'s str>, local_part: &'s str) -> QName<'s> {
        QName {
            namespace_uri: namespace_uri,
            local_part: local_part,
        }
    }

    pub fn namespace_uri(&self) -> Option<&'s str> { self.namespace_uri }
    pub fn local_part(&self) -> &'s str { self.local_part }
}

impl<'s> From<(&'s str, &'s str)> for QName<'s> {
    fn from(v: (&'s str, &'s str)) -> QName<'s> {
        QName { namespace_uri: Some(v.0), local_part: v.1 }
    }
}

impl<'s> From<&'s str> for QName<'s> {
    fn from(v: &'s str) -> QName<'s> {
        QName { namespace_uri: None, local_part: v }
    }
}

/// The main entrypoint to an XML document
///
/// This is an opaque structure that stores the internal details of
/// the XML document. Modify the document via `as_document`.
pub struct Package {
    storage: raw::Storage,
    connections: raw::Connections,
}

impl Package {
    pub fn new() -> Package {
        let s = raw::Storage::new();
        let root = s.create_root();
        Package {
            storage: s,
            connections: raw::Connections::new(root),
        }
    }

    pub fn as_document(&self) -> dom::Document {
        dom::Document::new(&self.storage, &self.connections)
    }

    #[doc(hidden)]
    pub fn as_thin_document(&self) -> (thindom::Storage, thindom::Connections) {
        let s = thindom::Storage::new(&self.storage);
        let c = thindom::Connections::new(&self.connections);
        (s, c)
    }
}

impl PartialEq for Package {
    fn eq(&self, other: &Package) -> bool {
        self as *const Package == other as *const Package
    }
}

impl fmt::Debug for Package {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Package")
    }
}
<commit_msg>Update feature flags for nightly<commit_after>//!
//! ```
//! use sxd_document::Package;
//! let package = Package::new();
//! let doc = package.as_document();
//!
//! let hello = doc.create_element("hello");
//! hello.set_attribute_value("planet", "Earth");
//! let comment = doc.create_comment("What about other planets?");
//! let text = doc.create_text("Greetings, Earthlings!");
//!
//! hello.append_child(comment);
//! hello.append_child(text);
//! doc.root().append_child(hello);
//! ```
//!
//! ### Memory and ownership
//!
//! The `Package` struct is responsible for owning every node in the
//! document. Strings are interned, allowing repeated text to consume
//! less memory. This is very useful for documents containing lots of
//! the same attributes and tag names.
//!
//! The flip side of this decision is that allocated nodes and strings
//! are not deallocated until the entire `Package` is dropped. This is
//! a reasonable decision for two common cases: building up an XML
//! document and reading an XML document. You may wish to perform
//! large modifications to your data *before* creating a document.
//!
//! ### Namespaces, QNames, and Prefixes
//!
//! The names of elements and attributes may use namespaces. XML
//! namespacing uses URIs to uniquely distinguish items with the same
//! local name. A qualified name (`QName`) combines this optional URI
//! with the local name.
//!
//! When an XML document is represented as text, namespaces are given
//! a shorthand reference known as a prefix. Prefix names are
//! non-authoritative, and only the URI can be used to namespace a
//! name.
//!
//! Elements and attributes may specify a *preferred prefix*, which is
//! an indication of what the user would like to be used as a
//! prefix. There are times where the preferred prefix would cause a
//! conflict, and so an autogenerated prefix will be used instead.
//!
//! ### Design decisions
//!
//! Try to leverage the type system as much as possible.

#![cfg_attr(feature = "unstable", feature(pattern))]
#![cfg_attr(feature = "unstable", feature(test))]

extern crate typed_arena;

#[macro_use]
extern crate peresil;

use std::fmt;

mod str_ext;
mod string_pool;
mod raw;
mod str;

#[doc(hidden)]
pub mod thindom;
pub mod dom;
pub mod parser;
pub mod writer;

pub use str::XmlChar;

/// A prefixed name. This represents what is found in the string form
/// of an XML document, and does not apply any namespace mapping.
#[derive(Debug,Copy,Clone,PartialEq,Eq,PartialOrd,Ord)]
pub struct PrefixedName<'a> {
    prefix: Option<&'a str>,
    local_part: &'a str,
}

impl<'a> PrefixedName<'a> {
    /// Create a `PrefixedName` without a prefix
    pub fn new(local_part: &str) -> PrefixedName {
        PrefixedName::with_prefix(None, local_part)
    }

    /// Create a `PrefixedName` without an optional prefix
    pub fn with_prefix(prefix: Option<&'a str>, local_part: &'a str) -> PrefixedName<'a> {
        PrefixedName {
            prefix: prefix,
            local_part: local_part,
        }
    }

    pub fn prefix(&self) -> Option<&str> { self.prefix }
    pub fn local_part(&self) -> &str { self.local_part }
}

/// A namespace-qualified name. This represents the name of an element
/// or attribute *after* the prefix has been mapped to a specific
/// namespace.
#[derive(Debug,Copy,Clone,PartialEq)]
pub struct QName<'s> {
    namespace_uri: Option<&'s str>,
    local_part: &'s str,
}

impl<'s> QName<'s> {
    /// Create a `QName` without a namespace
    pub fn new(local_part: &'s str) -> QName<'s> {
        QName::with_namespace_uri(None, local_part)
    }

    /// Create a `QName` with an optional namespace
    pub fn with_namespace_uri(namespace_uri: Option<&'s str>, local_part: &'s str) -> QName<'s> {
        QName {
            namespace_uri: namespace_uri,
            local_part: local_part,
        }
    }

    pub fn namespace_uri(&self) -> Option<&'s str> { self.namespace_uri }
    pub fn local_part(&self) -> &'s str { self.local_part }
}

impl<'s> From<(&'s str, &'s str)> for QName<'s> {
    fn from(v: (&'s str, &'s str)) -> QName<'s> {
        QName { namespace_uri: Some(v.0), local_part: v.1 }
    }
}

impl<'s> From<&'s str> for QName<'s> {
    fn from(v: &'s str) -> QName<'s> {
        QName { namespace_uri: None, local_part: v }
    }
}

/// The main entrypoint to an XML document
///
/// This is an opaque structure that stores the internal details of
/// the XML document. Modify the document via `as_document`.
pub struct Package {
    storage: raw::Storage,
    connections: raw::Connections,
}

impl Package {
    pub fn new() -> Package {
        let s = raw::Storage::new();
        let root = s.create_root();
        Package {
            storage: s,
            connections: raw::Connections::new(root),
        }
    }

    pub fn as_document(&self) -> dom::Document {
        dom::Document::new(&self.storage, &self.connections)
    }

    #[doc(hidden)]
    pub fn as_thin_document(&self) -> (thindom::Storage, thindom::Connections) {
        let s = thindom::Storage::new(&self.storage);
        let c = thindom::Connections::new(&self.connections);
        (s, c)
    }
}

impl PartialEq for Package {
    fn eq(&self, other: &Package) -> bool {
        self as *const Package == other as *const Package
    }
}

impl fmt::Debug for Package {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Package")
    }
}
<|endoftext|>