<commit_before>// A machine-local concurrent LSM tree based on B-tree implementation

use crate::index::btree::level::*;
use crate::index::btree::*;
use crate::index::trees::*;
use crate::ram::types::*;
use crate::ram::schema::{Field, Schema};
use crate::server;
use crate::client::AsyncClient;
use crate::ram::cell::Cell;
use std::{mem, ptr};
use std::sync::Arc;

pub const LSM_TREE_SCHEMA_NAME: &'static str = "NEB_LSM_TREE";
pub const LSM_TREE_LEVELS_NAME: &'static str = "levels";

lazy_static! {
    pub static ref LSM_TREE_SCHEMA_ID: u32 = key_hash(LSM_TREE_SCHEMA_NAME) as u32;
    pub static ref LSM_TREE_LEVELS_HASH: u64 = key_hash(LSM_TREE_LEVELS_NAME);
    pub static ref LSM_TREE_SCHEMA: Schema = lsm_treee_schema();
}

pub struct LSMTree {
    trees: [Box<dyn LevelTree>; NUM_LEVELS]
}

impl LSMTree {
    pub async fn create(neb: &Arc<server::NebServer>, neb_client: &Arc<AsyncClient>) -> Self {
        let tree_m = LevelMTree::new();
        let tree_1 = Level1Tree::new();
        let tree_2 = Level2Tree::new();
        let tree_3 = Level3Tree::new();
        let tree_4 = Level4Tree::new();
        tree_m.persist_root(neb).await;
        tree_1.persist_root(neb).await;
        tree_2.persist_root(neb).await;
        tree_3.persist_root(neb).await;
        tree_4.persist_root(neb).await;
        let level_ids = vec![
            tree_m.head_id(),
            tree_1.head_id(),
            tree_2.head_id(),
            tree_3.head_id(),
            tree_4.head_id()
        ];
        let mut cell_map = Map::new();
        cell_map.insert_key_id(*LSM_TREE_LEVELS_HASH, Value::Array(level_ids.iter().map(|id| id.value()).collect()));
        let lsm_tree_cell = Cell::new(&*LSM_TREE_SCHEMA, Value::Map(cell_map)).unwrap();
        neb_client.write_cell(lsm_tree_cell).await.unwrap().unwrap();
        Self {
            trees: [box tree_m, box tree_1, box tree_2, box tree_3, box tree_4]
        }
    }

    pub async fn recover(neb_client: &Arc<AsyncClient>, lsm_tree_id: Id) -> Self {
        let cell = neb_client.read_cell(lsm_tree_id).await.unwrap().unwrap();
        let trees = &cell.data[*LSM_TREE_LEVELS_HASH];
        let trees_m_val = &trees[0usize];
        let trees_1_val = &trees[1usize];
        let trees_2_val = &trees[2usize];
        let trees_3_val = &trees[3usize];
        let trees_4_val = &trees[4usize];

        let tree_m = LevelMTree::from_head_id(trees_m_val.Id().unwrap(), neb_client).await;
        let tree_1 = Level1Tree::from_head_id(trees_1_val.Id().unwrap(), neb_client).await;
        let tree_2 = Level2Tree::from_head_id(trees_2_val.Id().unwrap(), neb_client).await;
        let tree_3 = Level3Tree::from_head_id(trees_3_val.Id().unwrap(), neb_client).await;
        let tree_4 = Level4Tree::from_head_id(trees_4_val.Id().unwrap(), neb_client).await;

        Self {
            trees: [box tree_m, box tree_1, box tree_2, box tree_3, box tree_4]
        }
    }

    pub fn insert(&self, entry: &EntryKey) -> bool {
        self.trees[0].insert_into(entry)
    }

    pub fn delete(&self, entry: &EntryKey) -> bool {
        for tree in &self.trees {
            if tree.mark_key_deleted(entry) {
                return true;
            }
        }
        false
    }

}
fn lsm_treee_schema() -> Schema {
    Schema {
        id: *LSM_TREE_SCHEMA_ID,
        name: String::from(LSM_TREE_SCHEMA_NAME),
        key_field: None,
        str_key_field: None,
        is_dynamic: false,
        fields: Field::new(
            "*",
            0,
            false,
            false,
            Some(vec![
                Field::new(
                    LSM_TREE_LEVELS_NAME,
                    type_id_of(Type::Id),
                    false,
                    true,
                    None,
                    vec![],
                ),
            ]),
            vec![],
        ),
    }
}

impl_btree_level!(LEVEL_M);
type LevelMTreeKeySlice = [EntryKey; LEVEL_M];
type LevelMTreePtrSlice = [NodeCellRef; LEVEL_M + 1];
type LevelMTree = BPlusTree<LevelMTreeKeySlice, LevelMTreePtrSlice>;

impl_btree_level!(LEVEL_1);
type Level1TreeKeySlice = [EntryKey; LEVEL_1];
type Level1TreePtrSlice = [NodeCellRef; LEVEL_1 + 1];
type Level1Tree = BPlusTree<Level1TreeKeySlice, Level1TreePtrSlice>;

impl_btree_level!(LEVEL_2);
type Level2TreeKeySlice = [EntryKey; LEVEL_2];
type Level2TreePtrSlice = [NodeCellRef; LEVEL_2 + 1];
type Level2Tree = BPlusTree<Level2TreeKeySlice, Level2TreePtrSlice>;

impl_btree_level!(LEVEL_3);
type Level3TreeKeySlice = [EntryKey; LEVEL_3];
type Level3TreePtrSlice = [NodeCellRef; LEVEL_3 + 1];
type Level3Tree = BPlusTree<Level3TreeKeySlice, Level3TreePtrSlice>;

impl_btree_level!(LEVEL_4);
type Level4TreeKeySlice = [EntryKey; LEVEL_4];
type Level4TreePtrSlice = [NodeCellRef; LEVEL_4 + 1];
type Level4Tree = BPlusTree<Level4TreeKeySlice, Level4TreePtrSlice>;<commit_msg>LSM tree cursor<commit_after>// A machine-local concurrent LSM tree based on B-tree implementation

use crate::index::btree::level::*;
use crate::index::btree::*;
use crate::index::trees::*;
use crate::ram::types::*;
use crate::ram::schema::{Field, Schema};
use crate::server;
use crate::client::AsyncClient;
use crate::ram::cell::Cell;
use std::{mem, ptr};
use std::sync::Arc;

pub const LSM_TREE_SCHEMA_NAME: &'static str = "NEB_LSM_TREE";
pub const LSM_TREE_LEVELS_NAME: &'static str = "levels";
type LevelTrees = [Box<dyn LevelTree>; NUM_LEVELS];
type LevelCusors = [Box<dyn Cursor>; NUM_LEVELS];

lazy_static! {
    pub static ref LSM_TREE_SCHEMA_ID: u32 = key_hash(LSM_TREE_SCHEMA_NAME) as u32;
    pub static ref LSM_TREE_LEVELS_HASH: u64 = key_hash(LSM_TREE_LEVELS_NAME);
    pub static ref LSM_TREE_SCHEMA: Schema = lsm_treee_schema();
}

pub struct LSMTree {
    trees: LevelTrees
}

impl LSMTree {
    pub async fn create(neb: &Arc<server::NebServer>, neb_client: &Arc<AsyncClient>) -> Self {
        let tree_m = LevelMTree::new();
        let tree_1 = Level1Tree::new();
        let tree_2 = Level2Tree::new();
        let tree_3 = Level3Tree::new();
        let tree_4 = Level4Tree::new();
        tree_m.persist_root(neb).await;
        tree_1.persist_root(neb).await;
        tree_2.persist_root(neb).await;
        tree_3.persist_root(neb).await;
        tree_4.persist_root(neb).await;
        let level_ids = vec![
            tree_m.head_id(),
            tree_1.head_id(),
            tree_2.head_id(),
            tree_3.head_id(),
            tree_4.head_id()
        ];
        let mut cell_map = Map::new();
        cell_map.insert_key_id(*LSM_TREE_LEVELS_HASH, Value::Array(level_ids.iter().map(|id| id.value()).collect()));
        let lsm_tree_cell = Cell::new(&*LSM_TREE_SCHEMA, Value::Map(cell_map)).unwrap();
        neb_client.write_cell(lsm_tree_cell).await.unwrap().unwrap();
        Self {
            trees: [box tree_m, box tree_1, box tree_2, box tree_3, box tree_4]
        }
    }

    pub async fn recover(neb_client: &Arc<AsyncClient>, lsm_tree_id: Id) -> Self {
        let cell = neb_client.read_cell(lsm_tree_id).await.unwrap().unwrap();
        let trees = &cell.data[*LSM_TREE_LEVELS_HASH];
        let trees_m_val = &trees[0usize];
        let trees_1_val = &trees[1usize];
        let trees_2_val = &trees[2usize];
        let trees_3_val = &trees[3usize];
        let trees_4_val = &trees[4usize];

        let tree_m = LevelMTree::from_head_id(trees_m_val.Id().unwrap(), neb_client).await;
        let tree_1 = Level1Tree::from_head_id(trees_1_val.Id().unwrap(), neb_client).await;
        let tree_2 = Level2Tree::from_head_id(trees_2_val.Id().unwrap(), neb_client).await;
        let tree_3 = Level3Tree::from_head_id(trees_3_val.Id().unwrap(), neb_client).await;
        let tree_4 = Level4Tree::from_head_id(trees_4_val.Id().unwrap(), neb_client).await;

        Self {
            trees: [box tree_m, box tree_1, box tree_2, box tree_3, box tree_4]
        }
    }

    pub fn insert(&self, entry: &EntryKey) -> bool {
        self.trees[0].insert_into(entry)
    }

    pub fn delete(&self, entry: &EntryKey) -> bool {
        for tree in &self.trees {
            if tree.mark_key_deleted(entry) {
                return true;
            }
        }
        false
    }

    pub fn seek(&self, entry: &EntryKey, ordering: Ordering) -> LSMTreeCursor {
        LSMTreeCursor::new(entry, &self.trees, ordering)
    }
}

pub struct LSMTreeCursor {
    cursors: LevelCusors,
    current: Option<(usize, EntryKey)>,
    ordering: Ordering
}

impl LSMTreeCursor {
    fn new(key: &EntryKey, trees: &LevelTrees, ordering: Ordering) -> Self {
        let cursors = [
            trees[0].seek_for(key, ordering),
            trees[1].seek_for(key, ordering),
            trees[2].seek_for(key, ordering),
            trees[3].seek_for(key, ordering),
            trees[4].seek_for(key, ordering)
        ];
        let current = Self::leading_tree_key(&cursors, ordering);
        Self { cursors, current, ordering }
    }

    fn leading_tree_key(cursors: &LevelCusors, ordering: Ordering) -> Option<(usize, EntryKey)> {
        match ordering {
            Ordering::Forward => {
                cursors
                    .iter()
                    .enumerate()
                    .filter_map(|(i, c)| c.current().map(|c| (i, c)))
                    .min_by(|(_, x), (_, y)| x.cmp(y))
                    .map(|(i, k)| (i, k.clone()))
            },
            Ordering::Backward => {
                cursors
                    .iter()
                    .enumerate()
                    .filter_map(|(i, c)| c.current().map(|c| (i, c)))
                    .max_by(|(_, x), (_, y)| x.cmp(y))
                    .map(|(i, k)| (i, k.clone()))
            }
        }
    }
}

