<commit_before>use std::default::Default;
use std::env;
use std::path::Path;

use syntax::ast;
use syntax::codemap;
use syntax::ext::base;
use syntax::fold::Folder;
use syntax::parse;
use syntax::parse::token;
use syntax::ptr::P;
use syntax::util::small_vector::SmallVector;

use bindgen::{Bindings, BindgenOptions, LinkType, Logger, self};

pub fn bindgen_macro(cx: &mut base::ExtCtxt, sp: codemap::Span, tts: &[ast::TokenTree]) -> Box<base::MacResult+'static> {
    let mut visit = BindgenArgsVisitor {
        options: Default::default(),
        seen_named: false
    };

    visit.options.builtins = true;
    if !parse_macro_opts(cx, tts, &mut visit) {
        return base::DummyResult::any(sp);
    }

    // Reparse clang_args as it is passed in string form
    let clang_args = visit.options.clang_args.connect(" ");
    visit.options.clang_args = parse_process_args(&clang_args[..]);

    if let Some(path) = bindgen::get_include_dir() {
        visit.options.clang_args.push("-I".to_owned());
        visit.options.clang_args.push(path);
    }

    // Set the working dir to the directory containing the invoking rs file so
    // that clang searches for headers relative to it rather than the crate root
    let filename = cx.codemap().span_to_filename(sp);
    let mod_dir = Path::new(&filename).parent().unwrap();
    let cwd = match env::current_dir() {
      Ok(d)   => d,
      Err(e)  => panic!("Invalid current working directory: {}", e),
    };
    let p = Path::new(mod_dir);
    if let Err(e) = env::set_current_dir(&p) {
      panic!("Failed to change to directory {}: {}", p.display(), e);
    };

    // We want the span for errors to just match the bindgen! symbol
    // instead of the whole invocation which can span multiple lines
    let mut short_span = sp;
    short_span.hi = short_span.lo + codemap::BytePos(8);

    let logger = MacroLogger { sp: short_span, cx: cx };

    let ret = match Bindings::generate(&visit.options, Some(&logger as &Logger), None) {
        Ok(bindings) => {
            // syntex_syntax is not compatible with libsyntax so convert to string and reparse
            let bindings_str = bindings.to_string();
            // Unfortunately we lose span information due to reparsing
            let mut parser = parse::new_parser_from_source_str(cx.parse_sess(), cx.cfg(), "(Auto-generated bindings)".to_string(), bindings_str);

            let mut items = Vec::new();
            while let Some(item) = parser.parse_item() {
                items.push(item);
            }

            Box::new(BindgenResult { items: Some(SmallVector::many(items)) }) as Box<base::MacResult>

        }
        Err(_) => base::DummyResult::any(sp)
    };

    let p = Path::new(&cwd);
    if let Err(e) = env::set_current_dir(&p) {
      panic!("Failed to return to directory {}: {}", p.display(), e);
    }

    ret
}

trait MacroArgsVisitor {
    fn visit_str(&mut self, name: Option<&str>, val: &str) -> bool;
    fn visit_int(&mut self, name: Option<&str>, val: i64) -> bool;
    fn visit_bool(&mut self, name: Option<&str>, val: bool) -> bool;
    fn visit_ident(&mut self, name: Option<&str>, ident: &str) -> bool;
}

struct BindgenArgsVisitor {
    pub options: BindgenOptions,
    seen_named: bool
}

impl MacroArgsVisitor for BindgenArgsVisitor {
    fn visit_str(&mut self, mut name: Option<&str>, val: &str) -> bool {
        if name.is_some() { self.seen_named = true; }
        else if !self.seen_named { name = Some("clang_args") }
        match name {
            Some("link") => self.options.links.push((val.to_string(), LinkType::Default)),
            Some("link_static") => self.options.links.push((val.to_string(), LinkType::Static)),
            Some("link_framework") => self.options.links.push((val.to_string(), LinkType::Framework)),
            Some("match") => self.options.match_pat.push(val.to_string()),
            Some("clang_args") => self.options.clang_args.push(val.to_string()),
            Some("enum_type") => self.options.override_enum_ty = val.to_string(),
            _ => return false
        }
        true
    }

    fn visit_int(&mut self, name: Option<&str>, _val: i64) -> bool {
        if name.is_some() { self.seen_named = true; }
        false
    }

    fn visit_bool(&mut self, name: Option<&str>, val: bool) -> bool {
        if name.is_some() { self.seen_named = true; }
        match name {
            Some("allow_unknown_types") => self.options.fail_on_unknown_type = !val,
            Some("emit_builtins") => self.options.builtins = val,
            _ => return false
        }
        true
    }

    fn visit_ident(&mut self, name: Option<&str>, _val: &str) -> bool {
        if name.is_some() { self.seen_named = true; }
        false
    }
}

// Parses macro invocations in the form [ident=|:]value where value is an ident or literal
// e.g. bindgen!(module_name, "header.h", emit_builtins=false, clang_args:"-I /usr/local/include")
fn parse_macro_opts(cx: &mut base::ExtCtxt, tts: &[ast::TokenTree], visit: &mut MacroArgsVisitor) -> bool {
    let mut parser = cx.new_parser_from_tts(tts);
    let mut args_good = true;

    loop {
        let mut name: Option<String> = None;
        let mut span = parser.span;

        // Check for [ident=]value and if found save ident to name
        if parser.look_ahead(1, |t| t == &token::Eq) {
            match parser.bump_and_get() {
                Ok(token::Ident(ident, _)) => {
                    let ident = parser.id_to_interned_str(ident);
                    name = Some(ident.to_string());
                    parser.expect(&token::Eq);
                },
                _ => {
                    cx.span_err(span, "invalid argument format");
                    return false
                }
            }
        }

        match parser.token {
            // Match [ident]
            token::Ident(val, _) => {
                let val = parser.id_to_interned_str(val);
                span.hi = parser.span.hi;
                parser.bump();

                // Bools are simply encoded as idents
                let ret = match &*val {
                    "true" => visit.visit_bool(as_str(&name), true),
                    "false" => visit.visit_bool(as_str(&name), false),
                    val => visit.visit_ident(as_str(&name), val)
                };
                if !ret {
                    cx.span_err(span, "invalid argument");
                    args_good = false;
                }
            }
            // Match [literal] and parse as an expression so we can expand macros
            _ => {
                let expr = cx.expander().fold_expr(parser.parse_expr());
                span.hi = expr.span.hi;
                match expr.node {
                    ast::ExprLit(ref lit) => {
                        let ret = match lit.node {
                            ast::LitStr(ref s, _) => visit.visit_str(as_str(&name), &*s),
                            ast::LitBool(b) => visit.visit_bool(as_str(&name), b),
                            ast::LitInt(i, ast::SignedIntLit(_, sign)) |
                            ast::LitInt(i, ast::UnsuffixedIntLit(sign)) => {
                                let i = i as i64;
                                let i = if sign == ast::Minus { -i } else { i };
                                visit.visit_int(as_str(&name), i)
                            },
                            ast::LitInt(i, ast::UnsignedIntLit(_)) => visit.visit_int(as_str(&name), i as i64),
                            _ => {
                                cx.span_err(span, "invalid argument format");
                                return false
                            }
                        };
                        if !ret {
                            cx.span_err(span, "invalid argument");
                            args_good = false;
                        }
                    },
                    _ => {
                        cx.span_err(span, "invalid argument format");
                        return false
                    }
                }
            }
        }

        if parser.eat(&token::Eof).is_ok() {
            return args_good
        }

        if parser.eat(&token::Comma).is_err() {
            cx.span_err(parser.span, "invalid argument format");
            return false
        }
    }
}

// I'm sure there's a nicer way of doing it
fn as_str<'a>(owned: &'a Option<String>) -> Option<&'a str> {
    match owned {
        &Some(ref s) => Some(&s[..]),
        &None => None
    }
}

#[derive(PartialEq, Eq)]
enum QuoteState {
    InNone,
    InSingleQuotes,
    InDoubleQuotes
}

fn parse_process_args(s: &str) -> Vec<String> {
    let s = s.trim();
    let mut parts = Vec::new();
    let mut quote_state = QuoteState::InNone;
    let mut positions = vec!(0);
    let mut last = ' ';
    for (i, c) in s.chars().chain(" ".chars()).enumerate() {
        match (last, c) {
            // Match \" set has_escaped and skip
            ('\\', '\"') => (),
            // Match \'
            ('\\', '\'') => (),
            // Match \<space>
            // Check we don't escape the final added space
            ('\\', ' ') if i < s.len() => (),
            // Match \\
            ('\\', '\\') => (),
            // Match <any>"
            (_, '\"') if quote_state == QuoteState::InNone => {
                quote_state = QuoteState::InDoubleQuotes;
                positions.push(i);
                positions.push(i + 1);
            },
            (_, '\"') if quote_state == QuoteState::InDoubleQuotes => {
                quote_state = QuoteState::InNone;
                positions.push(i);
                positions.push(i + 1);
            },
            // Match <any>'
            (_, '\'') if quote_state == QuoteState::InNone => {
                quote_state = QuoteState::InSingleQuotes;
                positions.push(i);
                positions.push(i + 1);
            },
            (_, '\'') if quote_state == QuoteState::InSingleQuotes => {
                quote_state = QuoteState::InNone;
                positions.push(i);
                positions.push(i + 1);
            },
            // Match <any><space>
            // If we are at the end of the string close any open quotes
            (_, ' ') if quote_state == QuoteState::InNone || i >= s.len() => {
                {
                    positions.push(i);

                    let starts = positions.iter().enumerate().filter(|&(i, _)| i % 2 == 0);
                    let ends = positions.iter().enumerate().filter(|&(i, _)| i % 2 == 1);

                    let part: Vec<String> = starts.zip(ends).map(|((_, start), (_, end))| s[*start..*end].to_string()).collect();

                    let part = part.connect("");

                    if part.len() > 0 {
                        // Remove any extra whitespace outside the quotes
                        let part = &part[..].trim();
                        // Replace quoted characters
                        let part = part.replace("\\\"", "\"");
                        let part = part.replace("\\\'", "\'");
                        let part = part.replace("\\ ", " ");
                        let part = part.replace("\\\\", "\\");
                        parts.push(part);
                    }
                }

                positions.clear();
                positions.push(i + 1);
            },
            (_, _) => ()
        }
        last = c;
    }
    parts
}

struct MacroLogger<'a, 'b:'a> {
    sp: codemap::Span,
    cx: &'a base::ExtCtxt<'b>
}

impl<'a, 'b> Logger for MacroLogger<'a, 'b> {
    fn error(&self, msg: &str) {
        self.cx.span_err(self.sp, msg)
    }

    fn warn(&self, msg: &str) {
        self.cx.span_warn(self.sp, msg)
    }
}

struct BindgenResult {
    items: Option<SmallVector<P<ast::Item>>>
}

impl base::MacResult for BindgenResult {
    fn make_items(mut self: Box<BindgenResult>) -> Option<SmallVector<P<ast::Item>>> {
        self.items.take()
    }
}

#[test]
fn test_parse_process_args() {
    assert_eq!(parse_process_args("a b c"),         vec!("a", "b", "c"));
    assert_eq!(parse_process_args("a \"b\" c"),     vec!("a", "b", "c"));
    assert_eq!(parse_process_args("a \'b\' c"),     vec!("a", "b", "c"));
    assert_eq!(parse_process_args("a \"b c\""),     vec!("a", "b c"));
    assert_eq!(parse_process_args("a \'\"b\"\' c"), vec!("a", "\"b\"", "c"));
    assert_eq!(parse_process_args("a b\\ c"),       vec!("a", "b c"));
    assert_eq!(parse_process_args("a b c\\"),       vec!("a", "b", "c\\"));
}
<commit_msg>Use parser.check(&token::Eof) rather than .eat().<commit_after>use std::default::Default;
use std::env;
use std::path::Path;

use syntax::ast;
use syntax::codemap;
use syntax::ext::base;
use syntax::fold::Folder;
use syntax::parse;
use syntax::parse::token;
use syntax::ptr::P;
use syntax::util::small_vector::SmallVector;

use bindgen::{Bindings, BindgenOptions, LinkType, Logger, self};

pub fn bindgen_macro(cx: &mut base::ExtCtxt, sp: codemap::Span, tts: &[ast::TokenTree]) -> Box<base::MacResult+'static> {
    let mut visit = BindgenArgsVisitor {
        options: Default::default(),
        seen_named: false
    };

    visit.options.builtins = true;
    if !parse_macro_opts(cx, tts, &mut visit) {
        return base::DummyResult::any(sp);
    }

    // Reparse clang_args as it is passed in string form
    let clang_args = visit.options.clang_args.connect(" ");
    visit.options.clang_args = parse_process_args(&clang_args[..]);

    if let Some(path) = bindgen::get_include_dir() {
        visit.options.clang_args.push("-I".to_owned());
        visit.options.clang_args.push(path);
    }

    // Set the working dir to the directory containing the invoking rs file so
    // that clang searches for headers relative to it rather than the crate root
    let filename = cx.codemap().span_to_filename(sp);
    let mod_dir = Path::new(&filename).parent().unwrap();
    let cwd = match env::current_dir() {
      Ok(d)   => d,
      Err(e)  => panic!("Invalid current working directory: {}", e),
    };
    let p = Path::new(mod_dir);
    if let Err(e) = env::set_current_dir(&p) {
      panic!("Failed to change to directory {}: {}", p.display(), e);
    };

    // We want the span for errors to just match the bindgen! symbol
    // instead of the whole invocation which can span multiple lines
    let mut short_span = sp;
    short_span.hi = short_span.lo + codemap::BytePos(8);

    let logger = MacroLogger { sp: short_span, cx: cx };

    let ret = match Bindings::generate(&visit.options, Some(&logger as &Logger), None) {
        Ok(bindings) => {
            // syntex_syntax is not compatible with libsyntax so convert to string and reparse
            let bindings_str = bindings.to_string();
            // Unfortunately we lose span information due to reparsing
            let mut parser = parse::new_parser_from_source_str(cx.parse_sess(), cx.cfg(), "(Auto-generated bindings)".to_string(), bindings_str);

            let mut items = Vec::new();
            while let Some(item) = parser.parse_item() {
                items.push(item);
            }

            Box::new(BindgenResult { items: Some(SmallVector::many(items)) }) as Box<base::MacResult>

        }
        Err(_) => base::DummyResult::any(sp)
    };

    let p = Path::new(&cwd);
    if let Err(e) = env::set_current_dir(&p) {
      panic!("Failed to return to directory {}: {}", p.display(), e);
    }

    ret
}

trait MacroArgsVisitor {
    fn visit_str(&mut self, name: Option<&str>, val: &str) -> bool;
    fn visit_int(&mut self, name: Option<&str>, val: i64) -> bool;
    fn visit_bool(&mut self, name: Option<&str>, val: bool) -> bool;
    fn visit_ident(&mut self, name: Option<&str>, ident: &str) -> bool;
}

struct BindgenArgsVisitor {
    pub options: BindgenOptions,
    seen_named: bool
}

impl MacroArgsVisitor for BindgenArgsVisitor {
    fn visit_str(&mut self, mut name: Option<&str>, val: &str) -> bool {
        if name.is_some() { self.seen_named = true; }
        else if !self.seen_named { name = Some("clang_args") }
        match name {
            Some("link") => self.options.links.push((val.to_string(), LinkType::Default)),
            Some("link_static") => self.options.links.push((val.to_string(), LinkType::Static)),
            Some("link_framework") => self.options.links.push((val.to_string(), LinkType::Framework)),
            Some("match") => self.options.match_pat.push(val.to_string()),
            Some("clang_args") => self.options.clang_args.push(val.to_string()),
            Some("enum_type") => self.options.override_enum_ty = val.to_string(),
            _ => return false
        }
        true
    }

    fn visit_int(&mut self, name: Option<&str>, _val: i64) -> bool {
        if name.is_some() { self.seen_named = true; }
        false
    }

    fn visit_bool(&mut self, name: Option<&str>, val: bool) -> bool {
        if name.is_some() { self.seen_named = true; }
        match name {
            Some("allow_unknown_types") => self.options.fail_on_unknown_type = !val,
            Some("emit_builtins") => self.options.builtins = val,
            _ => return false
        }
        true
    }

    fn visit_ident(&mut self, name: Option<&str>, _val: &str) -> bool {
        if name.is_some() { self.seen_named = true; }
        false
    }
}

// Parses macro invocations in the form [ident=|:]value where value is an ident or literal
// e.g. bindgen!(module_name, "header.h", emit_builtins=false, clang_args:"-I /usr/local/include")
fn parse_macro_opts(cx: &mut base::ExtCtxt, tts: &[ast::TokenTree], visit: &mut MacroArgsVisitor) -> bool {
    let mut parser = cx.new_parser_from_tts(tts);
    let mut args_good = true;

    loop {
        let mut name: Option<String> = None;
        let mut span = parser.span;

        // Check for [ident=]value and if found save ident to name
        if parser.look_ahead(1, |t| t == &token::Eq) {
            match parser.bump_and_get() {
                Ok(token::Ident(ident, _)) => {
                    let ident = parser.id_to_interned_str(ident);
                    name = Some(ident.to_string());
                    parser.expect(&token::Eq);
                },
                _ => {
                    cx.span_err(span, "invalid argument format");
                    return false
                }
            }
        }

        match parser.token {
            // Match [ident]
            token::Ident(val, _) => {
                let val = parser.id_to_interned_str(val);
                span.hi = parser.span.hi;
                parser.bump();

                // Bools are simply encoded as idents
                let ret = match &*val {
                    "true" => visit.visit_bool(as_str(&name), true),
                    "false" => visit.visit_bool(as_str(&name), false),
                    val => visit.visit_ident(as_str(&name), val)
                };
                if !ret {
                    cx.span_err(span, "invalid argument");
                    args_good = false;
                }
            }
            // Match [literal] and parse as an expression so we can expand macros
            _ => {
                let expr = cx.expander().fold_expr(parser.parse_expr());
                span.hi = expr.span.hi;
                match expr.node {
                    ast::ExprLit(ref lit) => {
                        let ret = match lit.node {
                            ast::LitStr(ref s, _) => visit.visit_str(as_str(&name), &*s),
                            ast::LitBool(b) => visit.visit_bool(as_str(&name), b),
                            ast::LitInt(i, ast::SignedIntLit(_, sign)) |
                            ast::LitInt(i, ast::UnsuffixedIntLit(sign)) => {
                                let i = i as i64;
                                let i = if sign == ast::Minus { -i } else { i };
                                visit.visit_int(as_str(&name), i)
                            },
                            ast::LitInt(i, ast::UnsignedIntLit(_)) => visit.visit_int(as_str(&name), i as i64),
                            _ => {
                                cx.span_err(span, "invalid argument format");
                                return false
                            }
                        };
                        if !ret {
                            cx.span_err(span, "invalid argument");
                            args_good = false;
                        }
                    },
                    _ => {
                        cx.span_err(span, "invalid argument format");
                        return false
                    }
                }
            }
        }

        if parser.check(&token::Eof) {
            return args_good
        }

        if parser.eat(&token::Comma).is_err() {
            cx.span_err(parser.span, "invalid argument format");
            return false
        }
    }
}