impl Cursor for LSMTreeCursor {
    fn current(&self) -> Option<&EntryKey> {
        self.current.as_ref().map(|(_, k)| k)
    }
    fn next(&mut self) -> bool {
        if let Some((tree_id, _)) = self.current {
            self.cursors[tree_id].next();
            let next_leading = Self::leading_tree_key(&self.cursors, self.ordering);
            let has_next = next_leading.is_some();
            self.current = next_leading;
            has_next
        } else {
            return false;
        }
    }
}

fn lsm_treee_schema() -> Schema {
    Schema {
        id: *LSM_TREE_SCHEMA_ID,
        name: String::from(LSM_TREE_SCHEMA_NAME),
        key_field: None,
        str_key_field: None,
        is_dynamic: false,
        fields: Field::new(
            "*",
            0,
            false,
            false,
            Some(vec![
                Field::new(
                    LSM_TREE_LEVELS_NAME,
                    type_id_of(Type::Id),
                    false,
                    true,
                    None,
                    vec![],
                ),
            ]),
            vec![],
        ),
    }
}

impl_btree_level!(LEVEL_M);
type LevelMTreeKeySlice = [EntryKey; LEVEL_M];
type LevelMTreePtrSlice = [NodeCellRef; LEVEL_M + 1];
type LevelMTree = BPlusTree<LevelMTreeKeySlice, LevelMTreePtrSlice>;

impl_btree_level!(LEVEL_1);
type Level1TreeKeySlice = [EntryKey; LEVEL_1];
type Level1TreePtrSlice = [NodeCellRef; LEVEL_1 + 1];
type Level1Tree = BPlusTree<Level1TreeKeySlice, Level1TreePtrSlice>;

impl_btree_level!(LEVEL_2);
type Level2TreeKeySlice = [EntryKey; LEVEL_2];
type Level2TreePtrSlice = [NodeCellRef; LEVEL_2 + 1];
type Level2Tree = BPlusTree<Level2TreeKeySlice, Level2TreePtrSlice>;

impl_btree_level!(LEVEL_3);
type Level3TreeKeySlice = [EntryKey; LEVEL_3];
type Level3TreePtrSlice = [NodeCellRef; LEVEL_3 + 1];
type Level3Tree = BPlusTree<Level3TreeKeySlice, Level3TreePtrSlice>;

impl_btree_level!(LEVEL_4);
type Level4TreeKeySlice = [EntryKey; LEVEL_4];
type Level4TreePtrSlice = [NodeCellRef; LEVEL_4 + 1];
type Level4Tree = BPlusTree<Level4TreeKeySlice, Level4TreePtrSlice>;<|endoftext|>


<commit_before>use super::{Tokenizer,Token};

use {
    Global,Module,Value,Expression,Type,Block,
    Signature,Function,Parameter,types
};
use std;

pub type Result<T> = std::result::Result<T,String>;

/// An IR parser.
pub struct Parser<I: Iterator<Item=char>>
{
    tokenizer: Tokenizer<I>,
    module: Module,
}

impl<I> Parser<I>
    where I: Iterator<Item=char>
{
    /// Creates a new parser.
    pub fn new(chars: I) -> Self {
        Parser {
            tokenizer: Tokenizer::new(chars),
            module: Module::empty(),
        }
    }

    /// Gets parser which preserves comments.
    pub fn preserve_comments(mut self) -> Self {
        self.tokenizer = self.tokenizer.preserve_comments();
        self
    }

    /// Eats tokens while a predicate is true.
    pub fn parse(mut self) -> Result<Module> {
        while self.tokenizer.peek().is_some() {
            try!(self.parse_next());
        }

        Ok(self.module)
    }

    fn parse_next(&mut self) -> Result<()> {
        try!(self.eat_new_lines());

        let first_token = match self.tokenizer.peek() {
            Some(result) => try!(result),
            None => return Ok(()),
        };

        if first_token == keywords::global() {
            self.parse_global()
        } else if first_token == keywords::function() {
            self.parse_function()
        } else {
            Err(format!("unexpected token: {}", first_token))
        }
    }

    fn eat_new_lines(&mut self) -> Result<()> {
        self.tokenizer.eat_while(|token| token.is_new_line())
    }

    fn parse_global(&mut self) -> Result<()> {
        self.assert(keywords::global());

        let name = try!(self.parse_global_identifier());
        try!(self.expect(Token::equal_sign()));
        let value = try!(self.parse_value());

        try!(self.expect(Token::new_line()));

        self.module.add_global(Global::new(name, value));
        Ok(())
    }

    fn parse_function(&mut self) -> Result<()> {
        self.assert(keywords::function());

        let name = try!(self.parse_global_identifier());
        let params = try!(self.parse_parameter_list());
        let returns = try!(self.parse_function_returns());
        let body = try!(self.parse_body());

        let signature = Signature::new(params, returns);
        let function = Function::new(name, signature, body);

        self.module.add_function(function);
        Ok(())
    }

    /// Parses a curly-brace contained list of blocks.
    fn parse_body(&mut self) -> Result<Vec<Block>> {
        try!(self.eat_whitespace());
        try!(self.expect(Token::left_curly_brace()));
        try!(self.eat_whitespace());

        let mut blocks = Vec::new();

        while try!(self.peek_something()) != Token::right_curly_brace() {
            let block = try!(self.parse_block());
            blocks.push(block);
        }

        try!(self.expect(Token::right_curly_brace()));

        Ok(blocks)
    }

    fn parse_block(&mut self) -> Result<Block> {
        try!(self.expect(Token::right_curly_brace()));
        unimplemented!();
    }

    fn parse_parameter_list(&mut self) -> Result<Vec<Parameter>> {
        try!(self.eat_whitespace());
        try!(self.expect(Token::left_parenthesis()));
        try!(self.eat_whitespace());

        let mut params = Vec::new();

        while try!(self.peek_something()) != Token::right_parenthesis() {
            try!(self.eat_whitespace());

            let name = try!(self.parse_local_identifier());
            try!(self.expect(Token::colon()));
            let ty = try!(self.parse_type());

            params.push(Parameter::new(name, ty));

            try!(self.maybe_eat(Token::comma()));
            try!(self.eat_whitespace());
        }

        self.assert(Token::right_parenthesis());

        Ok(params)
    }

    fn parse_type_list(&mut self) -> Result<Vec<Type>> {
        try!(self.eat_whitespace());

        let mut types = Vec::new();

        while try!(self.peek_something()) != Token::left_curly_brace() {
            try!(self.eat_whitespace());

            let ty = try!(self.parse_type());
            types.push(ty);

            try!(self.maybe_eat(Token::comma()));
            try!(self.eat_whitespace());
        }

        Ok(types)
    }

    fn parse_function_returns(&mut self) -> Result<Vec<Type>> {
        try!(self.eat_whitespace());
        let first_token = try!(self.peek_something());

        if first_token == Token::function_arrow() {
            self.assert(Token::function_arrow());
            try!(self.eat_whitespace());

            self.parse_type_list()
        } else if first_token == Token::left_curly_brace() {
            Ok(Vec::new())
        } else {
            Err(format!("expected -> or {{ but got {}", first_token))
        }
    }

    fn parse_value(&mut self) -> Result<Value> {
        self.parse_expression().map(|expr| Value::new(expr))
    }

    fn parse_type(&mut self) -> Result<Type> {
        let first_token =  try!(self.expect_something());

        match first_token {
            Token::Word(first_word) => self.parse_word_type(first_word),
            _ => Err(format!("unknown token for type: {}",
                             first_token)),
        }
    }

    fn parse_word_type(&mut self, first_word: String)
        -> Result<Type> {
        if util::is_integer_type(&first_word) {
            self.parse_integer_type(&first_word).map(|t| t.into())
        } else {
            Err(format!("unknown type: {}", first_word))
        }
    }

    fn parse_expression(&mut self) -> Result<Expression> {
        let first_token = try!(self.expect_something());

        match first_token {
            Token::Word(word) => self.parse_word_expression(word),
            Token::String(string) => self.parse_string_expression(string),
            _ => Err("unknown token for expression".into()),
        }
    }

    fn parse_word_expression(&mut self, first_word: String)
        -> Result<Expression> {
        if util::is_integer_type(&first_word) {
            self.parse_integer_expression(&first_word)
        } else {
            Err("unknown token for expression".into())
        }
    }

    fn parse_integer_expression(&mut self, type_word: &str)
        -> Result<Expression> {
        debug_assert!(type_word.starts_with('i') || type_word.starts_with('u'));

        let ty = try!(self.parse_integer_type(type_word));
        let value = try!(self.expect_integer());

        Ok(Expression::integer(ty, value).unwrap())
    }

    fn parse_string_expression(&mut self, _string: String)
        -> Result<Expression> {
        unimplemented!();
    }

    fn parse_integer_type(&mut self, type_str: &str)
        -> Result<types::Integer> {
        let kind = match type_str.chars().next().unwrap() {
            'i' => ::util::IntegerKind::Signed,
            'u' => ::util::IntegerKind::Unsigned,
            _ => unreachable!(),
        };

        let width_str: String = type_str.chars().skip(1).collect();
        let width = try!(util::parse_integer(&width_str, 10));

        Ok(types::Integer::new(kind, width as u16))
    }

    fn parse_global_identifier(&mut self) -> Result<String> {
        try!(self.expect(Token::at_sign()));
        self.expect_word()
    }

    fn parse_local_identifier(&mut self) -> Result<String> {
        try!(self.expect(Token::percent_sign()));
        self.expect_word()
    }

    fn assert(&mut self, expected: Token) {
        self.expect(expected).unwrap();
    }

    fn expect_something(&mut self) -> Result<Token> {
        util::expect(self.tokenizer.next())
    }

    fn peek_something(&mut self) -> Result<Token> {
        util::expect(self.tokenizer.peek())
    }

    fn maybe_eat(&mut self, token: Token) -> Result<()> {
        match self.tokenizer.peek() {
            Some(Ok(peeked)) => {
                if peeked == token {
                    self.tokenizer.eat();
                }

                Ok(())
            },
            Some(Err(e)) => Err(e),
            None => Ok(()),
        }
    }

    fn expect(&mut self, expected: Token) -> Result<Token> {
        // TODO: this could be a more descriptive error message
        self.expect_one_of(&[expected])
    }

    fn expect_one_of(&mut self, expected: &[Token]) -> Result<Token> {
        assert!(!expected.is_empty());
        let token = try!(util::expect(self.tokenizer.next()));

        if expected.iter().any(|e| e==&token) {
            Ok(token)
        } else {
            if expected.len() == 1 {
                Err(format!("expected {} but got {}",
                            expected[0], token))
            } else { // multiple expected tokens
                Err(format!("expected one of {} but got {}",
                            ::util::comma_separated_values(expected.iter()),
                            token))
            }
        }
    }

    fn expect_word(&mut self) -> Result<String> {
        match self.expect_something() {
            Ok(ref token) => match *token {
                Token::Word(ref w) => Ok(w.clone()),
                _ => Err("expected a word".into()),
            },
            Err(e) => Err(e),
        }
    }

    fn expect_integer(&mut self) -> Result<i64> {
        match self.expect_something() {
            Ok(ref token) => match *token {
                Token::Integer(i) => Ok(i),
                _ => Err("expected an integer".into()),
            },
            Err(e) => Err(e),
        }
    }

    fn eat_whitespace(&mut self) -> Result<()> {
        self.tokenizer.eat_while(|t| t.is_new_line())
    }
}