// I'm sure there's a nicer way of doing it
fn as_str<'a>(owned: &'a Option<String>) -> Option<&'a str> {
    match owned {
        &Some(ref s) => Some(&s[..]),
        &None => None
    }
}

#[derive(PartialEq, Eq)]
enum QuoteState {
    InNone,
    InSingleQuotes,
    InDoubleQuotes
}

fn parse_process_args(s: &str) -> Vec<String> {
    let s = s.trim();
    let mut parts = Vec::new();
    let mut quote_state = QuoteState::InNone;
    let mut positions = vec!(0);
    let mut last = ' ';
    for (i, c) in s.chars().chain(" ".chars()).enumerate() {
        match (last, c) {
            // Match \" set has_escaped and skip
            ('\\', '\"') => (),
            // Match \'
            ('\\', '\'') => (),
            // Match \<space>
            // Check we don't escape the final added space
            ('\\', ' ') if i < s.len() => (),
            // Match \\
            ('\\', '\\') => (),
            // Match <any>"
            (_, '\"') if quote_state == QuoteState::InNone => {
                quote_state = QuoteState::InDoubleQuotes;
                positions.push(i);
                positions.push(i + 1);
            },
            (_, '\"') if quote_state == QuoteState::InDoubleQuotes => {
                quote_state = QuoteState::InNone;
                positions.push(i);
                positions.push(i + 1);
            },
            // Match <any>'
            (_, '\'') if quote_state == QuoteState::InNone => {
                quote_state = QuoteState::InSingleQuotes;
                positions.push(i);
                positions.push(i + 1);
            },
            (_, '\'') if quote_state == QuoteState::InSingleQuotes => {
                quote_state = QuoteState::InNone;
                positions.push(i);
                positions.push(i + 1);
            },
            // Match <any><space>
            // If we are at the end of the string close any open quotes
            (_, ' ') if quote_state == QuoteState::InNone || i >= s.len() => {
                {
                    positions.push(i);

                    let starts = positions.iter().enumerate().filter(|&(i, _)| i % 2 == 0);
                    let ends = positions.iter().enumerate().filter(|&(i, _)| i % 2 == 1);

                    let part: Vec<String> = starts.zip(ends).map(|((_, start), (_, end))| s[*start..*end].to_string()).collect();

                    let part = part.connect("");

                    if part.len() > 0 {
                        // Remove any extra whitespace outside the quotes
                        let part = &part[..].trim();
                        // Replace quoted characters
                        let part = part.replace("\\\"", "\"");
                        let part = part.replace("\\\'", "\'");
                        let part = part.replace("\\ ", " ");
                        let part = part.replace("\\\\", "\\");
                        parts.push(part);
                    }
                }

                positions.clear();
                positions.push(i + 1);
            },
            (_, _) => ()
        }
        last = c;
    }
    parts
}

struct MacroLogger<'a, 'b:'a> {
    sp: codemap::Span,
    cx: &'a base::ExtCtxt<'b>
}

impl<'a, 'b> Logger for MacroLogger<'a, 'b> {
    fn error(&self, msg: &str) {
        self.cx.span_err(self.sp, msg)
    }

    fn warn(&self, msg: &str) {
        self.cx.span_warn(self.sp, msg)
    }
}

struct BindgenResult {
    items: Option<SmallVector<P<ast::Item>>>
}

impl base::MacResult for BindgenResult {
    fn make_items(mut self: Box<BindgenResult>) -> Option<SmallVector<P<ast::Item>>> {
        self.items.take()
    }
}

#[test]
fn test_parse_process_args() {
    assert_eq!(parse_process_args("a b c"),         vec!("a", "b", "c"));
    assert_eq!(parse_process_args("a \"b\" c"),     vec!("a", "b", "c"));
    assert_eq!(parse_process_args("a \'b\' c"),     vec!("a", "b", "c"));
    assert_eq!(parse_process_args("a \"b c\""),     vec!("a", "b c"));
    assert_eq!(parse_process_args("a \'\"b\"\' c"), vec!("a", "\"b\"", "c"));
    assert_eq!(parse_process_args("a b\\ c"),       vec!("a", "b c"));
    assert_eq!(parse_process_args("a b c\\"),       vec!("a", "b", "c\\"));
}
<|endoftext|>


<commit_before><commit_msg>EX-1872 stratagem: require at least one file (#2308)<commit_after><|endoftext|>


<commit_before>#[crate_type = "rlib"];

extern mod extra;
extern mod common;
extern mod math;

use std::iter;
use std::num::Zero;
use extra::rational::{Rational, Ratio};
use common::calc;
use math::numconv;

pub static EXPECTED_ANSWER: &'static str = "1258";

enum Op { Add, Sub, Mul, Div }

#[inline(always)]
fn each_numseq(f: |&[Rational]|) {
    for a in range(1, 10) {
        let ra = Ratio::from_integer(a);
        for b in range(a + 1, 10) {
            let rb = Ratio::from_integer(b);
            for c in range(b + 1, 10) {
                let rc = Ratio::from_integer(c);
                for d in range(c + 1, 10) {
                    let rd = Ratio::from_integer(d);
                    f(&[ra, rb, rc, rd]);
                }
            }
        }
    }
}

#[inline(always)]
fn each_opseq(f: |&[Op]|) {
    let ops = ~[ Add, Sub, Mul, Div ];
    for i1 in range(0, ops.len()) {
        for i2 in range(0, ops.len()) {
            for i3 in  range(0, ops.len()) {
                f(&[ops[i1], ops[i2], ops[i3]]);
            }
        }
    }
}

fn each_value(num: &[Rational], op: &[Op], f: |Rational|) {
    assert_eq!(num.len() - 1, op.len());
    if num.len() == 1 { f(num[0]); return }

    calc::combinate(num, 1, |v1, rest| {
            let a = v1[0];
            each_value(rest, op.tailn(1), |b| {
                    match op[0] {
                        Add => { f(a + b) }
                        Mul => { f(a * b) }
                        Sub => { f(a - b); f(b - a) }
                        Div => {
                            if !b.is_zero() { f(a / b) }
                            if !a.is_zero() { f(b / a) }
                        }
                    }
                });
            true
    });
}

fn count_seqlen(nums: &[Rational]) -> uint {
    let mut set = [false, .. 10000];

    each_opseq(|ops| {
        each_value(nums, ops, |n| {
            if n.is_integer() && n.numer().is_positive() {
                        set[n.to_integer()] = true;
            }
        });
    });

    iter::count(1u, 1)
        .take_while(|&i| set[i])
        .last()
        .unwrap_or(Zero::zero())
}

pub fn solve() -> ~str {
    let mut max_seq = ~"";
    let mut max_cnt = 0;
    each_numseq(|nums| {
        let cnt = count_seqlen(nums);
        if cnt > max_cnt {
            max_cnt = cnt;
            let ds = nums.rev_iter().map(|r| r.to_integer() as uint).to_owned_vec();
            max_seq = numconv::from_digits(ds, 10).to_str();
        }
    });

    return max_seq;
}
<commit_msg>some refactoring<commit_after>#[crate_type = "rlib"];

extern mod extra;
extern mod common;
extern mod math;

use std::iter;
use std::num::Zero;
use extra::rational::{Rational, Ratio};
use common::calc;
use math::numconv;

pub static EXPECTED_ANSWER: &'static str = "1258";

#[deriving(Clone)]
enum Op { Add, Sub, Mul, Div }

#[inline(always)]
fn each_numseq(f: |&[Rational]|) {
    calc::combinate(range(1, 10).map(Ratio::from_integer).to_owned_vec(), 4, |x, _| {f(x); true});
}

#[inline(always)]
fn each_opseq(f: |&[Op]|) {
    let ops = ~[ Add, Sub, Mul, Div ];
    for i1 in range(0, ops.len()) {
        for i2 in range(0, ops.len()) {
            for i3 in  range(0, ops.len()) {
                f(&[ops[i1], ops[i2], ops[i3]]);
            }
        }
    }
}

fn each_value(num: &[Rational], op: &[Op], f: |Rational|) {
    assert_eq!(num.len() - 1, op.len());
    if num.len() == 1 { f(num[0]); return }

    calc::combinate(num, 1, |v1, rest| {
            let a = v1[0];
            each_value(rest, op.tailn(1), |b| {
                    match op[0] {
                        Add => { f(a + b) }
                        Mul => { f(a * b) }
                        Sub => { f(a - b); f(b - a) }
                        Div => {
                            if !b.is_zero() { f(a / b) }
                            if !a.is_zero() { f(b / a) }
                        }
                    }
                });
            true
    });
}

fn count_seqlen(nums: &[Rational]) -> uint {
    let mut set = [false, .. 10000];

    each_opseq(|ops| {
        each_value(nums, ops, |n| {
            if n.is_integer() && n.numer().is_positive() {
                        set[n.to_integer()] = true;
            }
        });
    });

    iter::count(1u, 1)
        .take_while(|&i| set[i])
        .last()
        .unwrap_or(Zero::zero())
}

pub fn solve() -> ~str {
    let mut max_seq = ~"";
    let mut max_cnt = 0;
    each_numseq(|nums| {
        let cnt = count_seqlen(nums);
        if cnt > max_cnt {
            max_cnt = cnt;
            let ds = nums.rev_iter().map(|r| r.to_integer() as uint).to_owned_vec();
            max_seq = numconv::from_digits(ds, 10).to_str();
        }
    });

    return max_seq;
}
<|endoftext|>


<commit_before>//!
//! [`RawDevice`](RawDevice) and [`RawSurface`](RawSurface)
//! implementations using the atomic mode-setting infrastructure.
//!
//! Usually this implementation will wrapped into a [`GbmDevice`](::backend::drm::gbm::GbmDevice).
//! Take a look at `anvil`s source code for an example of this.
//!
//! For an example how to use this standalone, take a look at the raw_atomic_drm example.
//!

use std::cell::RefCell;
use std::collections::HashMap;
use std::os::unix::io::{AsRawFd, RawFd};
use std::rc::{Rc, Weak};
use std::sync::{
    atomic::{AtomicBool, Ordering},
    Arc,
};

use drm::control::{atomic::AtomicModeReq, AtomicCommitFlags, Device as ControlDevice, Event};
use drm::control::{
    connector, crtc, encoder, framebuffer, plane, property, PropertyValueSet, ResourceHandle, ResourceHandles,
};
use drm::SystemError as DrmError;
use drm::{ClientCapability, Device as BasicDevice};
use failure::{Fail, ResultExt};
use nix::libc::dev_t;
use nix::sys::stat::fstat;

use super::{common::Error, DevPath, Device, DeviceHandler, RawDevice};

mod surface;
pub use self::surface::AtomicDrmSurface;
use self::surface::AtomicDrmSurfaceInternal;

#[cfg(feature = "backend_session")]
pub mod session;

/// Open raw drm device utilizing atomic mode-setting
pub struct AtomicDrmDevice<A: AsRawFd + 'static> {
    dev: Rc<Dev<A>>,
    dev_id: dev_t,
    active: Arc<AtomicBool>,
    backends: Rc<RefCell<HashMap<crtc::Handle, Weak<AtomicDrmSurfaceInternal<A>>>>>,
    handler: Option<RefCell<Box<dyn DeviceHandler<Device = AtomicDrmDevice<A>>>>>,
    logger: ::slog::Logger,
}

type OldState = (
    Vec<(connector::Handle, PropertyValueSet)>,
    Vec<(crtc::Handle, PropertyValueSet)>,
    Vec<(framebuffer::Handle, PropertyValueSet)>,
    Vec<(plane::Handle, PropertyValueSet)>,
);

type Mapping = (
    HashMap<connector::Handle, HashMap<String, property::Handle>>,
    HashMap<crtc::Handle, HashMap<String, property::Handle>>,
    HashMap<framebuffer::Handle, HashMap<String, property::Handle>>,
    HashMap<plane::Handle, HashMap<String, property::Handle>>,
);

struct Dev<A: AsRawFd + 'static> {
    fd: A,
    privileged: bool,
    active: Arc<AtomicBool>,
    old_state: OldState,
    prop_mapping: Mapping,
    logger: ::slog::Logger,
}

impl<A: AsRawFd + 'static> AsRawFd for Dev<A> {
    fn as_raw_fd(&self) -> RawFd {
        self.fd.as_raw_fd()
    }
}
impl<A: AsRawFd + 'static> BasicDevice for Dev<A> {}
impl<A: AsRawFd + 'static> ControlDevice for Dev<A> {}
impl<A: AsRawFd + 'static> Drop for Dev<A> {
    fn drop(&mut self) {
        info!(self.logger, "Dropping device: {:?}", self.dev_path());
        if self.active.load(Ordering::SeqCst) {
            // Here we restore the card/tty's to it's previous state.
            // In case e.g. getty was running on the tty sets the correct framebuffer again,
            // so that getty will be visible.

            let mut req = AtomicModeReq::new();

            fn add_multiple_props<T: ResourceHandle>(
                req: &mut AtomicModeReq,
                old_state: &[(T, PropertyValueSet)],
            ) {
                for (handle, set) in old_state {
                    let (prop_handles, values) = set.as_props_and_values();
                    for (&prop_handle, &val) in prop_handles.iter().zip(values.iter()) {
                        req.add_raw_property((*handle).into(), prop_handle, val);
                    }
                }
            };

            add_multiple_props(&mut req, &self.old_state.0);
            add_multiple_props(&mut req, &self.old_state.1);
            add_multiple_props(&mut req, &self.old_state.2);
            add_multiple_props(&mut req, &self.old_state.3);

            if let Err(err) = self.atomic_commit(&[AtomicCommitFlags::AllowModeset], req) {
                error!(self.logger, "Failed to restore previous state. Error: {}", err);
            }
        }
        if self.privileged {
            if let Err(err) = self.release_master_lock() {
                error!(self.logger, "Failed to drop drm master state. Error: {}", err);
            }
        }
    }
}

impl<A: AsRawFd + 'static> AtomicDrmDevice<A> {
    /// Create a new [`AtomicDrmDevice`] from an open drm node
    ///
    /// Returns an error if the file is no valid drm node or context creation was not
    /// successful.
    pub fn new<L>(fd: A, logger: L) -> Result<Self, Error>
    where
        L: Into<Option<::slog::Logger>>,
    {
        let log = crate::slog_or_stdlog(logger).new(o!("smithay_module" => "backend_drm"));
        info!(log, "AtomicDrmDevice initializing");

        let dev_id = fstat(fd.as_raw_fd())
            .map_err(|source| Error::UnableToGetDeviceId(source))?
            .st_rdev;

        let active = Arc::new(AtomicBool::new(true));
        let mut dev = Dev {
            fd,
            privileged: true,
            active: active.clone(),
            old_state: (Vec::new(), Vec::new(), Vec::new(), Vec::new()),
            prop_mapping: (HashMap::new(), HashMap::new(), HashMap::new(), HashMap::new()),
            logger: log.clone(),
        };

        // we want to modeset, so we better be the master, if we run via a tty session
        if dev.acquire_master_lock().is_err() {
            warn!(log, "Unable to become drm master, assuming unprivileged mode");
            dev.privileged = false;
        };

        // enable the features we need
        dev.set_client_capability(ClientCapability::UniversalPlanes, true)
            .compat()
            .map_err(|source| Error::Access {
                errmsg: "Error enabling UniversalPlanes",
                dev: dev.dev_path(),
                source,
            })?;
        dev.set_client_capability(ClientCapability::Atomic, true)
            .compat()
            .map_err(|source| Error::Access {
                errmsg: "Error enabling AtomicModesetting",
                dev: dev.dev_path(),
                source,
            })?;

        // enumerate (and save) the current device state
        let res_handles = ControlDevice::resource_handles(&dev)
            .compat()
            .map_err(|source| Error::Access {
                errmsg: "Error loading drm resources",
                dev: dev.dev_path(),
                source,
            })?;

        let plane_handles = dev.plane_handles().compat().map_err(|source| Error::Access {
            errmsg: "Error loading planes",
            dev: dev.dev_path(),
            source,
        })?;
        let planes = plane_handles.planes();

        fn add_props<A, T>(
            dev: &Dev<A>,
            handles: &[T],
            state: &mut Vec<(T, PropertyValueSet)>,
        ) -> Result<(), Error>
        where
            A: AsRawFd + 'static,
            T: ResourceHandle,
        {
            let iter = handles.iter().map(|x| (x, dev.get_properties(*x)));
            if let Some(len) = iter.size_hint().1 {
                state.reserve_exact(len)
            }

            iter.map(|(x, y)| (*x, y))
                .try_for_each(|(x, y)| match y {
                    Ok(y) => {
                        state.push((x, y));
                        Ok(())
                    }
                    Err(err) => Err(err),
                })
                .compat()
                .map_err(|source| Error::Access {
                    errmsg: "Error reading properties",
                    dev: dev.dev_path(),
                    source,
                })
        }

        fn map_props<A, T>(
            dev: &Dev<A>,
            handles: &[T],
            mapping: &mut HashMap<T, HashMap<String, property::Handle>>,
        ) -> Result<(), Error>
        where
            A: AsRawFd + 'static,
            T: ResourceHandle + Eq + std::hash::Hash,
        {
            handles
                .iter()
                .map(|x| (x, dev.get_properties(*x)))
                .try_for_each(|(handle, props)| {
                    let mut map = HashMap::new();
                    //let prop_handles: PropertyValueSet = props.compat()?;
                    match props {
                        Ok(props) => {
                            let (prop_handles, _) = props.as_props_and_values();
                            for prop in prop_handles {
                                if let Ok(info) = dev.get_property(*prop) {
                                    let name = info.name().to_string_lossy().into_owned();
                                    map.insert(name, *prop);
                                }
                            }
                            mapping.insert(*handle, map);
                            Ok(())
                        }
                        Err(err) => Err(err),
                    }
                })
                .compat()
                .map_err(|source| Error::Access {
                    errmsg: "Error reading properties on {:?}",
                    dev: dev.dev_path(),
                    source,
                })
        }

        let mut old_state = dev.old_state.clone();
        let mut mapping = dev.prop_mapping.clone();

        add_props(&dev, res_handles.connectors(), &mut old_state.0)?;
        add_props(&dev, res_handles.crtcs(), &mut old_state.1)?;
        add_props(&dev, res_handles.framebuffers(), &mut old_state.2)?;
        add_props(&dev, planes, &mut old_state.3)?;

        map_props(&dev, res_handles.connectors(), &mut mapping.0)?;
        map_props(&dev, res_handles.crtcs(), &mut mapping.1)?;
        map_props(&dev, res_handles.framebuffers(), &mut mapping.2)?;
        map_props(&dev, planes, &mut mapping.3)?;

        dev.old_state = old_state;
        dev.prop_mapping = mapping;
        debug!(log, "Mapping: {:#?}", dev.prop_mapping);

        Ok(AtomicDrmDevice {
            dev: Rc::new(dev),
            dev_id,
            active,
            backends: Rc::new(RefCell::new(HashMap::new())),
            handler: None,
            logger: log.clone(),
        })
    }
}