pub mod util
{
    /// Expects that an `Option<Result>` is `Some`.
    // TODO: give this a name that doesn't clash with Parser::expect
    pub fn expect<T>(val: Option<Result<T,String>>) -> Result<T,String> {
        match val {
            Some(result) => result,
            None => Err("expected a token".into()),
        }
    }

    pub fn is_integer_type(word: &str) -> bool {
        if word.starts_with('i') || word.starts_with('u') {
            let next_part: String = word.chars().skip(1).collect();

            is_integer(&next_part, 10)
        } else {
            false
        }
    }

    pub fn is_integer(string: &str, radix: u32) -> bool {
        parse_integer(string, radix).is_ok()
    }

    pub fn parse_integer(string: &str, radix: u32) -> Result<i64,String> {
        match i64::from_str_radix(string, radix) {
            Ok(i) => Ok(i),
            Err(..) => Err("could not parse integer".into()),
        }
    }
}

pub mod keywords
{
    use read::Token;

    pub fn global() -> Token {
        Token::word("global")
    }

    pub fn function() -> Token {
        Token::word("fn")
    }
}

#[allow(unused_imports)]
mod test
{
    use super::Parser;
    use {Value,Function,Signature};

    #[cfg(test)]
    fn parse(text: &str) -> ::Module {
        Parser::new(text.chars()).parse().expect("parsing failed")
    }

    macro_rules! expect_global {
        ($input:expr => $name:expr, $value:expr) => {
            {
                let module = parse($input);

                let global = module.globals()
                                   .next()
                                   .expect("no globals were parsed");

                assert_eq!(global.name(), $name);
                assert_eq!(global.value(), &$value);
            }
        }
    }

    #[test]
    fn globals() {
        expect_global!("global ABCD = i32 5" => "ABCD", Value::i32(5));

        expect_global!("global hello_world = u127 38"
                       => "hello_world", Value::u(127, 38));

        expect_global!("global ewf = i16 52" => "ewf", Value::i(16, 52));
    }
}

<commit_msg>Fixed IR tests<commit_after>use super::{Tokenizer,Token};

use {
    Global,Module,Value,Expression,Type,Block,
    Signature,Function,Parameter,types
};
use std;

pub type Result<T> = std::result::Result<T,String>;

/// An IR parser.
pub struct Parser<I: Iterator<Item=char>>
{
    tokenizer: Tokenizer<I>,
    module: Module,
}

impl<I> Parser<I>
    where I: Iterator<Item=char>
{
    /// Creates a new parser.
    pub fn new(chars: I) -> Self {
        Parser {
            tokenizer: Tokenizer::new(chars),
            module: Module::empty(),
        }
    }

    /// Gets parser which preserves comments.
    pub fn preserve_comments(mut self) -> Self {
        self.tokenizer = self.tokenizer.preserve_comments();
        self
    }

    /// Eats tokens while a predicate is true.
    pub fn parse(mut self) -> Result<Module> {
        while self.tokenizer.peek().is_some() {
            try!(self.parse_next());
        }

        Ok(self.module)
    }

    fn parse_next(&mut self) -> Result<()> {
        try!(self.eat_new_lines());

        let first_token = match self.tokenizer.peek() {
            Some(result) => try!(result),
            None => return Ok(()),
        };

        if first_token == keywords::global() {
            self.parse_global()
        } else if first_token == keywords::function() {
            self.parse_function()
        } else {
            Err(format!("unexpected token: {}", first_token))
        }
    }

    fn eat_new_lines(&mut self) -> Result<()> {
        self.tokenizer.eat_while(|token| token.is_new_line())
    }

    fn parse_global(&mut self) -> Result<()> {
        self.assert(keywords::global());

        let name = try!(self.parse_global_identifier());
        try!(self.expect(Token::equal_sign()));
        let value = try!(self.parse_value());

        try!(self.expect(Token::new_line()));

        self.module.add_global(Global::new(name, value));
        Ok(())
    }

    fn parse_function(&mut self) -> Result<()> {
        self.assert(keywords::function());

        let name = try!(self.parse_global_identifier());
        let params = try!(self.parse_parameter_list());
        let returns = try!(self.parse_function_returns());
        let body = try!(self.parse_body());

        let signature = Signature::new(params, returns);
        let function = Function::new(name, signature, body);

        self.module.add_function(function);
        Ok(())
    }

    /// Parses a curly-brace contained list of blocks.
    fn parse_body(&mut self) -> Result<Vec<Block>> {
        try!(self.eat_whitespace());
        try!(self.expect(Token::left_curly_brace()));
        try!(self.eat_whitespace());

        let mut blocks = Vec::new();

        while try!(self.peek_something()) != Token::right_curly_brace() {
            let block = try!(self.parse_block());
            blocks.push(block);
        }

        try!(self.expect(Token::right_curly_brace()));

        Ok(blocks)
    }

    fn parse_block(&mut self) -> Result<Block> {
        try!(self.expect(Token::right_curly_brace()));
        unimplemented!();
    }

    fn parse_parameter_list(&mut self) -> Result<Vec<Parameter>> {
        try!(self.eat_whitespace());
        try!(self.expect(Token::left_parenthesis()));
        try!(self.eat_whitespace());

        let mut params = Vec::new();

        while try!(self.peek_something()) != Token::right_parenthesis() {
            try!(self.eat_whitespace());

            let name = try!(self.parse_local_identifier());
            try!(self.expect(Token::colon()));
            let ty = try!(self.parse_type());

            params.push(Parameter::new(name, ty));

            try!(self.maybe_eat(Token::comma()));
            try!(self.eat_whitespace());
        }

        self.assert(Token::right_parenthesis());

        Ok(params)
    }

    fn parse_type_list(&mut self) -> Result<Vec<Type>> {
        try!(self.eat_whitespace());

        let mut types = Vec::new();

        while try!(self.peek_something()) != Token::left_curly_brace() {
            try!(self.eat_whitespace());

            let ty = try!(self.parse_type());
            types.push(ty);

            try!(self.maybe_eat(Token::comma()));
            try!(self.eat_whitespace());
        }

        Ok(types)
    }

    fn parse_function_returns(&mut self) -> Result<Vec<Type>> {
        try!(self.eat_whitespace());
        let first_token = try!(self.peek_something());

        if first_token == Token::function_arrow() {
            self.assert(Token::function_arrow());
            try!(self.eat_whitespace());

            self.parse_type_list()
        } else if first_token == Token::left_curly_brace() {
            Ok(Vec::new())
        } else {
            Err(format!("expected -> or {{ but got {}", first_token))
        }
    }

    fn parse_value(&mut self) -> Result<Value> {
        self.parse_expression().map(|expr| Value::new(expr))
    }

    fn parse_type(&mut self) -> Result<Type> {
        let first_token =  try!(self.expect_something());

        match first_token {
            Token::Word(first_word) => self.parse_word_type(first_word),
            _ => Err(format!("unknown token for type: {}",
                             first_token)),
        }
    }

    fn parse_word_type(&mut self, first_word: String)
        -> Result<Type> {
        if util::is_integer_type(&first_word) {
            self.parse_integer_type(&first_word).map(|t| t.into())
        } else {
            Err(format!("unknown type: {}", first_word))
        }
    }

    fn parse_expression(&mut self) -> Result<Expression> {
        let first_token = try!(self.expect_something());

        match first_token {
            Token::Word(word) => self.parse_word_expression(word),
            Token::String(string) => self.parse_string_expression(string),
            _ => Err("unknown token for expression".into()),
        }
    }

    fn parse_word_expression(&mut self, first_word: String)
        -> Result<Expression> {
        if util::is_integer_type(&first_word) {
            self.parse_integer_expression(&first_word)
        } else {
            Err("unknown token for expression".into())
        }
    }

    fn parse_integer_expression(&mut self, type_word: &str)
        -> Result<Expression> {
        debug_assert!(type_word.starts_with('i') || type_word.starts_with('u'));

        let ty = try!(self.parse_integer_type(type_word));
        let value = try!(self.expect_integer());

        Ok(Expression::integer(ty, value).unwrap())
    }

    fn parse_string_expression(&mut self, _string: String)
        -> Result<Expression> {
        unimplemented!();
    }

    fn parse_integer_type(&mut self, type_str: &str)
        -> Result<types::Integer> {
        let kind = match type_str.chars().next().unwrap() {
            'i' => ::util::IntegerKind::Signed,
            'u' => ::util::IntegerKind::Unsigned,
            _ => unreachable!(),
        };

        let width_str: String = type_str.chars().skip(1).collect();
        let width = try!(util::parse_integer(&width_str, 10));

        Ok(types::Integer::new(kind, width as u16))
    }

    fn parse_global_identifier(&mut self) -> Result<String> {
        try!(self.expect(Token::at_sign()));
        self.expect_word()
    }

    fn parse_local_identifier(&mut self) -> Result<String> {
        try!(self.expect(Token::percent_sign()));
        self.expect_word()
    }

    fn assert(&mut self, expected: Token) {
        self.expect(expected).unwrap();
    }

    fn expect_something(&mut self) -> Result<Token> {
        util::expect(self.tokenizer.next())
    }

    fn peek_something(&mut self) -> Result<Token> {
        util::expect(self.tokenizer.peek())
    }

    fn maybe_eat(&mut self, token: Token) -> Result<()> {
        match self.tokenizer.peek() {
            Some(Ok(peeked)) => {
                if peeked == token {
                    self.tokenizer.eat();
                }

                Ok(())
            },
            Some(Err(e)) => Err(e),
            None => Ok(()),
        }
    }

    fn expect(&mut self, expected: Token) -> Result<Token> {
        // TODO: this could be a more descriptive error message
        self.expect_one_of(&[expected])
    }

    fn expect_one_of(&mut self, expected: &[Token]) -> Result<Token> {
        assert!(!expected.is_empty());
        let token = try!(util::expect(self.tokenizer.next()));

        if expected.iter().any(|e| e==&token) {
            Ok(token)
        } else {
            if expected.len() == 1 {
                Err(format!("expected {} but got {}",
                            expected[0], token))
            } else { // multiple expected tokens
                Err(format!("expected one of {} but got {}",
                            ::util::comma_separated_values(expected.iter()),
                            token))
            }
        }
    }

    fn expect_word(&mut self) -> Result<String> {
        match self.expect_something() {
            Ok(ref token) => match *token {
                Token::Word(ref w) => Ok(w.clone()),
                _ => Err("expected a word".into()),
            },
            Err(e) => Err(e),
        }
    }

    fn expect_integer(&mut self) -> Result<i64> {
        match self.expect_something() {
            Ok(ref token) => match *token {
                Token::Integer(i) => Ok(i),
                _ => Err("expected an integer".into()),
            },
            Err(e) => Err(e),
        }
    }

    fn eat_whitespace(&mut self) -> Result<()> {
        self.tokenizer.eat_while(|t| t.is_new_line())
    }
}