impl<A: AsRawFd + 'static> AsRawFd for AtomicDrmDevice<A> {
    fn as_raw_fd(&self) -> RawFd {
        self.dev.as_raw_fd()
    }
}

impl<A: AsRawFd + 'static> BasicDevice for AtomicDrmDevice<A> {}
impl<A: AsRawFd + 'static> ControlDevice for AtomicDrmDevice<A> {}

impl<A: AsRawFd + 'static> Device for AtomicDrmDevice<A> {
    type Surface = AtomicDrmSurface<A>;

    fn device_id(&self) -> dev_t {
        self.dev_id
    }

    fn set_handler(&mut self, handler: impl DeviceHandler<Device = Self> + 'static) {
        self.handler = Some(RefCell::new(Box::new(handler)));
    }

    fn clear_handler(&mut self) {
        let _ = self.handler.take();
    }

    fn create_surface(&mut self, crtc: crtc::Handle) -> Result<AtomicDrmSurface<A>, Error> {
        if self.backends.borrow().contains_key(&crtc) {
            return Err(Error::CrtcAlreadyInUse(crtc));
        }

        if !self.active.load(Ordering::SeqCst) {
            return Err(Error::DeviceInactive);
        }

        let backend = Rc::new(AtomicDrmSurfaceInternal::new(
            self.dev.clone(),
            crtc,
            self.logger.new(o!("crtc" => format!("{:?}", crtc))),
        )?);

        self.backends.borrow_mut().insert(crtc, Rc::downgrade(&backend));
        Ok(AtomicDrmSurface(backend))
    }

    fn process_events(&mut self) {
        match self.receive_events() {
            Ok(events) => {
                for event in events {
                    if let Event::PageFlip(event) = event {
                        trace!(self.logger, "Got event!");
                        if self.active.load(Ordering::SeqCst) {
                            if self
                                .backends
                                .borrow()
                                .get(&event.crtc)
                                .iter()
                                .flat_map(|x| x.upgrade())
                                .next()
                                .is_some()
                            {
                                trace!(self.logger, "Handling event for backend {:?}", event.crtc);
                                if let Some(handler) = self.handler.as_ref() {
                                    handler.borrow_mut().vblank(event.crtc);
                                }
                            } else {
                                self.backends.borrow_mut().remove(&event.crtc);
                            }
                        } else {
                            debug!(self.logger, "Device not active. Ignoring PageFlip");
                        }
                    } else {
                        trace!(self.logger, "Unrelated event");
                    }
                }
            }
            Err(source) => {
                if let Some(handler) = self.handler.as_ref() {
                    handler.borrow_mut().error(Error::Access {
                        errmsg: "Error processing drm events",
                        dev: self.dev_path(),
                        source: source.compat(),
                    });
                }
            }
        }
    }

    fn resource_handles(&self) -> Result<ResourceHandles, Error> {
        ControlDevice::resource_handles(self)
            .compat()
            .map_err(|source| Error::Access {
                errmsg: "Error loading resource info",
                dev: self.dev_path(),
                source,
            })
    }

    fn get_connector_info(&self, conn: connector::Handle) -> Result<connector::Info, DrmError> {
        self.get_connector(conn)
    }
    fn get_crtc_info(&self, crtc: crtc::Handle) -> Result<crtc::Info, DrmError> {
        self.get_crtc(crtc)
    }
    fn get_encoder_info(&self, enc: encoder::Handle) -> Result<encoder::Info, DrmError> {
        self.get_encoder(enc)
    }
    fn get_framebuffer_info(&self, fb: framebuffer::Handle) -> Result<framebuffer::Info, DrmError> {
        self.get_framebuffer(fb)
    }
    fn get_plane_info(&self, plane: plane::Handle) -> Result<plane::Info, DrmError> {
        self.get_plane(plane)
    }
}

impl<A: AsRawFd + 'static> RawDevice for AtomicDrmDevice<A> {
    type Surface = AtomicDrmSurface<A>;
}

impl<A: AsRawFd + 'static> Drop for AtomicDrmDevice<A> {
    fn drop(&mut self) {
        self.clear_handler();
    }
}
<commit_msg>atomic: Move out `add/map_props` to `Dev`<commit_after>//!
//! [`RawDevice`](RawDevice) and [`RawSurface`](RawSurface)
//! implementations using the atomic mode-setting infrastructure.
//!
//! Usually this implementation will wrapped into a [`GbmDevice`](::backend::drm::gbm::GbmDevice).
//! Take a look at `anvil`s source code for an example of this.
//!
//! For an example how to use this standalone, take a look at the raw_atomic_drm example.
//!

use std::cell::RefCell;
use std::collections::HashMap;
use std::os::unix::io::{AsRawFd, RawFd};
use std::rc::{Rc, Weak};
use std::sync::{
    atomic::{AtomicBool, Ordering},
    Arc,
};

use drm::control::{atomic::AtomicModeReq, AtomicCommitFlags, Device as ControlDevice, Event};
use drm::control::{
    connector, crtc, encoder, framebuffer, plane, property, PropertyValueSet, ResourceHandle, ResourceHandles,
};
use drm::SystemError as DrmError;
use drm::{ClientCapability, Device as BasicDevice};
use failure::{Fail, ResultExt};
use nix::libc::dev_t;
use nix::sys::stat::fstat;

use super::{common::Error, DevPath, Device, DeviceHandler, RawDevice};

mod surface;
pub use self::surface::AtomicDrmSurface;
use self::surface::AtomicDrmSurfaceInternal;

#[cfg(feature = "backend_session")]
pub mod session;

/// Open raw drm device utilizing atomic mode-setting
pub struct AtomicDrmDevice<A: AsRawFd + 'static> {
    dev: Rc<Dev<A>>,
    dev_id: dev_t,
    active: Arc<AtomicBool>,
    backends: Rc<RefCell<HashMap<crtc::Handle, Weak<AtomicDrmSurfaceInternal<A>>>>>,
    handler: Option<RefCell<Box<dyn DeviceHandler<Device = AtomicDrmDevice<A>>>>>,
    logger: ::slog::Logger,
}

type OldState = (
    Vec<(connector::Handle, PropertyValueSet)>,
    Vec<(crtc::Handle, PropertyValueSet)>,
    Vec<(framebuffer::Handle, PropertyValueSet)>,
    Vec<(plane::Handle, PropertyValueSet)>,
);

type Mapping = (
    HashMap<connector::Handle, HashMap<String, property::Handle>>,
    HashMap<crtc::Handle, HashMap<String, property::Handle>>,
    HashMap<framebuffer::Handle, HashMap<String, property::Handle>>,
    HashMap<plane::Handle, HashMap<String, property::Handle>>,
);

struct Dev<A: AsRawFd + 'static> {
    fd: A,
    privileged: bool,
    active: Arc<AtomicBool>,
    old_state: OldState,
    prop_mapping: Mapping,
    logger: ::slog::Logger,
}

impl<A: AsRawFd + 'static> AsRawFd for Dev<A> {
    fn as_raw_fd(&self) -> RawFd {
        self.fd.as_raw_fd()
    }
}
impl<A: AsRawFd + 'static> BasicDevice for Dev<A> {}
impl<A: AsRawFd + 'static> ControlDevice for Dev<A> {}
impl<A: AsRawFd + 'static> Drop for Dev<A> {
    fn drop(&mut self) {
        info!(self.logger, "Dropping device: {:?}", self.dev_path());
        if self.active.load(Ordering::SeqCst) {
            // Here we restore the card/tty's to it's previous state.
            // In case e.g. getty was running on the tty sets the correct framebuffer again,
            // so that getty will be visible.

            let mut req = AtomicModeReq::new();

            fn add_multiple_props<T: ResourceHandle>(
                req: &mut AtomicModeReq,
                old_state: &[(T, PropertyValueSet)],
            ) {
                for (handle, set) in old_state {
                    let (prop_handles, values) = set.as_props_and_values();
                    for (&prop_handle, &val) in prop_handles.iter().zip(values.iter()) {
                        req.add_raw_property((*handle).into(), prop_handle, val);
                    }
                }
            };

            add_multiple_props(&mut req, &self.old_state.0);
            add_multiple_props(&mut req, &self.old_state.1);
            add_multiple_props(&mut req, &self.old_state.2);
            add_multiple_props(&mut req, &self.old_state.3);

            if let Err(err) = self.atomic_commit(&[AtomicCommitFlags::AllowModeset], req) {
                error!(self.logger, "Failed to restore previous state. Error: {}", err);
            }
        }
        if self.privileged {
            if let Err(err) = self.release_master_lock() {
                error!(self.logger, "Failed to drop drm master state. Error: {}", err);
            }
        }
    }
}

impl<A: AsRawFd + 'static> Dev<A> {
    // Add all properties of given handles to a given drm resource type to state.
    // You may use this to snapshot the current state of the drm device (fully or partially).
    fn add_props<T>(&self, handles: &[T], state: &mut Vec<(T, PropertyValueSet)>) -> Result<(), Error>
    where
        A: AsRawFd + 'static,
        T: ResourceHandle,
    {
        let iter = handles.iter().map(|x| (x, self.get_properties(*x)));
        if let Some(len) = iter.size_hint().1 {
            state.reserve_exact(len)
        }

        iter.map(|(x, y)| (*x, y))
            .try_for_each(|(x, y)| match y {
                Ok(y) => {
                    state.push((x, y));
                    Ok(())
                }
                Err(err) => Err(err),
            })
            .compat()
            .map_err(|source| Error::Access {
                errmsg: "Error reading properties",
                dev: self.dev_path(),
                source,
            })
    }

    /// Create a mapping of property names and handles for given handles of a given drm resource type.
    /// You may use this to easily lookup properties by name instead of going through this procedure manually.
    fn map_props<T>(
        &self,
        handles: &[T],
        mapping: &mut HashMap<T, HashMap<String, property::Handle>>,
    ) -> Result<(), Error>
    where
        A: AsRawFd + 'static,
        T: ResourceHandle + Eq + std::hash::Hash,
    {
        handles
            .iter()
            .map(|x| (x, self.get_properties(*x)))
            .try_for_each(|(handle, props)| {
                let mut map = HashMap::new();
                match props {
                    Ok(props) => {
                        let (prop_handles, _) = props.as_props_and_values();
                        for prop in prop_handles {
                            if let Ok(info) = self.get_property(*prop) {
                                let name = info.name().to_string_lossy().into_owned();
                                map.insert(name, *prop);
                            }
                        }
                        mapping.insert(*handle, map);
                        Ok(())
                    }
                    Err(err) => Err(err),
                }
            })
            .compat()
            .map_err(|source| Error::Access {
                errmsg: "Error reading properties on {:?}",
                dev: self.dev_path(),
                source,
            })
    }
}

impl<A: AsRawFd + 'static> AtomicDrmDevice<A> {
    /// Create a new [`AtomicDrmDevice`] from an open drm node
    ///
    /// Returns an error if the file is no valid drm node or context creation was not
    /// successful.
    pub fn new<L>(fd: A, logger: L) -> Result<Self, Error>
    where
        L: Into<Option<::slog::Logger>>,
    {
        let log = crate::slog_or_stdlog(logger).new(o!("smithay_module" => "backend_drm"));
        info!(log, "AtomicDrmDevice initializing");

        let dev_id = fstat(fd.as_raw_fd())
            .map_err(|source| Error::UnableToGetDeviceId(source))?
            .st_rdev;

        let active = Arc::new(AtomicBool::new(true));
        let mut dev = Dev {
            fd,
            privileged: true,
            active: active.clone(),
            old_state: (Vec::new(), Vec::new(), Vec::new(), Vec::new()),
            prop_mapping: (HashMap::new(), HashMap::new(), HashMap::new(), HashMap::new()),
            logger: log.clone(),
        };

        // we want to modeset, so we better be the master, if we run via a tty session
        if dev.acquire_master_lock().is_err() {
            warn!(log, "Unable to become drm master, assuming unprivileged mode");
            dev.privileged = false;
        };

        // enable the features we need
        dev.set_client_capability(ClientCapability::UniversalPlanes, true)
            .compat()
            .map_err(|source| Error::Access {
                errmsg: "Error enabling UniversalPlanes",
                dev: dev.dev_path(),
                source,
            })?;
        dev.set_client_capability(ClientCapability::Atomic, true)
            .compat()
            .map_err(|source| Error::Access {
                errmsg: "Error enabling AtomicModesetting",
                dev: dev.dev_path(),
                source,
            })?;

        // enumerate (and save) the current device state
        let res_handles = ControlDevice::resource_handles(&dev)
            .compat()
            .map_err(|source| Error::Access {
                errmsg: "Error loading drm resources",
                dev: dev.dev_path(),
                source,
            })?;

        let plane_handles = dev.plane_handles().compat().map_err(|source| Error::Access {
            errmsg: "Error loading planes",
            dev: dev.dev_path(),
            source,
        })?;
        let planes = plane_handles.planes();

        let mut old_state = dev.old_state.clone();
        let mut mapping = dev.prop_mapping.clone();

        dev.add_props(res_handles.connectors(), &mut old_state.0)?;
        dev.add_props(res_handles.crtcs(), &mut old_state.1)?;
        dev.add_props(res_handles.framebuffers(), &mut old_state.2)?;
        dev.add_props(planes, &mut old_state.3)?;

        dev.map_props(res_handles.connectors(), &mut mapping.0)?;
        dev.map_props(res_handles.crtcs(), &mut mapping.1)?;
        dev.map_props(res_handles.framebuffers(), &mut mapping.2)?;
        dev.map_props(planes, &mut mapping.3)?;

        dev.old_state = old_state;
        dev.prop_mapping = mapping;
        debug!(log, "Mapping: {:#?}", dev.prop_mapping);

        Ok(AtomicDrmDevice {
            dev: Rc::new(dev),
            dev_id,
            active,
            backends: Rc::new(RefCell::new(HashMap::new())),
            handler: None,
            logger: log.clone(),
        })
    }
}

impl<A: AsRawFd + 'static> AsRawFd for AtomicDrmDevice<A> {
    fn as_raw_fd(&self) -> RawFd {
        self.dev.as_raw_fd()
    }
}

impl<A: AsRawFd + 'static> BasicDevice for AtomicDrmDevice<A> {}
impl<A: AsRawFd + 'static> ControlDevice for AtomicDrmDevice<A> {}