pub mod util
{
    /// Expects that an `Option<Result>` is `Some`.
    // TODO: give this a name that doesn't clash with Parser::expect
    pub fn expect<T>(val: Option<Result<T,String>>) -> Result<T,String> {
        match val {
            Some(result) => result,
            None => Err("expected a token".into()),
        }
    }

    pub fn is_integer_type(word: &str) -> bool {
        if word.starts_with('i') || word.starts_with('u') {
            let next_part: String = word.chars().skip(1).collect();

            is_integer(&next_part, 10)
        } else {
            false
        }
    }

    pub fn is_integer(string: &str, radix: u32) -> bool {
        parse_integer(string, radix).is_ok()
    }

    pub fn parse_integer(string: &str, radix: u32) -> Result<i64,String> {
        match i64::from_str_radix(string, radix) {
            Ok(i) => Ok(i),
            Err(..) => Err("could not parse integer".into()),
        }
    }
}

pub mod keywords
{
    use read::Token;

    pub fn global() -> Token {
        Token::word("global")
    }

    pub fn function() -> Token {
        Token::word("fn")
    }
}

#[allow(unused_imports)]
mod test
{
    use super::Parser;
    use {Value,Function,Signature};

    #[cfg(test)]
    fn parse(text: &str) -> ::Module {
        Parser::new(text.chars()).parse().expect("parsing failed")
    }

    macro_rules! expect_global {
        ($input:expr => $name:expr, $value:expr) => {
            {
                let module = parse($input);

                let global = module.globals()
                                   .next()
                                   .expect("no globals were parsed");

                assert_eq!(global.name(), $name);
                assert_eq!(global.value(), &$value);
            }
        }
    }

    #[test]
    fn globals() {
        expect_global!("global @ABCD = i32 5" => "ABCD", Value::i32(5));

        expect_global!("global @hello_world = u127 38"
                       => "hello_world", Value::u(127, 38));

        expect_global!("global @ewf = i16 52" => "ewf", Value::i(16, 52));
    }
}

<|endoftext|>


<commit_before>//! Methods for converting shapes into triangles.

use std::f64::consts::{
    PI,
    PI_2,
    FRAC_PI_2,
};
use {
    Color,
    Image,
    Line,
    Matrix2d,
    Rectangle,
};
use interpolation::{lerp};
use vecmath::{
    multiply,
    orient,
    translate,
};

#[inline(always)]
fn tx(m: &Matrix2d, x: f64, y: f64) -> f32 {
    (m[0] * x + m[1] * y + m[2]) as f32
}

#[inline(always)]
fn ty(m: &Matrix2d, x: f64, y: f64) -> f32 {
    (m[3] * x + m[4] * y + m[5]) as f32
}

/// Streams tweened polygons using linear interpolation.
#[inline(always)]
pub fn with_lerp_polygons_tri_list_xy_f32_rgba_f32(
    m: &Matrix2d,
    polygons: &[&[f64]],
    tween_factor: f64,
    color: &Color,
    f: |vertices: &[f32], colors: &[f32]|) {

    let poly_len = polygons.len() as f64;
    // Map to interval between 0 and 1.
    let tw = tween_factor % 1.0;
    // Map negative values to positive.
    let tw = if tw < 0.0 { tw + 1.0 } else { tw };
    // Map to frame.
    let tw = tw * poly_len;
    // Get the current frame.
    let frame = tw as uint;
    // Get the next frame.
    let next_frame = (frame + 1) % polygons.len();
    let p0 = polygons[frame];
    let p1 = polygons[next_frame];
    // Get factor between frames.
    let tw = tw - frame as f64;
    let n = polygons[0].len();
    let mut i = 0u;
    stream_polygon_tri_list_xy_f32_rgba_f32(m, || {
        if i >= n { return None; }

        let j = i;
        i += 2;
        let (x0, y0) = (p0[j], p0[j+1]);
        let (x1, y1) = (p1[j], p1[j+1]);
        Some([lerp(&x0, &x1, &tw), lerp(&y0, &y1, &tw)])
    }, color, f);
}

/// Streams an ellipse specified by a resolution.
#[inline(always)]
pub fn with_ellipse_tri_list_xy_f32_rgba_f32(
    resolution: uint,
    m: &Matrix2d,
    rect: &Rectangle,
    color: &Color,
    f: |vertices: &[f32], colors: &[f32]|) {

    let (x, y, w, h) = (rect[0], rect[1], rect[2], rect[3]);
    let (cw, ch) = (0.5 * w, 0.5 * h);
    let (cx, cy) = (x + cw, y + ch);
    let n = resolution;
    let mut i = 0u;
    stream_polygon_tri_list_xy_f32_rgba_f32(m, || {
        if i >= n { return None; }

        let angle = i as f64 / n as f64 * PI_2;
        i += 1;
        Some([cx + angle.cos() * cw, cy + angle.sin() * ch])
    }, color, f);
}

/// Streams a round border line.
#[inline(always)]
pub fn with_round_border_line_tri_list_xy_f32_rgba_f32(
    resolution_cap: uint,
    m: &Matrix2d,
    line: &Line,
    round_border_radius: &f64,
    color: &Color,
    f: |vertices: &[f32], colors: &[f32]|) {

    let radius = *round_border_radius;
    let (x1, y1, x2, y2) = (line[0], line[1], line[2], line[3]);
    let (dx, dy) = (x2 - x1, y2 - y1);
    let w = (dx * dx + dy * dy).sqrt();
    let m = multiply(m, &translate(x1, y1));
    let m = multiply(&m, &orient(dx, dy));
    let n = resolution_cap * 2;
    let mut i = 0u;
    stream_polygon_tri_list_xy_f32_rgba_f32(&m, || {
        if i >= n { return None; }

        let j = i;
        i += 1;
        match j {
            j if j >= resolution_cap => {
                let angle = (j - resolution_cap) as f64 / (resolution_cap - 1) as f64 * PI + PI;
                let angle = angle + FRAC_PI_2;
                Some([w + angle.cos() * radius, angle.sin() * radius])
            },
            j => {
                let angle = j as f64 / (resolution_cap - 1) as f64 * PI;
                let angle = angle + FRAC_PI_2;
                Some([angle.cos() * radius, angle.sin() * radius])
            },
        }
    }, color, f);
    /*
    let (x, y, w, h) = (rect[0], rect[1], rect[2], rect[3]);
    let radius = round_border[0];
    let n = resolution_corner * 4 + 4;
    let mut i = 0u;
    stream_polygon_tri_list_xy_f32_rgba_f32(m, || {
        if i >= n { return None; }

        let j = i;
        i += 1;
        match j {
            j if j >= resolution_corner * 3 => {
                let angle = j as f64 / (n - 3) as f64 * std::f64::consts::PI_2;
                let (cx, cy) = (x + w - radius, y + radius);
                Some([cx + angle.cos() * radius, cy + angle.sin() * radius])
            },
            j if j >= resolution_corner * 2 => {
                let angle = j as f64 / (n - 2) as f64 * std::f64::consts::PI_2;
                let (cx, cy) = (x + radius, y + radius);
                Some([cx + angle.cos() * radius, cy + angle.sin() * radius])
            },
            j if j >= resolution_corner * 1 => {
                let angle = j as f64 / (n - 1) as f64 * std::f64::consts::PI_2;
                let (cx, cy) = (x + radius, y + h - radius);
                Some([cx + angle.cos() * radius, cy + angle.sin() * radius])
            },
            j => {
                let angle = j as f64 / (n - 0) as f64 * std::f64::consts::PI_2;
                let (cx, cy) = (x + w - radius, y + h - radius);
                Some([cx + angle.cos() * radius, cy + angle.sin() * radius])
            },
        }
    }, color, f);
    */
}

/// Streams a round rectangle.
#[inline(always)]
pub fn with_round_rectangle_tri_list_xy_f32_rgba_f32(
    resolution_corner: uint,
    m: &Matrix2d,
    rect: &Rectangle,
    round_radius: &f64,
    color: &Color,
    f: |vertices: &[f32], colors: &[f32]|) {

    let (x, y, w, h) = (rect[0], rect[1], rect[2], rect[3]);
    let radius = *round_radius;
    let n = resolution_corner * 4 + 4;
    let mut i = 0u;
    stream_polygon_tri_list_xy_f32_rgba_f32(m, || {
        if i >= n { return None; }

        let j = i;
        i += 1;
        match j {
            j if j >= resolution_corner * 3 => {
                let angle = j as f64 / (n - 3) as f64 * PI_2;
                let (cx, cy) = (x + w - radius, y + radius);
                Some([cx + angle.cos() * radius, cy + angle.sin() * radius])
            },
            j if j >= resolution_corner * 2 => {
                let angle = j as f64 / (n - 2) as f64 * PI_2;
                let (cx, cy) = (x + radius, y + radius);
                Some([cx + angle.cos() * radius, cy + angle.sin() * radius])
            },
            j if j >= resolution_corner * 1 => {
                let angle = j as f64 / (n - 1) as f64 * PI_2;
                let (cx, cy) = (x + radius, y + h - radius);
                Some([cx + angle.cos() * radius, cy + angle.sin() * radius])
            },
            j => {
                let angle = j as f64 / (n - 0) as f64 * PI_2;
                let (cx, cy) = (x + w - radius, y + h - radius);
                Some([cx + angle.cos() * radius, cy + angle.sin() * radius])
            },
        }
    }, color, f);
}

/// Streams a polygon into tri list with color per vertex.
/// Uses buffers that fit inside L1 cache.
pub fn stream_polygon_tri_list_xy_f32_rgba_f32(
    m: &Matrix2d,
    polygon: || -> Option<[f64, ..2]>,
    color: &Color,
    f: |vertices: &[f32], colors: &[f32]|) {

    let mut vertices: [f32, ..740] = [0.0, ..740];
    let mut colors: [f32, ..1480] = [0.0, ..1480];
    // Get the first point which will be used a lot.
    let fp = match polygon() { None => return, Some(val) => val };
    let (fx, fy) = (tx(m, fp[0], fp[1]), ty(m, fp[0], fp[1]));
    let gp = match polygon() { None => return, Some(val) => val };
    let (gx, gy) = (tx(m, gp[0], gp[1]), ty(m, gp[0], gp[1]));
    let mut gx = gx;
    let mut gy = gy;
    let mut i = 0;
    'read_vertices: loop {
        let ind_out = i * 2 * 3;
        vertices[ind_out + 0] = fx;
        vertices[ind_out + 1] = fy;
        let ind_out = i * 4 * 3;
        colors[ind_out + 0] = color[0];
        colors[ind_out + 1] = color[1];
        colors[ind_out + 2] = color[2];
        colors[ind_out + 3] = color[3];

        // Copy vertex.
        let ind_out = i * 2 * 3 + 2;
        let p =
            match polygon() {
                None => break 'read_vertices,
                Some(val) => val,
            };
        let x = tx(m, p[0], p[1]);
        let y = ty(m, p[0], p[1]);

        vertices[ind_out + 0] = gx;
        vertices[ind_out + 1] = gy;
        vertices[ind_out + 2] = x;
        vertices[ind_out + 3] = y;
        gx = x;
        gy = y;
        let ind_out = i * 4 * 3 + 4;
        colors[ind_out + 0] = color[0];
        colors[ind_out + 1] = color[1];
        colors[ind_out + 2] = color[2];
        colors[ind_out + 3] = color[3];
        colors[ind_out + 4] = color[0];
        colors[ind_out + 5] = color[1];
        colors[ind_out + 6] = color[2];
        colors[ind_out + 7] = color[3];

        i += 1;
        // Buffer is full.
        if i * 2 * 3 + 2 == vertices.len() {
            // Send chunk and start over.
            f(vertices.slice(0, i * 2 * 3),
                colors.slice(0, i * 4 * 3));
            i = 0;
        }
    }

    if i > 0 {
        f(vertices.slice(0, i * 2 * 3),
            colors.slice(0, i * 4 * 3));
    }
}