impl<A: AsRawFd + 'static> Device for AtomicDrmDevice<A> {
    type Surface = AtomicDrmSurface<A>;

    fn device_id(&self) -> dev_t {
        self.dev_id
    }

    fn set_handler(&mut self, handler: impl DeviceHandler<Device = Self> + 'static) {
        self.handler = Some(RefCell::new(Box::new(handler)));
    }

    fn clear_handler(&mut self) {
        let _ = self.handler.take();
    }

    fn create_surface(&mut self, crtc: crtc::Handle) -> Result<AtomicDrmSurface<A>, Error> {
        if self.backends.borrow().contains_key(&crtc) {
            return Err(Error::CrtcAlreadyInUse(crtc));
        }

        if !self.active.load(Ordering::SeqCst) {
            return Err(Error::DeviceInactive);
        }

        let backend = Rc::new(AtomicDrmSurfaceInternal::new(
            self.dev.clone(),
            crtc,
            self.logger.new(o!("crtc" => format!("{:?}", crtc))),
        )?);

        self.backends.borrow_mut().insert(crtc, Rc::downgrade(&backend));
        Ok(AtomicDrmSurface(backend))
    }

    fn process_events(&mut self) {
        match self.receive_events() {
            Ok(events) => {
                for event in events {
                    if let Event::PageFlip(event) = event {
                        trace!(self.logger, "Got event!");
                        if self.active.load(Ordering::SeqCst) {
                            if self
                                .backends
                                .borrow()
                                .get(&event.crtc)
                                .iter()
                                .flat_map(|x| x.upgrade())
                                .next()
                                .is_some()
                            {
                                trace!(self.logger, "Handling event for backend {:?}", event.crtc);
                                if let Some(handler) = self.handler.as_ref() {
                                    handler.borrow_mut().vblank(event.crtc);
                                }
                            } else {
                                self.backends.borrow_mut().remove(&event.crtc);
                            }
                        } else {
                            debug!(self.logger, "Device not active. Ignoring PageFlip");
                        }
                    } else {
                        trace!(self.logger, "Unrelated event");
                    }
                }
            }
            Err(source) => {
                if let Some(handler) = self.handler.as_ref() {
                    handler.borrow_mut().error(Error::Access {
                        errmsg: "Error processing drm events",
                        dev: self.dev_path(),
                        source: source.compat(),
                    });
                }
            }
        }
    }

    fn resource_handles(&self) -> Result<ResourceHandles, Error> {
        ControlDevice::resource_handles(self)
            .compat()
            .map_err(|source| Error::Access {
                errmsg: "Error loading resource info",
                dev: self.dev_path(),
                source,
            })
    }

    fn get_connector_info(&self, conn: connector::Handle) -> Result<connector::Info, DrmError> {
        self.get_connector(conn)
    }
    fn get_crtc_info(&self, crtc: crtc::Handle) -> Result<crtc::Info, DrmError> {
        self.get_crtc(crtc)
    }
    fn get_encoder_info(&self, enc: encoder::Handle) -> Result<encoder::Info, DrmError> {
        self.get_encoder(enc)
    }
    fn get_framebuffer_info(&self, fb: framebuffer::Handle) -> Result<framebuffer::Info, DrmError> {
        self.get_framebuffer(fb)
    }
    fn get_plane_info(&self, plane: plane::Handle) -> Result<plane::Info, DrmError> {
        self.get_plane(plane)
    }
}

impl<A: AsRawFd + 'static> RawDevice for AtomicDrmDevice<A> {
    type Surface = AtomicDrmSurface<A>;
}

impl<A: AsRawFd + 'static> Drop for AtomicDrmDevice<A> {
    fn drop(&mut self) {
        self.clear_handler();
    }
}
<|endoftext|>


<commit_before>//! Encode `Node` nodes to HTML

use super::{attr, attr_itemtype_str, elem, json, EncodeContext, ToHtml};
use stencila_schema::Node;

/// Encode a `Node` to HTML
///
/// All node types that have an `impl ToHtml` should be listed here. Not all node types
/// are supported, in which case this function returns HTML indicating that that is the case.
impl ToHtml for Node {
    fn to_html(&self, context: &EncodeContext) -> String {
        match self {
            Node::Array(node) => node.to_html(context),
            Node::Article(node) => node.to_html(context),
            Node::AudioObject(node) => node.to_html(context),
            Node::Boolean(node) => node.to_html(context),
            Node::Cite(node) => node.to_html(context),
            Node::CiteGroup(node) => node.to_html(context),
            Node::Claim(node) => node.to_html(context),
            Node::CodeBlock(node) => node.to_html(context),
            Node::CodeChunk(node) => node.to_html(context),
            Node::CodeExpression(node) => node.to_html(context),
            Node::CodeFragment(node) => node.to_html(context),
            Node::Delete(node) => node.to_html(context),
            Node::Emphasis(node) => node.to_html(context),
            Node::Figure(node) => node.to_html(context),
            Node::Heading(node) => node.to_html(context),
            Node::ImageObject(node) => node.to_html(context),
            Node::Integer(node) => node.to_html(context),
            Node::Link(node) => node.to_html(context),
            Node::List(node) => node.to_html(context),
            Node::MathBlock(node) => node.to_html(context),
            Node::MathFragment(node) => node.to_html(context),
            Node::NontextualAnnotation(node) => node.to_html(context),
            Node::Note(node) => node.to_html(context),
            Node::Null(node) => node.to_html(context),
            Node::Number(node) => node.to_html(context),
            Node::Object(node) => node.to_html(context),
            Node::Paragraph(node) => node.to_html(context),
            Node::Quote(node) => node.to_html(context),
            Node::QuoteBlock(node) => node.to_html(context),
            // Wrap strings with the `itemtype` attribute (see note under `ToHtml` for `InlineContent`)
            // This encoding will be used in places such as `CodeChunk.outputs`, `CodeExpression.output` etc
            Node::String(node) => {
                elem("span", &[attr_itemtype_str("Text")], &node.to_html(context))
            }
            Node::Strong(node) => node.to_html(context),
            Node::Subscript(node) => node.to_html(context),
            Node::Superscript(node) => node.to_html(context),
            Node::Table(node) => node.to_html(context),
            Node::ThematicBreak(node) => node.to_html(context),
            Node::VideoObject(node) => node.to_html(context),
            _ => elem("div", &[attr("class", "unsupported")], &json(self)),
        }
    }
}
<commit_msg>fix(HTML encoding): Use `<pre>` for `Node::String` to retain pre-formatting<commit_after>//! Encode `Node` nodes to HTML

use super::{attr, attr_itemtype_str, elem, json, EncodeContext, ToHtml};
use stencila_schema::Node;

/// Encode a `Node` to HTML
///
/// All node types that have an `impl ToHtml` should be listed here. Not all node types
/// are supported, in which case this function returns HTML indicating that that is the case.
impl ToHtml for Node {
    fn to_html(&self, context: &EncodeContext) -> String {
        match self {
            Node::Array(node) => node.to_html(context),
            Node::Article(node) => node.to_html(context),
            Node::AudioObject(node) => node.to_html(context),
            Node::Boolean(node) => node.to_html(context),
            Node::Cite(node) => node.to_html(context),
            Node::CiteGroup(node) => node.to_html(context),
            Node::Claim(node) => node.to_html(context),
            Node::CodeBlock(node) => node.to_html(context),
            Node::CodeChunk(node) => node.to_html(context),
            Node::CodeExpression(node) => node.to_html(context),
            Node::CodeFragment(node) => node.to_html(context),
            Node::Delete(node) => node.to_html(context),
            Node::Emphasis(node) => node.to_html(context),
            Node::Figure(node) => node.to_html(context),
            Node::Heading(node) => node.to_html(context),
            Node::ImageObject(node) => node.to_html(context),
            Node::Integer(node) => node.to_html(context),
            Node::Link(node) => node.to_html(context),
            Node::List(node) => node.to_html(context),
            Node::MathBlock(node) => node.to_html(context),
            Node::MathFragment(node) => node.to_html(context),
            Node::NontextualAnnotation(node) => node.to_html(context),
            Node::Note(node) => node.to_html(context),
            Node::Null(node) => node.to_html(context),
            Node::Number(node) => node.to_html(context),
            Node::Object(node) => node.to_html(context),
            Node::Paragraph(node) => node.to_html(context),
            Node::Quote(node) => node.to_html(context),
            Node::QuoteBlock(node) => node.to_html(context),
            // Wrap strings in a `<pre>` with the `itemtype` attribute.
            // This encoding will be used in places such as `CodeChunk.outputs`, `CodeExpression.output` etc
            // where pre-formatting is important and wrapping in an element is needed for patches.
            // See note under `ToHtml` for `InlineContent` for how strings are handled in that context.
            Node::String(node) => {
                elem("pre", &[attr_itemtype_str("Text")], &node.to_html(context))
            }
            Node::Strong(node) => node.to_html(context),
            Node::Subscript(node) => node.to_html(context),
            Node::Superscript(node) => node.to_html(context),
            Node::Table(node) => node.to_html(context),
            Node::ThematicBreak(node) => node.to_html(context),
            Node::VideoObject(node) => node.to_html(context),
            _ => elem("div", &[attr("class", "unsupported")], &json(self)),
        }
    }
}
<|endoftext|>


<commit_before>pub fn encode(text: &str) -> String {
    if text.is_empty() {
        return "".to_string();
    }

    let mut last = text.chars().nth(0).unwrap();
    let mut count = 0;

    let mut result = String::new();

    for c in text.chars() {
        if c == last {
            count += 1;

            continue;
        }

        if count != 1 {
            result.push_str(&count.to_string());
        }

        result.push(last);

        last = c;
        count = 1;
    }

    // deal with the last one
    if count != 1 {
        result.push_str(&count.to_string());
    }
    result.push(last);

    result
}

pub fn decode(text: &str) -> String {
    let mut result = String::new();

    let mut count = 0;

    for c in text.chars() {
        if !c.is_numeric() {
            if count < 2 {
                result.push(c);
            } else {
                result.push_str(&std::iter::repeat(c).take(count).collect::<String>());
            }

            count = 0;

            continue;
        }

        count = count * 10 + c.to_digit(10).unwrap() as usize;
    }

    result
}
<commit_msg>Use peekable to simplify rust code for run-length-encoding<commit_after>pub fn encode(text: &str) -> String {

    let mut count = 0;
    let mut result = String::new();
    let mut iter = text.chars().peekable();

    while let Some(c) = iter.next() {
        count += 1;

        if iter.peek() != Some(&c) {
            if count > 1 {
                result.push_str(&count.to_string());
            }

            result.push(c);

            count = 0;
        }
    }

    result
}

pub fn decode(text: &str) -> String {
    let mut count = 0;
    let mut result = String::new();

    for c in text.chars() {
        if let Some(v) = c.to_digit(10) {
            count = count * 10 + v as usize;

            continue;
        }

        if count < 2 {
            result.push(c);
        } else {
            let s = std::iter::repeat(c).take(count).collect::<String>();

            result.push_str(&s);
        }

        count = 0;
    }

    result
}
<|endoftext|>


<commit_before>use mio::*;

struct LambdaPoll {
    poll: Poll,
    events: Events,
    token_provider: Box<Iterator<Item=Token>>,
}

impl LambdaPoll {
    fn new() -> LambdaPoll {
        LambdaPoll {
            poll: Poll::new().unwrap(),
            events: Events::with_capacity(1024),
            token_provider: Box::new((0..).map(|x| Token(x))),
        }
    }

}

pub trait EventHandler {
    fn on_ready(&self, ready: Ready);
}

impl<F> EventHandler for F where F: Fn(Ready) {
    fn on_ready(&self, ready: Ready) {
        self(ready);
    }
}
<commit_msg>HandlerTokenManager<commit_after>use mio::*;
use std::io;
use std::collections::HashMap;

struct HandlerTokenManager {
    token_provider: Box<Iterator<Item=Token>>,
    handlers: HashMap<Token, Box<EventHandler>>,
}

impl HandlerTokenManager {
    fn new() -> HandlerTokenManager {
        HandlerTokenManager {
            token_provider: Box::new((0..).map(|x| Token(x))),
            handlers: HashMap::new(),
        }
    }
    fn create(handler: &EventHandler) -> Token {
        Token(0)
    }
}

struct CallbackPoll {
    poll: Poll,
    events: Events,
    token_provider: Box<Iterator<Item=Token>>,
    handlers: HashMap<Token, Box<EventHandler>>
}

impl CallbackPoll {
    fn new() -> io::Result<CallbackPoll> {
        Ok(CallbackPoll {
            poll: try!(Poll::new()),
            events: Events::with_capacity(1024),
            token_provider: Box::new((0..).map(|x| Token(x))),
            handlers: HashMap::new(),
        })
    }

    fn register<E>(&self, handle: &E, handler: &EventHandler, interest: Ready, opts: PollOpt) -> io::Result<()>
            where E: Evented + ?Sized {
        //let token = self.token_provider.next();
        self.poll.register(handle, Token(0), interest, opts)
    }
}

pub trait EventHandler {
    fn on_ready(&self, ready: Ready);
}

impl<F> EventHandler for F where F: Fn(Ready) {
    fn on_ready(&self, ready: Ready) {
        self(ready);
    }
}
<|endoftext|>


<commit_before>use std::path;
use std::process;

use clap::{App, Arg, SubCommand};

use config;
use models;
use web;
use utils;

pub fn main() {
    let matches =
        App::new("mysteryshack")
        .version(env!("CARGO_PKG_VERSION"))
        .author("Markus Unterwaditzer & contributors")
        .about("A remoteStorage server.")
        .args_from_usage("-c --config=[CONFIG] 'Use specified config file, defaults to ./config'")
        .subcommand(SubCommand::with_name("serve")
                    .about("Start server"))
        .subcommand(SubCommand::with_name("user")
                    .about("User management")
                    .subcommand(SubCommand::with_name("create")
                                .about("Create a new user")
                                .arg(Arg::with_name("USERNAME")
                                     .help("The username")
                                     .required(true)
                                     .index(1)))
                    .subcommand(SubCommand::with_name("delete")
                                .about("Delete a user")
                                .arg(Arg::with_name("USERNAME")
                                     .help("The username")
                                     .required(true)
                                     .index(1)))
                    .subcommand_required(true))
        .subcommand_required(true)
        .get_matches();

    let config_path = path::Path::new(matches.value_of("CONFIG").unwrap_or("./config"));

    let config = match config::Config::read_file(config_path) {
        Ok(x) => x,
        Err(e) => {
            println!("Failed to parse config: {}", e);
            process::exit(1);
        }
    };

    if let Some(_) = matches.subcommand_matches("serve") {
        web::run_server(config);
    } else if let Some(user_matches) = matches.subcommand_matches("user") {
        if let Some(user_create_matches) = user_matches.subcommand_matches("create") {
            let username = user_create_matches.value_of("USERNAME").unwrap();

            let password_hash = match models::PasswordHash::from_password(
                utils::double_prompt("Password for new user: ")) {
                Ok(x) => x,
                Err(e) => {
                    println!("Failed to hash password: {}", e);
                    process::exit(1);
                }
            };

            match models::User::create(&config.data_path, username).map(|user| {
                user.set_password_hash(password_hash)
            }) {
                Ok(_) => (),
                Err(e) => {
                    println!("Failed to create user {}: {}", username, e);
                    process::exit(1);
                }
            };

            println!("Successfully created user {}", username);
        } else if let Some(user_delete_matches) = user_matches.subcommand_matches("delete") {
            let username = user_delete_matches.value_of("USERNAME").unwrap();
            let user = match models::User::get(&config.data_path, username) {
                Some(x) => x,
                None => {
                    println!("User does not exist: {}", username);
                    process::exit(1);
                }
            };

            println!("You are about to delete the user {} and ALL the user's user data. This
                     process is irreversible.", username);
            if !utils::prompt_confirm(format!("Do you want to delete the user {}?", username), false) {
                println!("Aborted!");
                process::exit(1);
            }

            match user.delete() {
                Ok(_) => println!("Successfully deleted user {}.", username),
                Err(e) => {
                    println!("Failed to delete user: {:?}", e);
                    process::exit(1);
                }
            };
        }
    }
}
<commit_msg>Clap upgrade<commit_after>use std::path;
use std::process;

use clap::{App, Arg, SubCommand};

use config;
use models;
use web;
use utils;

pub fn main() {
    let matches =
        App::new("mysteryshack")
        .version(env!("CARGO_PKG_VERSION"))
        .author("Markus Unterwaditzer & contributors")
        .about("A remoteStorage server.")
        .args_from_usage("-c, --config=[FILE] 'Use specified config file, defaults to ./config'")
        .subcommand(SubCommand::with_name("serve")
                    .about("Start server"))
        .subcommand(SubCommand::with_name("user")
                    .about("User management")
                    .subcommand(SubCommand::with_name("create")
                                .about("Create a new user")
                                .arg(Arg::with_name("USERNAME")
                                     .help("The username")
                                     .required(true)
                                     .index(1)))
                    .subcommand(SubCommand::with_name("delete")
                                .about("Delete a user")
                                .arg(Arg::with_name("USERNAME")
                                     .help("The username")
                                     .required(true)
                                     .index(1))))
        .get_matches();

    let config_path = path::Path::new(matches.value_of("config").unwrap_or("./config"));

    let config = match config::Config::read_file(config_path) {
        Ok(x) => x,
        Err(e) => {
            println!("Failed to parse config: {}", e);
            process::exit(1);
        }
    };

    if let Some(_) = matches.subcommand_matches("serve") {
        web::run_server(config);
    } else if let Some(user_matches) = matches.subcommand_matches("user") {
        if let Some(user_create_matches) = user_matches.subcommand_matches("create") {
            let username = user_create_matches.value_of("USERNAME").unwrap();

            let password_hash = match models::PasswordHash::from_password(
                utils::double_prompt("Password for new user: ")) {
                Ok(x) => x,
                Err(e) => {
                    println!("Failed to hash password: {}", e);
                    process::exit(1);
                }
            };

            match models::User::create(&config.data_path, username).map(|user| {
                user.set_password_hash(password_hash)
            }) {
                Ok(_) => (),
                Err(e) => {
                    println!("Failed to create user {}: {}", username, e);
                    process::exit(1);
                }
            };

            println!("Successfully created user {}", username);
        } else if let Some(user_delete_matches) = user_matches.subcommand_matches("delete") {
            let username = user_delete_matches.value_of("USERNAME").unwrap();
            let user = match models::User::get(&config.data_path, username) {
                Some(x) => x,
                None => {
                    println!("User does not exist: {}", username);
                    process::exit(1);
                }
            };

            println!("You are about to delete the user {} and ALL the user's user data. This
                     process is irreversible.", username);
            if !utils::prompt_confirm(format!("Do you want to delete the user {}?", username), false) {
                println!("Aborted!");
                process::exit(1);
            }

            match user.delete() {
                Ok(_) => println!("Successfully deleted user {}.", username),
                Err(e) => {
                    println!("Failed to delete user: {:?}", e);
                    process::exit(1);
                }
            };
        }
    }
}
<|endoftext|>