/// Splits polygon into convex segments with one color per vertex.
/// Create a buffer that fits into L1 cache with 1KB overhead.
pub fn with_polygon_tri_list_xy_f32_rgba_f32(
    m: &Matrix2d,
    polygon: &[f64],
    color: &Color,
    f: |vertices: &[f32], colors: &[f32]|) {

    let n = polygon.len();
    let mut i = 0;
    stream_polygon_tri_list_xy_f32_rgba_f32(
        m, || {
            if i >= n { return None; }

            let j = i;
            i += 2;
            Some([polygon[j], polygon[j+1]])
        }, color, f);
}

/// Creates triangle list vertices from rectangle.
pub fn rect_tri_list_xy_f32(m: &Matrix2d, rect: &Rectangle) -> [f32, ..12] {
    let (x, y, w, h) = (rect[0], rect[1], rect[2], rect[3]);
    let (x2, y2) = (x + w, y + h);
    [tx(m,x,y), ty(m,x,y), tx(m,x2,y), ty(m,x2,y), tx(m,x,y2), ty(m,x,y2),
     tx(m,x2,y), ty(m,x2,y), tx(m,x2,y2), ty(m,x2,y2), tx(m,x,y2), ty(m,x,y2)]
}

/// Creates triangle list colors from rectangle.
pub fn rect_tri_list_rgba_f32(color: &Color) -> [f32, ..48] {
    let (r, g, b, a) = (color[0], color[1], color[2], color[3]);
    [r, g, b, a, // 0
     r, g, b, a, // 1
     r, g, b, a, // 2
     r, g, b, a, // 3
     r, g, b, a, // 4
     r, g, b, a, // 5
     r, g, b, a, // 6
     r, g, b, a, // 7
     r, g, b, a, // 8
     r, g, b, a, // 9
     r, g, b, a, // 10
     r, g, b, a]
}

/// Creates triangle list texture coords from image.
pub fn rect_tri_list_uv_f32(image: &Image) -> [f32, ..12] {
    let x1 = image.source_rect[0] as f32 / image.texture_width as f32;
    let y1 = image.source_rect[1] as f32 / image.texture_height as f32;
    let x2 = (image.source_rect[0] + image.source_rect[2]) as f32 / image.texture_width as f32;
    let y2 = (image.source_rect[1] + image.source_rect[3]) as f32 / image.texture_height as f32;
    [x1, y1, x2, y1, x1, y2,
     x2, y1, x2, y2, x1, y2]
}
<commit_msg>Add more comments to `with_round_border_line_tri_list_xy_f32_rgba_f32`<commit_after>//! Methods for converting shapes into triangles.

use std::f64::consts::{
    PI,
    PI_2,
    FRAC_PI_2,
};
use {
    Color,
    Image,
    Line,
    Matrix2d,
    Rectangle,
};
use interpolation::{lerp};
use vecmath::{
    multiply,
    orient,
    translate,
};

#[inline(always)]
fn tx(m: &Matrix2d, x: f64, y: f64) -> f32 {
    (m[0] * x + m[1] * y + m[2]) as f32
}

#[inline(always)]
fn ty(m: &Matrix2d, x: f64, y: f64) -> f32 {
    (m[3] * x + m[4] * y + m[5]) as f32
}

/// Streams tweened polygons using linear interpolation.
#[inline(always)]
pub fn with_lerp_polygons_tri_list_xy_f32_rgba_f32(
    m: &Matrix2d,
    polygons: &[&[f64]],
    tween_factor: f64,
    color: &Color,
    f: |vertices: &[f32], colors: &[f32]|) {

    let poly_len = polygons.len() as f64;
    // Map to interval between 0 and 1.
    let tw = tween_factor % 1.0;
    // Map negative values to positive.
    let tw = if tw < 0.0 { tw + 1.0 } else { tw };
    // Map to frame.
    let tw = tw * poly_len;
    // Get the current frame.
    let frame = tw as uint;
    // Get the next frame.
    let next_frame = (frame + 1) % polygons.len();
    let p0 = polygons[frame];
    let p1 = polygons[next_frame];
    // Get factor between frames.
    let tw = tw - frame as f64;
    let n = polygons[0].len();
    let mut i = 0u;
    stream_polygon_tri_list_xy_f32_rgba_f32(m, || {
        if i >= n { return None; }

        let j = i;
        i += 2;
        let (x0, y0) = (p0[j], p0[j+1]);
        let (x1, y1) = (p1[j], p1[j+1]);
        Some([lerp(&x0, &x1, &tw), lerp(&y0, &y1, &tw)])
    }, color, f);
}

/// Streams an ellipse specified by a resolution.
#[inline(always)]
pub fn with_ellipse_tri_list_xy_f32_rgba_f32(
    resolution: uint,
    m: &Matrix2d,
    rect: &Rectangle,
    color: &Color,
    f: |vertices: &[f32], colors: &[f32]|) {

    let (x, y, w, h) = (rect[0], rect[1], rect[2], rect[3]);
    let (cw, ch) = (0.5 * w, 0.5 * h);
    let (cx, cy) = (x + cw, y + ch);
    let n = resolution;
    let mut i = 0u;
    stream_polygon_tri_list_xy_f32_rgba_f32(m, || {
        if i >= n { return None; }

        let angle = i as f64 / n as f64 * PI_2;
        i += 1;
        Some([cx + angle.cos() * cw, cy + angle.sin() * ch])
    }, color, f);
}

/// Streams a round border line.
#[inline(always)]
pub fn with_round_border_line_tri_list_xy_f32_rgba_f32(
    resolution_cap: uint,
    m: &Matrix2d,
    line: &Line,
    round_border_radius: &f64,
    color: &Color,
    f: |vertices: &[f32], colors: &[f32]|) {

    let radius = *round_border_radius;
    let (x1, y1, x2, y2) = (line[0], line[1], line[2], line[3]);
    let (dx, dy) = (x2 - x1, y2 - y1);
    let w = (dx * dx + dy * dy).sqrt();
    let m = multiply(m, &translate(x1, y1));
    let m = multiply(&m, &orient(dx, dy));
    let n = resolution_cap * 2;
    let mut i = 0u;
    stream_polygon_tri_list_xy_f32_rgba_f32(&m, || {
        if i >= n { return None; }

        let j = i;
        i += 1;
        // Detect the half circle from index.
        // There is one half circle at each end of the line.
        // Together they form a full circle if the length of the line is zero.
        match j {
            j if j >= resolution_cap => {
                // Compute the angle to match start and end point of half circle.
                // This requires an angle offset since the other end of line is the first half circle.
                let angle = (j - resolution_cap) as f64 / (resolution_cap - 1) as f64 * PI + PI;
                // Rotate 90 degrees since the line is horizontal.
                let angle = angle + FRAC_PI_2;
                Some([w + angle.cos() * radius, angle.sin() * radius])
            },
            j => {
                // Compute the angle to match start and end point of half circle.
                let angle = j as f64 / (resolution_cap - 1) as f64 * PI;
                // Rotate 90 degrees since the line is horizontal.
                let angle = angle + FRAC_PI_2;
                Some([angle.cos() * radius, angle.sin() * radius])
            },
        }
    }, color, f);
    /*
    let (x, y, w, h) = (rect[0], rect[1], rect[2], rect[3]);
    let radius = round_border[0];
    let n = resolution_corner * 4 + 4;
    let mut i = 0u;
    stream_polygon_tri_list_xy_f32_rgba_f32(m, || {
        if i >= n { return None; }

        let j = i;
        i += 1;
        match j {
            j if j >= resolution_corner * 3 => {
                let angle = j as f64 / (n - 3) as f64 * std::f64::consts::PI_2;
                let (cx, cy) = (x + w - radius, y + radius);
                Some([cx + angle.cos() * radius, cy + angle.sin() * radius])
            },
            j if j >= resolution_corner * 2 => {
                let angle = j as f64 / (n - 2) as f64 * std::f64::consts::PI_2;
                let (cx, cy) = (x + radius, y + radius);
                Some([cx + angle.cos() * radius, cy + angle.sin() * radius])
            },
            j if j >= resolution_corner * 1 => {
                let angle = j as f64 / (n - 1) as f64 * std::f64::consts::PI_2;
                let (cx, cy) = (x + radius, y + h - radius);
                Some([cx + angle.cos() * radius, cy + angle.sin() * radius])
            },
            j => {
                let angle = j as f64 / (n - 0) as f64 * std::f64::consts::PI_2;
                let (cx, cy) = (x + w - radius, y + h - radius);
                Some([cx + angle.cos() * radius, cy + angle.sin() * radius])
            },
        }
    }, color, f);
    */
}

/// Streams a round rectangle.
#[inline(always)]
pub fn with_round_rectangle_tri_list_xy_f32_rgba_f32(
    resolution_corner: uint,
    m: &Matrix2d,
    rect: &Rectangle,
    round_radius: &f64,
    color: &Color,
    f: |vertices: &[f32], colors: &[f32]|) {

    let (x, y, w, h) = (rect[0], rect[1], rect[2], rect[3]);
    let radius = *round_radius;
    let n = resolution_corner * 4 + 4;
    let mut i = 0u;
    stream_polygon_tri_list_xy_f32_rgba_f32(m, || {
        if i >= n { return None; }

        let j = i;
        i += 1;
        match j {
            j if j >= resolution_corner * 3 => {
                let angle = j as f64 / (n - 3) as f64 * PI_2;
                let (cx, cy) = (x + w - radius, y + radius);
                Some([cx + angle.cos() * radius, cy + angle.sin() * radius])
            },
            j if j >= resolution_corner * 2 => {
                let angle = j as f64 / (n - 2) as f64 * PI_2;
                let (cx, cy) = (x + radius, y + radius);
                Some([cx + angle.cos() * radius, cy + angle.sin() * radius])
            },
            j if j >= resolution_corner * 1 => {
                let angle = j as f64 / (n - 1) as f64 * PI_2;
                let (cx, cy) = (x + radius, y + h - radius);
                Some([cx + angle.cos() * radius, cy + angle.sin() * radius])
            },
            j => {
                let angle = j as f64 / (n - 0) as f64 * PI_2;
                let (cx, cy) = (x + w - radius, y + h - radius);
                Some([cx + angle.cos() * radius, cy + angle.sin() * radius])
            },
        }
    }, color, f);
}

/// Streams a polygon into tri list with color per vertex.
/// Uses buffers that fit inside L1 cache.
pub fn stream_polygon_tri_list_xy_f32_rgba_f32(
    m: &Matrix2d,
    polygon: || -> Option<[f64, ..2]>,
    color: &Color,
    f: |vertices: &[f32], colors: &[f32]|) {

    let mut vertices: [f32, ..740] = [0.0, ..740];
    let mut colors: [f32, ..1480] = [0.0, ..1480];
    // Get the first point which will be used a lot.
    let fp = match polygon() { None => return, Some(val) => val };
    let (fx, fy) = (tx(m, fp[0], fp[1]), ty(m, fp[0], fp[1]));
    let gp = match polygon() { None => return, Some(val) => val };
    let (gx, gy) = (tx(m, gp[0], gp[1]), ty(m, gp[0], gp[1]));
    let mut gx = gx;
    let mut gy = gy;
    let mut i = 0;
    'read_vertices: loop {
        let ind_out = i * 2 * 3;
        vertices[ind_out + 0] = fx;
        vertices[ind_out + 1] = fy;
        let ind_out = i * 4 * 3;
        colors[ind_out + 0] = color[0];
        colors[ind_out + 1] = color[1];
        colors[ind_out + 2] = color[2];
        colors[ind_out + 3] = color[3];

        // Copy vertex.
        let ind_out = i * 2 * 3 + 2;
        let p =
            match polygon() {
                None => break 'read_vertices,
                Some(val) => val,
            };
        let x = tx(m, p[0], p[1]);
        let y = ty(m, p[0], p[1]);

        vertices[ind_out + 0] = gx;
        vertices[ind_out + 1] = gy;
        vertices[ind_out + 2] = x;
        vertices[ind_out + 3] = y;
        gx = x;
        gy = y;
        let ind_out = i * 4 * 3 + 4;
        colors[ind_out + 0] = color[0];
        colors[ind_out + 1] = color[1];
        colors[ind_out + 2] = color[2];
        colors[ind_out + 3] = color[3];
        colors[ind_out + 4] = color[0];
        colors[ind_out + 5] = color[1];
        colors[ind_out + 6] = color[2];
        colors[ind_out + 7] = color[3];

        i += 1;
        // Buffer is full.
        if i * 2 * 3 + 2 == vertices.len() {
            // Send chunk and start over.
            f(vertices.slice(0, i * 2 * 3),
                colors.slice(0, i * 4 * 3));
            i = 0;
        }
    }

    if i > 0 {
        f(vertices.slice(0, i * 2 * 3),
            colors.slice(0, i * 4 * 3));
    }
}

/// Splits polygon into convex segments with one color per vertex.
/// Create a buffer that fits into L1 cache with 1KB overhead.
pub fn with_polygon_tri_list_xy_f32_rgba_f32(
    m: &Matrix2d,
    polygon: &[f64],
    color: &Color,
    f: |vertices: &[f32], colors: &[f32]|) {

    let n = polygon.len();
    let mut i = 0;
    stream_polygon_tri_list_xy_f32_rgba_f32(
        m, || {
            if i >= n { return None; }

            let j = i;
            i += 2;
            Some([polygon[j], polygon[j+1]])
        }, color, f);
}

/// Creates triangle list vertices from rectangle.
pub fn rect_tri_list_xy_f32(m: &Matrix2d, rect: &Rectangle) -> [f32, ..12] {
    let (x, y, w, h) = (rect[0], rect[1], rect[2], rect[3]);
    let (x2, y2) = (x + w, y + h);
    [tx(m,x,y), ty(m,x,y), tx(m,x2,y), ty(m,x2,y), tx(m,x,y2), ty(m,x,y2),
     tx(m,x2,y), ty(m,x2,y), tx(m,x2,y2), ty(m,x2,y2), tx(m,x,y2), ty(m,x,y2)]
}

/// Creates triangle list colors from rectangle.
pub fn rect_tri_list_rgba_f32(color: &Color) -> [f32, ..48] {
    let (r, g, b, a) = (color[0], color[1], color[2], color[3]);
    [r, g, b, a, // 0
     r, g, b, a, // 1
     r, g, b, a, // 2
     r, g, b, a, // 3
     r, g, b, a, // 4
     r, g, b, a, // 5
     r, g, b, a, // 6
     r, g, b, a, // 7
     r, g, b, a, // 8
     r, g, b, a, // 9
     r, g, b, a, // 10
     r, g, b, a]
}

/// Creates triangle list texture coords from image.
pub fn rect_tri_list_uv_f32(image: &Image) -> [f32, ..12] {
    let x1 = image.source_rect[0] as f32 / image.texture_width as f32;
    let y1 = image.source_rect[1] as f32 / image.texture_height as f32;
    let x2 = (image.source_rect[0] + image.source_rect[2]) as f32 / image.texture_width as f32;
    let y2 = (image.source_rect[1] + image.source_rect[3]) as f32 / image.texture_height as f32;
    [x1, y1, x2, y1, x1, y2,
     x2, y1, x2, y2, x1, y2]
}
<|endoftext|>


<commit_before>use std::marker::PhantomData;
use super::context::Context;
use super::vertex_data::{VertexData, VertexBytes, VertexAttribBinder};
use super::index_data::{IndexData, IndexDatum};
use super::buffer::{Buffer, BufferBinding,
                    ArrayBufferBinding, ElementArrayBufferBinding};
use super::types::DrawingMode;

pub struct VertexBuffer<T: VertexData> {
    pub attrib_binder: Option<T::Binder>,
    buffer: Buffer,
    count: usize,
    phantom: PhantomData<*const T>
}

impl<T: VertexData> VertexBuffer<T> {
    pub fn build_attrib_binder(&self)
        -> <T::Binder as VertexAttribBinder>::Builder
    {
        T::build_attrib_binder()
    }

    pub fn bind(&self, gl_buffer: &ArrayBufferBinding) -> Result<(), ()> {
        match self.attrib_binder {
            Some(ref binder) => {
                binder.bind(gl_buffer);
                Ok(())
            },
            None => { Err(()) }
        }
    }

    pub fn buffer(&self) -> &Buffer {
        &self.buffer
    }

    pub fn buffer_mut(&mut self) -> &mut Buffer {
        &mut self.buffer
    }
}

pub struct VertexBufferBinding<'a, T: VertexData>
    where T: 'a, T::Binder: 'a
{
    gl_buffer: ArrayBufferBinding<'a>,
    vbo: &'a mut VertexBuffer<T>
}

impl<'a, T: VertexData> VertexBufferBinding<'a, T>
    where T: 'a, T::Binder: 'a
{
    pub fn new(gl_buffer: ArrayBufferBinding<'a>, vbo: &'a mut VertexBuffer<T>)
        -> Self
    {
        VertexBufferBinding {
            gl_buffer: gl_buffer,
            vbo: vbo
        }
    }

    pub fn buffer_data(&mut self, data: &[T], usage: super::BufferDataUsage)
        where [T]: VertexBytes
    {
        self.vbo.count = data.len();
        self.gl_buffer.buffer_bytes(data.vertex_bytes(), usage);
    }

    pub fn draw_arrays_range(&self,
                             mode: DrawingMode,
                             start: u32,
                             length: usize)
    {
        debug_assert!((start as usize) + length <= self.vbo.count);

        unsafe {
            self.gl_buffer.draw_arrays_range(mode, start, length);
        }
    }

    pub fn draw_arrays(&self, mode: DrawingMode) {
        unsafe {
            self.gl_buffer.draw_arrays_range(mode, 0, self.vbo.count);
        }
    }

    pub fn draw_n_elements_buffered<I>(&self,
                                       gl_ibo: &IndexBufferBinding<'a, I>,
                                       mode: DrawingMode,
                                       length: usize)
        where I: IndexDatum
    {
        debug_assert!(length <= gl_ibo.ibo.count);

        unsafe {
            self.gl_buffer.draw_n_elements_buffered(&gl_ibo.gl_buffer,
                                                    mode,
                                                    length,
                                                    I::index_datum_type());
        }
    }

    pub fn draw_n_elements<I>(&self,
                              mode: DrawingMode,
                              count: usize,
                              indicies: &[I])
        where I: IndexDatum, [I]: IndexData
    {
        unsafe {
            self.gl_buffer.draw_n_elements(mode, count, indicies);
        }
    }

    pub fn draw_elements<I>(&self,
                            mode: DrawingMode,
                            indicies: &[I])
        where I: IndexDatum, [I]: IndexData
    {
        unsafe {
            self.gl_buffer.draw_elements(mode, indicies);
        }
    }
}

impl Context {
    pub fn new_vertex_buffer<T: VertexData>(&self) -> VertexBuffer<T> {
        VertexBuffer {
            attrib_binder: None,
            buffer: self.gen_buffer(),
            count: 0,
            phantom: PhantomData
        }
    }
}

pub struct IndexBuffer<T: IndexDatum> {
    buffer: Buffer,
    count: usize,
    phantom: PhantomData<*const T>
}

impl<T: IndexDatum> IndexBuffer<T> {
    pub fn buffer(&self) -> &Buffer {
        &self.buffer
    }

    pub fn buffer_mut(&mut self) -> &mut Buffer {
        &mut self.buffer
    }
}

pub struct IndexBufferBinding<'a, T: IndexDatum + 'a> {
    gl_buffer: ElementArrayBufferBinding<'a>,
    ibo: &'a mut IndexBuffer<T>
}

impl<'a, T: IndexDatum + 'a> IndexBufferBinding<'a, T> {
    pub fn new(gl_buffer: ElementArrayBufferBinding<'a>,
               ibo: &'a mut IndexBuffer<T>)
        -> Self
    {
        IndexBufferBinding {
            gl_buffer: gl_buffer,
            ibo: ibo
        }
    }

    pub fn buffer_data(&mut self, data: &[T], usage: super::BufferDataUsage)
        where [T]: IndexData
    {
        self.ibo.count = data.len();
        self.gl_buffer.buffer_bytes(data.index_bytes(), usage);
    }
}

impl Context {
    pub fn new_index_buffer<T: IndexDatum>(&self) -> IndexBuffer<T> {
        IndexBuffer {
            buffer: self.gen_buffer(),
            count: 0,
            phantom: PhantomData
        }
    }
}

#[macro_export]
macro_rules! bind_attrib_pointers {
    ($gl:expr, $vbo:expr, {
        $($field_name:ident => $field_attrib:expr),*
    }) => {
        {
            let vbo = $vbo;
            let binder = vbo.build_attrib_binder()
                            $(.$field_name($field_attrib))*
                            .unwrap($gl);
            vbo.attrib_binder = Some(binder)
        }
    }
}

#[macro_export]
macro_rules! bind_vertex_buffer {
    ($gl:expr, $vbo:expr) => {
        {
            let vbo = $vbo;

            let gl_buffer = bind_array_buffer!($gl, vbo.buffer_mut());
            vbo.bind(&gl_buffer).unwrap();
            $crate::VertexBufferBinding::new(gl_buffer, vbo)
        }
    }
}

#[macro_export]
macro_rules! bind_index_buffer {
    ($gl:expr, $ibo:expr) => {
        {
            let ibo = $ibo;

            let gl_buffer = bind_element_array_buffer!($gl, ibo.buffer_mut());
            $crate::IndexBufferBinding::new(gl_buffer, ibo)
        }
    }
}
<commit_msg>Add `VertexBufferBinding.draw_elements_buffered()`<commit_after>use std::marker::PhantomData;
use super::context::Context;
use super::vertex_data::{VertexData, VertexBytes, VertexAttribBinder};
use super::index_data::{IndexData, IndexDatum};
use super::buffer::{Buffer, BufferBinding,
                    ArrayBufferBinding, ElementArrayBufferBinding};
use super::types::DrawingMode;

pub struct VertexBuffer<T: VertexData> {
    pub attrib_binder: Option<T::Binder>,
    buffer: Buffer,
    count: usize,
    phantom: PhantomData<*const T>
}

impl<T: VertexData> VertexBuffer<T> {
    pub fn build_attrib_binder(&self)
        -> <T::Binder as VertexAttribBinder>::Builder
    {
        T::build_attrib_binder()
    }

    pub fn bind(&self, gl_buffer: &ArrayBufferBinding) -> Result<(), ()> {
        match self.attrib_binder {
            Some(ref binder) => {
                binder.bind(gl_buffer);
                Ok(())
            },
            None => { Err(()) }
        }
    }

    pub fn buffer(&self) -> &Buffer {
        &self.buffer
    }

    pub fn buffer_mut(&mut self) -> &mut Buffer {
        &mut self.buffer
    }
}

pub struct VertexBufferBinding<'a, T: VertexData>
    where T: 'a, T::Binder: 'a
{
    gl_buffer: ArrayBufferBinding<'a>,
    vbo: &'a mut VertexBuffer<T>
}

impl<'a, T: VertexData> VertexBufferBinding<'a, T>
    where T: 'a, T::Binder: 'a
{
    pub fn new(gl_buffer: ArrayBufferBinding<'a>, vbo: &'a mut VertexBuffer<T>)
        -> Self
    {
        VertexBufferBinding {
            gl_buffer: gl_buffer,
            vbo: vbo
        }
    }

    pub fn buffer_data(&mut self, data: &[T], usage: super::BufferDataUsage)
        where [T]: VertexBytes
    {
        self.vbo.count = data.len();
        self.gl_buffer.buffer_bytes(data.vertex_bytes(), usage);
    }

    pub fn draw_arrays_range(&self,
                             mode: DrawingMode,
                             start: u32,
                             length: usize)
    {
        debug_assert!((start as usize) + length <= self.vbo.count);

        unsafe {
            self.gl_buffer.draw_arrays_range(mode, start, length);
        }
    }

    pub fn draw_arrays(&self, mode: DrawingMode) {
        unsafe {
            self.gl_buffer.draw_arrays_range(mode, 0, self.vbo.count);
        }
    }

    pub fn draw_n_elements_buffered<I>(&self,
                                       gl_ibo: &IndexBufferBinding<'a, I>,
                                       mode: DrawingMode,
                                       length: usize)
        where I: IndexDatum
    {
        debug_assert!(length <= gl_ibo.ibo.count);

        unsafe {
            self.gl_buffer.draw_n_elements_buffered(&gl_ibo.gl_buffer,
                                                    mode,
                                                    length,
                                                    I::index_datum_type());
        }
    }

    pub fn draw_elements_buffered<I>(&self,
                                     gl_ibo: &IndexBufferBinding<'a, I>,
                                     mode: DrawingMode)
        where I: IndexDatum
    {
        unsafe {
            self.gl_buffer.draw_n_elements_buffered(&gl_ibo.gl_buffer,
                                                    mode,
                                                    gl_ibo.ibo.count,
                                                    I::index_datum_type());
        }
    }

    pub fn draw_n_elements<I>(&self,
                              mode: DrawingMode,
                              count: usize,
                              indicies: &[I])
        where I: IndexDatum, [I]: IndexData
    {
        unsafe {
            self.gl_buffer.draw_n_elements(mode, count, indicies);
        }
    }

    pub fn draw_elements<I>(&self,
                            mode: DrawingMode,
                            indicies: &[I])
        where I: IndexDatum, [I]: IndexData
    {
        unsafe {
            self.gl_buffer.draw_elements(mode, indicies);
        }
    }
}

impl Context {
    pub fn new_vertex_buffer<T: VertexData>(&self) -> VertexBuffer<T> {
        VertexBuffer {
            attrib_binder: None,
            buffer: self.gen_buffer(),
            count: 0,
            phantom: PhantomData
        }
    }
}

pub struct IndexBuffer<T: IndexDatum> {
    buffer: Buffer,
    count: usize,
    phantom: PhantomData<*const T>
}

impl<T: IndexDatum> IndexBuffer<T> {
    pub fn buffer(&self) -> &Buffer {
        &self.buffer
    }

    pub fn buffer_mut(&mut self) -> &mut Buffer {
        &mut self.buffer
    }
}

pub struct IndexBufferBinding<'a, T: IndexDatum + 'a> {
    gl_buffer: ElementArrayBufferBinding<'a>,
    ibo: &'a mut IndexBuffer<T>
}

impl<'a, T: IndexDatum + 'a> IndexBufferBinding<'a, T> {
    pub fn new(gl_buffer: ElementArrayBufferBinding<'a>,
               ibo: &'a mut IndexBuffer<T>)
        -> Self
    {
        IndexBufferBinding {
            gl_buffer: gl_buffer,
            ibo: ibo
        }
    }

    pub fn buffer_data(&mut self, data: &[T], usage: super::BufferDataUsage)
        where [T]: IndexData
    {
        self.ibo.count = data.len();
        self.gl_buffer.buffer_bytes(data.index_bytes(), usage);
    }
}

impl Context {
    pub fn new_index_buffer<T: IndexDatum>(&self) -> IndexBuffer<T> {
        IndexBuffer {
            buffer: self.gen_buffer(),
            count: 0,
            phantom: PhantomData
        }
    }
}

#[macro_export]
macro_rules! bind_attrib_pointers {
    ($gl:expr, $vbo:expr, {
        $($field_name:ident => $field_attrib:expr),*
    }) => {
        {
            let vbo = $vbo;
            let binder = vbo.build_attrib_binder()
                            $(.$field_name($field_attrib))*
                            .unwrap($gl);
            vbo.attrib_binder = Some(binder)
        }
    }
}

#[macro_export]
macro_rules! bind_vertex_buffer {
    ($gl:expr, $vbo:expr) => {
        {
            let vbo = $vbo;

            let gl_buffer = bind_array_buffer!($gl, vbo.buffer_mut());
            vbo.bind(&gl_buffer).unwrap();
            $crate::VertexBufferBinding::new(gl_buffer, vbo)
        }
    }
}

#[macro_export]
macro_rules! bind_index_buffer {
    ($gl:expr, $ibo:expr) => {
        {
            let ibo = $ibo;

            let gl_buffer = bind_element_array_buffer!($gl, ibo.buffer_mut());
            $crate::IndexBufferBinding::new(gl_buffer, ibo)
        }
    }
}
<|endoftext|>


<commit_before>

// https://github.com/rust-lang/getopts
extern crate getopts;

// https://doc.rust-lang.org/stable/book/ffi.html
extern crate libc;

// Rust/C bindings for:
// krb5_init_context
// krb5_cc_default
// krb5_cc_get_principal
// com_err
#[allow(non_camel_case_types)]
mod krb5;
mod com_err;

use getopts::Options;
use std::env;
use std::ffi::{CStr,CString};
use std::io::{self,Write};
use std::process;
use std::ptr;

// This is a silly amount of work, but I wanted to learn how to
// get the progname into a global variable.
//
// https://github.com/Kimundi/lazy-static.rs
#[macro_use]
extern crate lazy_static;
lazy_static! {
    static ref PROGNAME: String = env::current_exe().unwrap() // PathBuf
        .file_name().unwrap()                                 // &OsStr
        .to_string_lossy().into_owned();                      // Cow<str> -> String
}

fn error(err: getopts::Fail) -> ! {
    let mut stderr = io::stderr();
    writeln!(&mut stderr, "Error: {}", err).unwrap();
    writeln!(&mut stderr, "Try '{} --help' for more information.", *PROGNAME).unwrap();
    process::exit(1);
}

fn usage(opts: &Options) -> ! {
    let brief = opts.short_usage(&*PROGNAME);
    println!("{}", opts.usage(&brief));
    process::exit(0);
}

fn main() {

    let progname = CString::new((*PROGNAME).clone())
        .unwrap()
        .into_raw();

    let args: Vec<String> = env::args().collect();
    let mut opts = Options::new();
    opts.optflag("h", "help", "print this help menu");

    let matches = match opts.parse(&args[1..]) {
        Ok(m) => { m }
        Err(f) => { error(f) }
    };

    if matches.opt_present("h") {
        usage(&opts);
    }

    let mut ctx: krb5::krb5_context = ptr::null_mut();
    let mut code: krb5::krb5_error_code = unsafe { krb5::krb5_init_context(&mut ctx) };
    if code != 0 {
        unsafe {
            com_err::com_err(progname,
                             code as i64,
                             CString::new("while initializing krb5").unwrap().into_raw());
        }
        std::process::exit(1);
    }

    let mut cache: krb5::krb5_ccache = ptr::null_mut();
    code = unsafe {krb5::krb5_cc_default(ctx, &mut cache)};
    if code != 0 {
        unsafe {
            com_err::com_err(progname,
                             code as i64,
                             CString::new("while getting default ccache").unwrap().into_raw());
        }
        std::process::exit(1);
    }

    let mut princ: krb5::krb5_principal = ptr::null_mut();
    code = unsafe { krb5::krb5_cc_get_principal(ctx, cache, &mut princ) };
    if code != 0 {
        unsafe {
            com_err::com_err(progname,
                             code as i64,
                             CString::new("while retrieving principal name").unwrap().into_raw());
        }
        std::process::exit(1);
    }

    let kpd = unsafe{(*princ)};
    let len = kpd.length;

    let d = unsafe { (*kpd.data).data };
    let s = unsafe { CStr::from_ptr(d).to_string_lossy() };
    print!("{}", s);

    for i in 1..len {
        let d = unsafe { (*kpd.data.offset(i as isize)).data };
        let s = unsafe { CStr::from_ptr(d).to_string_lossy() };
        print!("/{}", s);
    }
    println!("");

}
<commit_msg>Cleanup, and exploring encapsulation.<commit_after>

// https://github.com/rust-lang/getopts
extern crate getopts;

// https://doc.rust-lang.org/stable/book/ffi.html
extern crate libc;

// Rust FFI for:
// krb5_init_context
// krb5_cc_default
// krb5_cc_get_principal
// com_err
mod krb5;
mod com_err;

use getopts::Options;
use std::env;
use std::ffi::{CStr,CString};
use std::io::{self,Write};
use std::process;
use std::ptr;

pub struct Krb5Context {
    ctx: krb5::krb5_context,
}
impl Krb5Context {
    pub fn new() -> Option<Krb5Context> {
        let mut ctx: krb5::krb5_context = ptr::null_mut();
        unsafe {
            let code = krb5::krb5_init_context(&mut ctx);
            if code != 0 {
                let whoami = CString::new((*PROGNAME).clone())
                    .unwrap().into_raw();
                let detail = CString::new("while initializing krb5").
                    unwrap().into_raw();
                com_err::com_err(whoami, code as i64, detail);
                return None;
            }
        }
        Some(Krb5Context { ctx: ctx, })
    }
}

// This is a silly amount of work, but I wanted to learn how to
// get the progname into a global variable.
//
// https://github.com/Kimundi/lazy-static.rs
#[macro_use]
extern crate lazy_static;
lazy_static! {
    static ref PROGNAME: String = env::current_exe().unwrap() // PathBuf
        .file_name().unwrap()                                 // &OsStr
        .to_string_lossy().into_owned();                      // Cow<str> -> String
}

fn error(err: getopts::Fail) -> ! {
    let mut stderr = io::stderr();
    writeln!(&mut stderr, "Error: {}", err).unwrap();
    writeln!(&mut stderr, "Try '{} --help' for more information.", *PROGNAME).unwrap();
    process::exit(1);
}

fn usage(opts: &Options) -> ! {
    let brief = opts.short_usage(&*PROGNAME);
    println!("{}", opts.usage(&brief));
    process::exit(0);
}

fn main() {

    let progname = CString::new((*PROGNAME).clone())
        .unwrap()
        .into_raw();

    let args: Vec<String> = env::args().collect();
    let mut opts = Options::new();
    opts.optflag("h", "help", "print this help menu");

    let matches = match opts.parse(&args[1..]) {
        Ok(m) => { m }
        Err(f) => { error(f) }
    };

    if matches.opt_present("h") {
        usage(&opts);
    }

    let mut code: krb5::krb5_error_code;

    let ctx = Krb5Context::new().unwrap().ctx;

    let mut cache: krb5::krb5_ccache = ptr::null_mut();
    code = unsafe {krb5::krb5_cc_default(ctx, &mut cache)};
    if code != 0 {
        unsafe {
            com_err::com_err(progname,
                             code as i64,
                             CString::new("while getting default ccache").unwrap().into_raw());
        }
        std::process::exit(1);
    }

    let mut princ: krb5::krb5_principal = ptr::null_mut();
    code = unsafe { krb5::krb5_cc_get_principal(ctx, cache, &mut princ) };
    if code != 0 {
        unsafe {
            com_err::com_err(progname,
                             code as i64,
                             CString::new("while retrieving principal name").unwrap().into_raw());
        }
        std::process::exit(1);
    }

    let kpd = unsafe{(*princ)};
    let len = kpd.length;

    let d = unsafe { (*kpd.data).data };
    let s = unsafe { CStr::from_ptr(d).to_string_lossy() };
    print!("{}", s);

    for i in 1..len {
        let d = unsafe { (*kpd.data.offset(i as isize)).data };
        let s = unsafe { CStr::from_ptr(d).to_string_lossy() };
        print!("/{}", s);
    }
    println!("");

}
<|endoftext|>


<commit_before>#![unstable(feature = "wake_trait", issue = "69912")]
//! Types and Traits for working with asynchronous tasks.
use core::mem::{self, ManuallyDrop};
use core::task::{RawWaker, RawWakerVTable, Waker};

use crate::sync::Arc;

/// The implementation of waking a task on an executor.
///
/// This trait can be used to create a [`Waker`]. An executor can define an
/// implementation of this trait, and use that to construct a Waker to pass
/// to the tasks that are executed on that executor.
///
/// This trait is a memory-safe and ergonomic alternative to constructing a
/// [`RawWaker`]. It supports the common executor design in which the data
/// used to wake up a task is stored in an [`Arc`]. Some executors (especially
/// those for embedded systems) cannot use this API, which is why [`RawWaker`]
/// exists as an alternative for those systems.
#[unstable(feature = "wake_trait", issue = "69912")]
pub trait Wake {
    /// Wake this task.
    #[unstable(feature = "wake_trait", issue = "69912")]
    fn wake(self: Arc<Self>);

    /// Wake this task without consuming the waker.
    ///
    /// If an executor supports a cheaper way to wake without consuming the
    /// waker, it should override this method. By default, it clones the
    /// [`Arc`] and calls `wake` on the clone.
    #[unstable(feature = "wake_trait", issue = "69912")]
    fn wake_by_ref(self: &Arc<Self>) {
        self.clone().wake();
    }
}

#[unstable(feature = "wake_trait", issue = "69912")]
impl<W: Wake + Send + Sync + 'static> From<Arc<W>> for Waker {
    fn from(waker: Arc<W>) -> Waker {
        // SAFETY: This is safe because raw_waker safely constructs
        // a RawWaker from Arc<W>.
        unsafe { Waker::from_raw(raw_waker(waker)) }
    }
}

#[unstable(feature = "wake_trait", issue = "69912")]
impl<W: Wake + Send + Sync + 'static> From<Arc<W>> for RawWaker {
    fn from(waker: Arc<W>) -> RawWaker {
        raw_waker(waker)
    }
}

// NB: This private function for constructing a RawWaker is used, rather than
// inlining this into the `From<Arc<W>> for RawWaker` impl, to ensure that
// the safety of `From<Arc<W>> for Waker` does not depend on the correct
// trait dispatch - instead both impls call this function directly and
// explicitly.
#[inline(always)]
fn raw_waker<W: Wake + Send + Sync + 'static>(waker: Arc<W>) -> RawWaker {
    // Increment the reference count of the arc to clone it.
    unsafe fn clone_waker<W: Wake + Send + Sync + 'static>(waker: *const ()) -> RawWaker {
        let waker: Arc<W> = Arc::from_raw(waker as *const W);
        mem::forget(Arc::clone(&waker));
        raw_waker(waker)
    }

    // Wake by value, moving the Arc into the Wake::wake function
    unsafe fn wake<W: Wake + Send + Sync + 'static>(waker: *const ()) {
        let waker: Arc<W> = Arc::from_raw(waker as *const W);
        <W as Wake>::wake(waker);
    }

    // Wake by reference, wrap the waker in ManuallyDrop to avoid dropping it
    unsafe fn wake_by_ref<W: Wake + Send + Sync + 'static>(waker: *const ()) {
        let waker: ManuallyDrop<Arc<W>> = ManuallyDrop::new(Arc::from_raw(waker as *const W));
        <W as Wake>::wake_by_ref(&waker);
    }

    // Decrement the reference count of the Arc on drop
    unsafe fn drop_waker<W: Wake + Send + Sync + 'static>(waker: *const ()) {
        mem::drop(Arc::from_raw(waker as *const W));
    }

    RawWaker::new(
        Arc::into_raw(waker) as *const (),
        &RawWakerVTable::new(clone_waker::<W>, wake::<W>, wake_by_ref::<W>, drop_waker::<W>),
    )
}
<commit_msg>Rollup merge of #70730 - yoshuawuyts:fix-wake-docs-link, r=Dylan-DPC<commit_after>#![unstable(feature = "wake_trait", issue = "69912")]
//! Types and Traits for working with asynchronous tasks.
use core::mem::{self, ManuallyDrop};
use core::task::{RawWaker, RawWakerVTable, Waker};

use crate::sync::Arc;

/// The implementation of waking a task on an executor.
///
/// This trait can be used to create a [`Waker`]. An executor can define an
/// implementation of this trait, and use that to construct a Waker to pass
/// to the tasks that are executed on that executor.
///
/// This trait is a memory-safe and ergonomic alternative to constructing a
/// [`RawWaker`]. It supports the common executor design in which the data used
/// to wake up a task is stored in an [`Arc`][arc]. Some executors (especially
/// those for embedded systems) cannot use this API, which is why [`RawWaker`]
/// exists as an alternative for those systems.
///
/// [arc]: ../../std/sync/struct.Arc.html
#[unstable(feature = "wake_trait", issue = "69912")]
pub trait Wake {
    /// Wake this task.
    #[unstable(feature = "wake_trait", issue = "69912")]
    fn wake(self: Arc<Self>);

    /// Wake this task without consuming the waker.
    ///
    /// If an executor supports a cheaper way to wake without consuming the
    /// waker, it should override this method. By default, it clones the
    /// [`Arc`] and calls `wake` on the clone.
    #[unstable(feature = "wake_trait", issue = "69912")]
    fn wake_by_ref(self: &Arc<Self>) {
        self.clone().wake();
    }
}

#[unstable(feature = "wake_trait", issue = "69912")]
impl<W: Wake + Send + Sync + 'static> From<Arc<W>> for Waker {
    fn from(waker: Arc<W>) -> Waker {
        // SAFETY: This is safe because raw_waker safely constructs
        // a RawWaker from Arc<W>.
        unsafe { Waker::from_raw(raw_waker(waker)) }
    }
}

#[unstable(feature = "wake_trait", issue = "69912")]
impl<W: Wake + Send + Sync + 'static> From<Arc<W>> for RawWaker {
    fn from(waker: Arc<W>) -> RawWaker {
        raw_waker(waker)
    }
}

// NB: This private function for constructing a RawWaker is used, rather than
// inlining this into the `From<Arc<W>> for RawWaker` impl, to ensure that
// the safety of `From<Arc<W>> for Waker` does not depend on the correct
// trait dispatch - instead both impls call this function directly and
// explicitly.
#[inline(always)]
fn raw_waker<W: Wake + Send + Sync + 'static>(waker: Arc<W>) -> RawWaker {
    // Increment the reference count of the arc to clone it.
    unsafe fn clone_waker<W: Wake + Send + Sync + 'static>(waker: *const ()) -> RawWaker {
        let waker: Arc<W> = Arc::from_raw(waker as *const W);
        mem::forget(Arc::clone(&waker));
        raw_waker(waker)
    }

    // Wake by value, moving the Arc into the Wake::wake function
    unsafe fn wake<W: Wake + Send + Sync + 'static>(waker: *const ()) {
        let waker: Arc<W> = Arc::from_raw(waker as *const W);
        <W as Wake>::wake(waker);
    }

    // Wake by reference, wrap the waker in ManuallyDrop to avoid dropping it
    unsafe fn wake_by_ref<W: Wake + Send + Sync + 'static>(waker: *const ()) {
        let waker: ManuallyDrop<Arc<W>> = ManuallyDrop::new(Arc::from_raw(waker as *const W));
        <W as Wake>::wake_by_ref(&waker);
    }

    // Decrement the reference count of the Arc on drop
    unsafe fn drop_waker<W: Wake + Send + Sync + 'static>(waker: *const ()) {
        mem::drop(Arc::from_raw(waker as *const W));
    }

    RawWaker::new(
        Arc::into_raw(waker) as *const (),
        &RawWakerVTable::new(clone_waker::<W>, wake::<W>, wake_by_ref::<W>, drop_waker::<W>),
    )
}
<|endoftext|>