<commit_before>use crate::sites::*;
use std::collections::BTreeSet;

pub const LUT4_PIN_MAP : &[(&str, &str)] = &[
    ("A", "A"),
    ("B", "B"),
    ("C", "C"),
    ("D", "D"),
    ("Z", "F"),
];

// TODO: need to add an extra pip to use LUT->DI path
const FD1P3BX_PIN_MAP : &[(&str, &str)] = &[
    ("D", "M"),
    ("CK", "CLK"),
    ("SP", "CE"),
    ("PD", "LSR"),
    ("Q", "Q"),
];
const FD1P3DX_PIN_MAP : &[(&str, &str)] = &[
    ("D", "M"),
    ("CK", "CLK"),
    ("SP", "CE"),
    ("CD", "LSR"),
    ("Q", "Q"),
];
const FD1P3IX_PIN_MAP : &[(&str, &str)] = &[
    ("D", "M"),
    ("CK", "CLK"),
    ("SP", "CE"),
    ("CD", "LSR"),
    ("Q", "Q"),
];
const FD1P3JX_PIN_MAP : &[(&str, &str)] = &[
    ("D", "M"),
    ("CK", "CLK"),
    ("SP", "CE"),
    ("PD", "LSR"),
    ("Q", "Q"),
];

const IB_PIN_MAP : &[(&str, &str)] = &[
    ("I", "B"),
    ("O", "O"),
];

const OB_PIN_MAP : &[(&str, &str)] = &[
    ("I", "I"),
    ("O", "B"),
];
// TODO: add back DFFs once we have some constraints set up

const BEL_CELL_TYPES : &[(&str, &[&str])] = &[
    ("OXIDE_COMB", &["LUT4"]),
    ("OXIDE_FF", &["FD1P3BX", "FD1P3DX", "FD1P3IX", "FD1P3JX"]),
    ("SEIO33_CORE", &["IB", "OB"]),
    ("SEIO18_CORE", &["IB", "OB"]),
];

fn conv_map(map: &[(&str, &str)]) -> Vec<(String, String)> {
    map.iter().map(|(c, b)| (c.to_string(), b.to_string())).collect()
}

fn get_map_for_cell_bel(cell_type: &str, _bel: &SiteBel) -> Vec<(String, String)> {
    match cell_type {
        "LUT4" => conv_map(LUT4_PIN_MAP),
        "FD1P3BX" => conv_map(FD1P3BX_PIN_MAP),
        "FD1P3DX" => conv_map(FD1P3DX_PIN_MAP),
        "FD1P3IX" => conv_map(FD1P3IX_PIN_MAP),
        "FD1P3JX" => conv_map(FD1P3JX_PIN_MAP),
        "IB" => conv_map(IB_PIN_MAP),
        "OB" => conv_map(OB_PIN_MAP),
        _ => unimplemented!(),
    }
}

#[derive(Clone)]
pub struct PinMap {
    pub cell_type: String,
    pub bels: Vec<String>,
    pub pin_map: Vec<(String, String)>,
}

pub fn get_pin_maps(site: &Site) -> Vec<PinMap> {
    let mut map = Vec::new();
    let unique_bel_types : BTreeSet<String>
        = site.bels.iter().filter_map(|b| if b.bel_class == SiteBelClass::BEL { Some(b.bel_type.to_string()) } else { None }).collect();
    for bel_type in unique_bel_types.iter() {
        if let Some((_, cell_types)) = BEL_CELL_TYPES.iter().find(|(bt, _)| bt == bel_type) {
            for cell_type in cell_types.iter() {
                map.push(PinMap {
                    cell_type: cell_type.to_string(),
                    bels: site.bels.iter().filter_map(|b| if &b.bel_type == bel_type { Some(b.name.to_string()) } else { None }).collect(),
                    pin_map: get_map_for_cell_bel(cell_type, site.bels.iter().find(|b| &b.bel_type == bel_type).unwrap()),
                });
            }
        }
    }
    return map;
}
<commit_msg>interchange: Add DCC pin mapping<commit_after>use crate::sites::*;
use std::collections::BTreeSet;

pub const LUT4_PIN_MAP : &[(&str, &str)] = &[
    ("A", "A"),
    ("B", "B"),
    ("C", "C"),
    ("D", "D"),
    ("Z", "F"),
];

// TODO: need to add an extra pip to use LUT->DI path
const FD1P3BX_PIN_MAP : &[(&str, &str)] = &[
    ("D", "M"),
    ("CK", "CLK"),
    ("SP", "CE"),
    ("PD", "LSR"),
    ("Q", "Q"),
];
const FD1P3DX_PIN_MAP : &[(&str, &str)] = &[
    ("D", "M"),
    ("CK", "CLK"),
    ("SP", "CE"),
    ("CD", "LSR"),
    ("Q", "Q"),
];
const FD1P3IX_PIN_MAP : &[(&str, &str)] = &[
    ("D", "M"),
    ("CK", "CLK"),
    ("SP", "CE"),
    ("CD", "LSR"),
    ("Q", "Q"),
];
const FD1P3JX_PIN_MAP : &[(&str, &str)] = &[
    ("D", "M"),
    ("CK", "CLK"),
    ("SP", "CE"),
    ("PD", "LSR"),
    ("Q", "Q"),
];

const IB_PIN_MAP : &[(&str, &str)] = &[
    ("I", "B"),
    ("O", "O"),
];

const OB_PIN_MAP : &[(&str, &str)] = &[
    ("I", "I"),
    ("O", "B"),
];

// TODO: add back DFFs once we have some constraints set up

const BEL_CELL_TYPES : &[(&str, &[&str])] = &[
    ("OXIDE_COMB", &["LUT4"]),
    ("OXIDE_FF", &["FD1P3BX", "FD1P3DX", "FD1P3IX", "FD1P3JX"]),
    ("SEIO33_CORE", &["IB", "OB"]),
    ("SEIO18_CORE", &["IB", "OB"]),
    ("DCC", &["DCC"]),
];

fn conv_map(map: &[(&str, &str)]) -> Vec<(String, String)> {
    map.iter().map(|(c, b)| (c.to_string(), b.to_string())).collect()
}

fn auto_map(site: &Site, bel: &SiteBel) -> Vec<(String, String)> {
    bel.pins.iter().map(|p| &site.bel_pins[*p]).map(|p| (p.pin_name.to_string(), p.pin_name.to_string())).collect()
}

fn get_map_for_cell_bel(cell_type: &str, site: &Site, bel: &SiteBel) -> Vec<(String, String)> {
    match cell_type {
        "LUT4" => conv_map(LUT4_PIN_MAP),
        "FD1P3BX" => conv_map(FD1P3BX_PIN_MAP),
        "FD1P3DX" => conv_map(FD1P3DX_PIN_MAP),
        "FD1P3IX" => conv_map(FD1P3IX_PIN_MAP),
        "FD1P3JX" => conv_map(FD1P3JX_PIN_MAP),
        "IB" => conv_map(IB_PIN_MAP),
        "OB" => conv_map(OB_PIN_MAP),
        "DCC" => auto_map(site, bel),
        _ => unimplemented!(),
    }
}

#[derive(Clone)]
pub struct PinMap {
    pub cell_type: String,
    pub bels: Vec<String>,
    pub pin_map: Vec<(String, String)>,
}

pub fn get_pin_maps(site: &Site) -> Vec<PinMap> {
    let mut map = Vec::new();
    let unique_bel_types : BTreeSet<String>
        = site.bels.iter().filter_map(|b| if b.bel_class == SiteBelClass::BEL { Some(b.bel_type.to_string()) } else { None }).collect();
    for bel_type in unique_bel_types.iter() {
        if let Some((_, cell_types)) = BEL_CELL_TYPES.iter().find(|(bt, _)| bt == bel_type) {
            for cell_type in cell_types.iter() {
                map.push(PinMap {
                    cell_type: cell_type.to_string(),
                    bels: site.bels.iter().filter_map(|b| if &b.bel_type == bel_type { Some(b.name.to_string()) } else { None }).collect(),
                    pin_map: get_map_for_cell_bel(cell_type, site, site.bels.iter().find(|b| &b.bel_type == bel_type).unwrap()),
                });
            }
        }
    }
    return map;
}
<|endoftext|>


<commit_before>// Copyright 2015-2017 Intecture Developers.
//
// Licensed under the Mozilla Public License 2.0 <LICENSE or
// https://www.tldrlegal.com/l/mpl-2.0>. This file may not be copied,
// modified, or distributed except according to those terms.

extern crate futures;
extern crate intecture_api;
extern crate tokio_core;

use futures::Future;
use intecture_api::prelude::*;
use tokio_core::reactor::Core;

fn main() {
    let mut core = Core::new().unwrap();

    let host = Local::new().and_then(|host| {
        Command::new(&host, "whoami", None).and_then(|mut cmd| {
            cmd.exec().map(|out| {
                println!("I'm currently running as {}", String::from_utf8_lossy(&out.stdout).trim());
            })
        })
    });

    core.run(host).unwrap();
}
<commit_msg>Fixed examples<commit_after>// Copyright 2015-2017 Intecture Developers.
//
// Licensed under the Mozilla Public License 2.0 <LICENSE or
// https://www.tldrlegal.com/l/mpl-2.0>. This file may not be copied,
// modified, or distributed except according to those terms.

extern crate futures;
extern crate intecture_api;
extern crate tokio_core;

use futures::Future;
use intecture_api::prelude::*;
use tokio_core::reactor::Core;

fn main() {
    let mut core = Core::new().unwrap();
    let handle = core.handle();

    let host = Local::new().and_then(|host| {
        Command::new(&host, "whoami", None).and_then(|mut cmd| {
            cmd.exec(&handle).map(|out| {
                println!("I'm currently running as {}", String::from_utf8_lossy(&out.stdout).trim());
            })
        })
    });

    core.run(host).unwrap();
}

<|endoftext|>


<commit_before>#[macro_use]
mod macros;
mod expression;
mod statement;

use error::Result;

use ast::{Program, Store, Node, Index, Item};
use lexer::{Lexer, Token};
use lexer::Token::*;

pub struct Parser<'src> {
    /// Lexer will produce tokens from the source
    lexer: Lexer<'src>,

    /// Current token, to be used by peek! and next! macros
    token: Option<Token>,

    /// AST under construction
    program: Program<'src>,
}

impl<'src> Parser<'src> {
    pub fn new(source: &'src str) -> Self {
        Parser {
            lexer: Lexer::new(source),
            token: None,
            program: Program {
                source: source,
                root: None,
                items: Store::new(),
            }
        }
    }

    #[inline]
    fn consume(&mut self) {
        self.token = None;
    }

    #[inline]
    fn store(&mut self, node: Node) -> Index {
        self.program.items.insert(node)
    }

    #[inline]
    fn parse(&mut self) -> Result<()> {
        let statement = match next!(self) {
            EndOfProgram => return Ok(()),
            token        => try!(self.statement(token))
        };

        let mut previous = self.store(statement);

        self.program.root = Some(previous);

        loop {
            let statement = match next!(self) {
                EndOfProgram => break,
                token        => try!(self.statement(token))
            };

            let index = self.store(statement);

            self.program.items[previous].next = Some(index);

            previous = index;
        }

        Ok(())
    }

    #[inline]
    fn block_body_tail(&mut self) -> Result<Option<Index>> {
        let statement = match next!(self) {
            BraceClose => return Ok(None),
            token      => try!(self.statement(token)),
        };

        let mut previous = self.store(statement);
        let root = Some(previous);

        loop {
            let statement = match next!(self) {
                BraceClose => break,
                token      => try!(self.statement(token)),
            };

            let index = self.store(statement);
            self.program.items[previous].next = Some(index);

            previous = index;
        }

        Ok(root)
    }

    #[inline]
    fn block_body(&mut self) -> Result<Option<Index>> {
        expect!(self, BraceOpen);
        self.block_body_tail()
    }

    fn parameter_list(&mut self) -> Result<Option<Index>> {
        let name = match next!(self) {
            ParenClose       => return Ok(None),
            Identifier(name) => name,
            _                => unexpected_token!(self),
        };

        let mut previous = self.store(Item::Identifier(name.into()).at(0, 0));
        let root = Some(previous);

        loop {
            let name = match next!(self) {
                ParenClose => break,
                Comma      => expect_identifier!(self),
                _          => unexpected_token!(self),
            };

            let index = self.store(Item::Identifier(name.into()).at(0, 0));
            self.program.items[previous].next = Some(index);

            previous = index;
        }

        Ok(root)

        // let mut default_params = false;

        // loop {
        //     let name = match next!(self) {
        //         ParenClose       => break,
        //         Identifier(name) => name,
        //         _ => unexpected_token!(self)
        //     };

        //     list.push(match peek!(self) {
        //         Operator(Assign) => {
        //             self.consume();
        //             let expression = try!(self.expression(0));
        //             default_params = true;
        //             Parameter {
        //                 name: name.into(),
        //                 default: Some(Box::new(expression))
        //             }
        //         }
        //         _ => {
        //             if default_params {
        //                 unexpected_token!(self);
        //             }
        //             Parameter {
        //                 name: name.into(),
        //                 default: None
        //             }
        //         }
        //     });

        //     match next!(self) {
        //         ParenClose => break,
        //         Comma      => {},
        //         _          => unexpected_token!(self)
        //     }
        // }

        // Ok(list)
    }

}

pub fn parse<'src>(source: &'src str) -> Result<Program<'src>> {
    let mut parser = Parser::new(source);

    parser.parse()?;

    Ok(parser.program)
}

#[cfg(test)]
mod test {
    use super::*;
    use ast::OperatorKind;

    macro_rules! assert_item {
        ($item:expr, $m:pat => $eval:expr) => {
            match $item {
                $m => assert!($eval),
                _ => panic!("Failed assert_item")
            }
        }
    }

    macro_rules! assert_ident {
        ($item.expr, $src:ident, $expect:expr) => {
            assert_item!($item, Item::Identifier(ref i) => i.as_str($src) == $expect);
        }
    }

    #[test]
    fn empty_parse() {
        let program = parse("").unwrap();

        assert_eq!(program.items.len(), 0);
        assert_eq!(program.root, None);
        assert_eq!(program.statements().next(), None);
    }

    #[test]
    fn empty_statements() {
        let program = parse(";;;").unwrap();

        assert_eq!(program.items.len(), 3);

        // Statements are linked
        let mut stmts = program.statements();
        assert_eq!(stmts.next().unwrap(), &Item::EmptyStatement);
        assert_eq!(stmts.next().unwrap(), &Item::EmptyStatement);
        assert_eq!(stmts.next().unwrap(), &Item::EmptyStatement);
        assert_eq!(stmts.next(), None);
    }

    #[test]
    fn parse_ident_expr() {
        let src = "foo; bar; baz;";

        let program = parse(src).unwrap();

        let items = &program.items;

        // 3 times statement and expression
        assert_eq!(items.len(), 6);

        // First statement is after first expression
        assert_eq!(program.root, Some(1));

        // Statements are linked
        let mut stmts = program.statements();
        assert_eq!(stmts.next().unwrap(), &Item::ExpressionStatement(0));
        assert_eq!(stmts.next().unwrap(), &Item::ExpressionStatement(2));
        assert_eq!(stmts.next().unwrap(), &Item::ExpressionStatement(4));
        assert_eq!(stmts.next(), None);

        // Match identifiers
        assert_ident!(items[0].item, src, "foo");
        assert_ident!(items[0].item, src, "bar");
        assert_ident!(items[0].item, src, "baz");
    }

    #[test]
    fn parse_binary_and_postfix_expr() {
        let src = "foo + bar; baz++;";

        let program = parse(src).unwrap();

        let items = &program.items;

        // 2 statements, 3 simple expressions, one binary expression, one postfix expression
        assert_eq!(items.len(), 7);

        // First statement is after binary expression and two of it's side expressions
        assert_eq!(program.root, Some(3));

        // Statements are linked
        let mut stmts = program.statements();
        assert_eq!(stmts.next().unwrap(), &Item::ExpressionStatement(2));
        assert_eq!(stmts.next().unwrap(), &Item::ExpressionStatement(5));
        assert_eq!(stmts.next(), None);

        // Binary expression
        assert_eq!(items[2].item, Item::BinaryExpr {
            parenthesized: false,
            operator: OperatorKind::Addition,
            left: 0,
            right: 1,
        });
        assert_ident!(items[0].item, src, "foo");
        assert_ident!(items[1].item, src, "foo");

        // Postfix expression
        assert_eq!(items[5].item, Item::PostfixExpr {
            operator: OperatorKind::Increment,
            operand: 4
        });
        assert_ident!(items[1].item, src, "baz");
    }

    #[test]
    fn function_statement_empty() {
        let src = "function foo() {}";

        let program = parse(src).unwrap();

        let mut stmts = program.statements();

        match *stmts.next().unwrap() {
            Item::FunctionStatement {
                ref name,
                params: None,
                body: None,
            } => assert_eq!(name.as_str(src), "foo"),
            _ => panic!()
        }

        assert_eq!(stmts.next(), None);
    }

    #[test]
    fn function_statement_params() {
        let src = "function foo(bar, baz) {}";

        let program = parse(src).unwrap();

        let items = &program.items;
        let mut stmts = program.statements();

        match *stmts.next().unwrap() {
            Item::FunctionStatement {
                ref name,
                params: Some(0),
                body: None,
            } => assert_eq!(name.as_str(src), "foo"),
            _ => panic!()
        }

        // Params are linked
        let mut params = program.items.list(0);
        assert_ident!(*params.next().unwrap(), src, "bar");
        assert_ident!(*params.next().unwrap(), src, "baz");
        assert_eq!(params.next(), None);
    }
}
<commit_msg>Tests are working<commit_after>#[macro_use]
mod macros;
mod expression;
mod statement;

use error::Result;

use ast::{Program, Store, Node, Index, Item};
use lexer::{Lexer, Token};
use lexer::Token::*;

pub struct Parser<'src> {
    /// Lexer will produce tokens from the source
    lexer: Lexer<'src>,

    /// Current token, to be used by peek! and next! macros
    token: Option<Token>,

    /// AST under construction
    program: Program<'src>,
}

impl<'src> Parser<'src> {
    pub fn new(source: &'src str) -> Self {
        Parser {
            lexer: Lexer::new(source),
            token: None,
            program: Program {
                source: source,
                root: None,
                items: Store::new(),
            }
        }
    }

    #[inline]
    fn consume(&mut self) {
        self.token = None;
    }

    #[inline]
    fn store(&mut self, node: Node) -> Index {
        self.program.items.insert(node)
    }

    #[inline]
    fn parse(&mut self) -> Result<()> {
        let statement = match next!(self) {
            EndOfProgram => return Ok(()),
            token        => try!(self.statement(token))
        };

        let mut previous = self.store(statement);

        self.program.root = Some(previous);

        loop {
            let statement = match next!(self) {
                EndOfProgram => break,
                token        => try!(self.statement(token))
            };

            let index = self.store(statement);

            self.program.items[previous].next = Some(index);

            previous = index;
        }

        Ok(())
    }

    #[inline]
    fn block_body_tail(&mut self) -> Result<Option<Index>> {
        let statement = match next!(self) {
            BraceClose => return Ok(None),
            token      => try!(self.statement(token)),
        };

        let mut previous = self.store(statement);
        let root = Some(previous);

        loop {
            let statement = match next!(self) {
                BraceClose => break,
                token      => try!(self.statement(token)),
            };

            let index = self.store(statement);
            self.program.items[previous].next = Some(index);

            previous = index;
        }

        Ok(root)
    }

    #[inline]
    fn block_body(&mut self) -> Result<Option<Index>> {
        expect!(self, BraceOpen);
        self.block_body_tail()
    }

    fn parameter_list(&mut self) -> Result<Option<Index>> {
        let name = match next!(self) {
            ParenClose       => return Ok(None),
            Identifier(name) => name,
            _                => unexpected_token!(self),
        };

        let mut previous = self.store(Item::Identifier(name.into()).at(0, 0));
        let root = Some(previous);

        loop {
            let name = match next!(self) {
                ParenClose => break,
                Comma      => expect_identifier!(self),
                _          => unexpected_token!(self),
            };

            let index = self.store(Item::Identifier(name.into()).at(0, 0));
            self.program.items[previous].next = Some(index);

            previous = index;
        }

        Ok(root)

        // let mut default_params = false;

        // loop {
        //     let name = match next!(self) {
        //         ParenClose       => break,
        //         Identifier(name) => name,
        //         _ => unexpected_token!(self)
        //     };

        //     list.push(match peek!(self) {
        //         Operator(Assign) => {
        //             self.consume();
        //             let expression = try!(self.expression(0));
        //             default_params = true;
        //             Parameter {
        //                 name: name.into(),
        //                 default: Some(Box::new(expression))
        //             }
        //         }
        //         _ => {
        //             if default_params {
        //                 unexpected_token!(self);
        //             }
        //             Parameter {
        //                 name: name.into(),
        //                 default: None
        //             }
        //         }
        //     });

        //     match next!(self) {
        //         ParenClose => break,
        //         Comma      => {},
        //         _          => unexpected_token!(self)
        //     }
        // }

        // Ok(list)
    }

}

pub fn parse<'src>(source: &'src str) -> Result<Program<'src>> {
    let mut parser = Parser::new(source);

    parser.parse()?;

    Ok(parser.program)
}

#[cfg(test)]
mod test {
    use super::*;
    use ast::OperatorKind;

    macro_rules! assert_item {
        ($item:expr, $m:pat => $eval:expr) => {
            match $item {
                $m => assert!($eval),
                _ => panic!("Failed assert_item")
            }
        }
    }

    macro_rules! assert_ident {
        ($item:expr, $src:ident, $expect:expr) => {
            assert_item!($item, Item::Identifier(ref i) => i.as_str($src) == $expect);
        }
    }

    #[test]
    fn empty_parse() {
        let program = parse("").unwrap();

        assert_eq!(program.items.len(), 0);
        assert_eq!(program.root, None);
        assert_eq!(program.statements().next(), None);
    }

    #[test]
    fn empty_statements() {
        let program = parse(";;;").unwrap();

        assert_eq!(program.items.len(), 3);

        // Statements are linked
        let mut stmts = program.statements();
        assert_eq!(stmts.next().unwrap(), &Item::EmptyStatement);
        assert_eq!(stmts.next().unwrap(), &Item::EmptyStatement);
        assert_eq!(stmts.next().unwrap(), &Item::EmptyStatement);
        assert_eq!(stmts.next(), None);
    }

    #[test]
    fn parse_ident_expr() {
        let src = "foo; bar; baz;";

        let program = parse(src).unwrap();

        let items = &program.items;

        // 3 times statement and expression
        assert_eq!(items.len(), 6);

        // First statement is after first expression
        assert_eq!(program.root, Some(1));

        // Statements are linked
        let mut stmts = program.statements();
        assert_eq!(stmts.next().unwrap(), &Item::ExpressionStatement(0));
        assert_eq!(stmts.next().unwrap(), &Item::ExpressionStatement(2));
        assert_eq!(stmts.next().unwrap(), &Item::ExpressionStatement(4));
        assert_eq!(stmts.next(), None);

        // Match identifiers
        assert_ident!(items[0].item, src, "foo");
        assert_ident!(items[2].item, src, "bar");
        assert_ident!(items[4].item, src, "baz");
    }

    #[test]
    fn parse_binary_and_postfix_expr() {
        let src = "foo + bar; baz++;";

        let program = parse(src).unwrap();

        let items = &program.items;

        // 2 statements, 3 simple expressions, one binary expression, one postfix expression
        assert_eq!(items.len(), 7);

        // First statement is after binary expression and two of it's side expressions
        assert_eq!(program.root, Some(3));

        // Statements are linked
        let mut stmts = program.statements();
        assert_eq!(stmts.next().unwrap(), &Item::ExpressionStatement(2));
        assert_eq!(stmts.next().unwrap(), &Item::ExpressionStatement(5));
        assert_eq!(stmts.next(), None);

        // Binary expression
        assert_eq!(items[2].item, Item::BinaryExpr {
            parenthesized: false,
            operator: OperatorKind::Addition,
            left: 0,
            right: 1,
        });
        assert_ident!(items[0].item, src, "foo");
        assert_ident!(items[1].item, src, "bar");

        // Postfix expression
        assert_eq!(items[5].item, Item::PostfixExpr {
            operator: OperatorKind::Increment,
            operand: 4
        });
        assert_ident!(items[4].item, src, "baz");
    }

    #[test]
    fn function_statement_empty() {
        let src = "function foo() {}";

        let program = parse(src).unwrap();

        let mut stmts = program.statements();

        match *stmts.next().unwrap() {
            Item::FunctionStatement {
                ref name,
                params: None,
                body: None,
            } => assert_eq!(name.as_str(src), "foo"),
            _ => panic!()
        }

        assert_eq!(stmts.next(), None);
    }

    #[test]
    fn function_statement_params() {
        let src = "function foo(bar, baz) {}";

        let program = parse(src).unwrap();

        let items = &program.items;
        let mut stmts = program.statements();

        match *stmts.next().unwrap() {
            Item::FunctionStatement {
                ref name,
                params: Some(0),
                body: None,
            } => assert_eq!(name.as_str(src), "foo"),
            _ => panic!()
        }

        // Params are linked
        let mut params = program.items.list(0);
        assert_ident!(*params.next().unwrap(), src, "bar");
        assert_ident!(*params.next().unwrap(), src, "baz");
        assert_eq!(params.next(), None);
    }
}
<|endoftext|>


<commit_before>extern crate itertools;
use super::merge_policy::{MergePolicy, MergeCandidate};
use core::SegmentMeta;

pub struct LogMergePolicy;
use std::f64;

const LEVEL_LOG_SIZE: f64 = 0.75;
const MIN_MERGE_SIZE: usize = 3;

impl MergePolicy for LogMergePolicy {
    fn compute_merge_candidates(&self, segments: &[SegmentMeta]) -> Vec<MergeCandidate> {
        if segments.is_empty() {
            return Vec::new();
        }
        let mut size_sorted_tuples = segments.iter()
            .map(|x| x.num_docs)
            .enumerate()
            .collect::<Vec<(usize, u32)>>();

        size_sorted_tuples.sort_by(|x,y| y.cmp(x));

        let size_sorted_log_tuples: Vec<_> = size_sorted_tuples.iter()
            .map(|x| (x.0, (x.1 as f64).log2()))
            .collect();

        let (first_ind, first_score) = size_sorted_log_tuples[0];
        let mut current_max_log_size = first_score;
        let mut levels = vec!(vec!(first_ind));
        for &(ind, score) in (&size_sorted_log_tuples).iter().skip(1) {
            if score < (current_max_log_size - LEVEL_LOG_SIZE) {
                current_max_log_size = score;
                levels.push(Vec::new());
            }
            levels.last_mut().unwrap().push(ind);
        }

        let result = levels.iter()
            .filter(|level| {level.len() >= MIN_MERGE_SIZE})
            .map(|ind_vec| {
                MergeCandidate(ind_vec.iter()
                    .map(|&ind| segments[ind].segment_id)
                    .collect())
            })
            .collect();

        result
    }
}

impl Default for LogMergePolicy {
    fn default() -> LogMergePolicy {
        LogMergePolicy
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use indexer::merge_policy::MergePolicy;
    use core::{SegmentMeta, SegmentId};

    #[test]
    fn test_log_merge_policy_empty() {
        let y = Vec::new();
        let result_list = LogMergePolicy::default().compute_merge_candidates(&y);
        assert!(result_list.len() == 0);
    }

    #[test]
    fn test_log_merge_policy_pair() {
        let test_input = vec![SegmentMeta::new(SegmentId::generate_random(), 10),
                              SegmentMeta::new(SegmentId::generate_random(), 10),
        SegmentMeta::new(SegmentId::generate_random(), 10)];
        let result_list = LogMergePolicy::default().compute_merge_candidates(&test_input);
        assert!(result_list.len() == 1);
    }

    #[test]
    fn test_log_merge_policy_levels() {
        // multiple levels all get merged correctly
        let test_input = vec![SegmentMeta::new(SegmentId::generate_random(), 10),
                              SegmentMeta::new(SegmentId::generate_random(), 10),
                              SegmentMeta::new(SegmentId::generate_random(), 10),
                              SegmentMeta::new(SegmentId::generate_random(), 1000),
                              SegmentMeta::new(SegmentId::generate_random(), 1000),
                              SegmentMeta::new(SegmentId::generate_random(), 1000)];
        let result_list = LogMergePolicy::default().compute_merge_candidates(&test_input);
        assert!(result_list.len() == 2);
    }

    #[test]
    fn test_log_merge_policy_within_levels() {
        // multiple levels all get merged correctly
        let test_input = vec![SegmentMeta::new(SegmentId::generate_random(), 10),
                              SegmentMeta::new(SegmentId::generate_random(), 11),
                              SegmentMeta::new(SegmentId::generate_random(), 12),
                              SegmentMeta::new(SegmentId::generate_random(), 1000),
                              SegmentMeta::new(SegmentId::generate_random(), 1000),
                              SegmentMeta::new(SegmentId::generate_random(), 1000)];
        let result_list = LogMergePolicy::default().compute_merge_candidates(&test_input);
        assert!(result_list.len() == 2);
    }
}
<commit_msg>clip segment size floor<commit_after>extern crate itertools;
use super::merge_policy::{MergePolicy, MergeCandidate};
use core::SegmentMeta;

pub struct LogMergePolicy;
use std::f64;

const LEVEL_LOG_SIZE: f64 = 0.75;
const MIN_SEGMENT_SIZE: u32 = 2;
const MIN_MERGE_SIZE: usize = 3;

impl MergePolicy for LogMergePolicy {
    fn compute_merge_candidates(&self, segments: &[SegmentMeta]) -> Vec<MergeCandidate> {
        if segments.is_empty() {
            return Vec::new();
        }
        let mut size_sorted_tuples = segments.iter()
            .map(|x| x.num_docs)
            .enumerate()
            .collect::<Vec<(usize, u32)>>();

        size_sorted_tuples.sort_by(|x,y| y.cmp(x));

        fn clip_min_size(size: u32 ) -> u32 {
            if size <= MIN_SEGMENT_SIZE {
                MIN_SEGMENT_SIZE
            } else {
                size
            }
        }
        let size_sorted_log_tuples: Vec<_> = size_sorted_tuples.iter()
            .map(|x| (x.0, (clip_min_size(x.1) as f64).log2()))
            .collect();

        let (first_ind, first_score) = size_sorted_log_tuples[0];
        let mut current_max_log_size = first_score;
        let mut levels = vec!(vec!(first_ind));
        for &(ind, score) in (&size_sorted_log_tuples).iter().skip(1) {
            if score < (current_max_log_size - LEVEL_LOG_SIZE) {
                current_max_log_size = score;
                levels.push(Vec::new());
            }
            levels.last_mut().unwrap().push(ind);
        }

        let result = levels.iter()
            .filter(|level| {level.len() >= MIN_MERGE_SIZE})
            .map(|ind_vec| {
                MergeCandidate(ind_vec.iter()
                    .map(|&ind| segments[ind].segment_id)
                    .collect())
            })
            .collect();

        result
    }
}

impl Default for LogMergePolicy {
    fn default() -> LogMergePolicy {
        LogMergePolicy
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use indexer::merge_policy::MergePolicy;
    use core::{SegmentMeta, SegmentId};

    #[test]
    fn test_log_merge_policy_empty() {
        let y = Vec::new();
        let result_list = LogMergePolicy::default().compute_merge_candidates(&y);
        assert!(result_list.len() == 0);
    }

    #[test]
    fn test_log_merge_policy_pair() {
        let test_input = vec![SegmentMeta::new(SegmentId::generate_random(), 10),
                              SegmentMeta::new(SegmentId::generate_random(), 10),
        SegmentMeta::new(SegmentId::generate_random(), 10)];
        let result_list = LogMergePolicy::default().compute_merge_candidates(&test_input);
        assert!(result_list.len() == 1);
    }

    #[test]
    fn test_log_merge_policy_levels() {
        // multiple levels all get merged correctly
        let test_input = vec![SegmentMeta::new(SegmentId::generate_random(), 10),
                              SegmentMeta::new(SegmentId::generate_random(), 10),
                              SegmentMeta::new(SegmentId::generate_random(), 10),
                              SegmentMeta::new(SegmentId::generate_random(), 1000),
                              SegmentMeta::new(SegmentId::generate_random(), 1000),
                              SegmentMeta::new(SegmentId::generate_random(), 1000)];
        let result_list = LogMergePolicy::default().compute_merge_candidates(&test_input);
        assert!(result_list.len() == 2);
    }

    #[test]
    fn test_log_merge_policy_within_levels() {
        // multiple levels all get merged correctly
        let test_input = vec![SegmentMeta::new(SegmentId::generate_random(), 10),
                              SegmentMeta::new(SegmentId::generate_random(), 11),
                              SegmentMeta::new(SegmentId::generate_random(), 12),
                              SegmentMeta::new(SegmentId::generate_random(), 1000),
                              SegmentMeta::new(SegmentId::generate_random(), 1000),
                              SegmentMeta::new(SegmentId::generate_random(), 1000)];
        let result_list = LogMergePolicy::default().compute_merge_candidates(&test_input);
        assert!(result_list.len() == 2);
    }
    #[test]
    fn test_log_merge_policy_small_segments() {
        // multiple levels all get merged correctly
        let test_input = vec![SegmentMeta::new(SegmentId::generate_random(), 1),
                              SegmentMeta::new(SegmentId::generate_random(), 1),
                              SegmentMeta::new(SegmentId::generate_random(), 1),
                              SegmentMeta::new(SegmentId::generate_random(), 2),
                              SegmentMeta::new(SegmentId::generate_random(), 2),
                              SegmentMeta::new(SegmentId::generate_random(), 2)];
        let result_list = LogMergePolicy::default().compute_merge_candidates(&test_input);
        assert!(result_list.len() == 1);
    }
}
<|endoftext|>


<commit_before>//! The grid-details view lists several details views side-by-side.

use std::io::{self, Write};

use ansi_term::ANSIStrings;
use term_grid as grid;

use crate::fs::{Dir, File};
use crate::fs::feature::git::GitCache;
use crate::fs::feature::xattr::FileAttributes;
use crate::fs::filter::FileFilter;
use crate::output::cell::TextCell;
use crate::output::details::{Options as DetailsOptions, Row as DetailsRow, Render as DetailsRender};
use crate::output::file_name::Options as FileStyle;
use crate::output::grid::Options as GridOptions;
use crate::output::table::{Table, Row as TableRow, Options as TableOptions};
use crate::output::tree::{TreeParams, TreeDepth};
use crate::theme::Theme;

#[derive(PartialEq, Debug)]
pub struct Options {
    pub grid: GridOptions,
    pub details: DetailsOptions,
    pub row_threshold: RowThreshold,
}

impl Options {
    pub fn to_details_options(&self) -> &DetailsOptions {
        &self.details
    }
}

/// The grid-details view can be configured to revert to just a details view
/// (with one column) if it wouldn’t produce enough rows of output.
///
/// Doing this makes the resulting output look a bit better: when listing a
/// small directory of four files in four columns, the files just look spaced
/// out and it’s harder to see what’s going on. So it can be enabled just for
/// larger directory listings.
#[derive(PartialEq, Debug, Copy, Clone)]
pub enum RowThreshold {

    /// Only use grid-details view if it would result in at least this many
    /// rows of output.
    MinimumRows(usize),

    /// Use the grid-details view no matter what.
    AlwaysGrid,
}

pub struct Render<'a> {

    /// The directory that’s being rendered here.
    /// We need this to know which columns to put in the output.
    pub dir: Option<&'a Dir>,

    /// The files that have been read from the directory. They should all
    /// hold a reference to it.
    pub files: Vec<File<'a>>,

    /// How to colour various pieces of text.
    pub theme: &'a Theme,

    /// How to format filenames.
    pub file_style: &'a FileStyle,

    /// The grid part of the grid-details view.
    pub grid: &'a GridOptions,

    /// The details part of the grid-details view.
    pub details: &'a DetailsOptions,

    /// How to filter files after listing a directory. The files in this
    /// render will already have been filtered and sorted, but any directories
    /// that we recurse into will have to have this applied.
    pub filter: &'a FileFilter,

    /// The minimum number of rows that there need to be before grid-details
    /// mode is activated.
    pub row_threshold: RowThreshold,

    /// Whether we are skipping Git-ignored files.
    pub git_ignoring: bool,

    pub git: Option<&'a GitCache>,

    pub console_width: usize,
}

impl<'a> Render<'a> {

    /// Create a temporary Details render that gets used for the columns of
    /// the grid-details render that’s being generated.
    ///
    /// This includes an empty files vector because the files get added to
    /// the table in *this* file, not in details: we only want to insert every
    /// *n* files into each column’s table, not all of them.
    fn details_for_column(&self) -> DetailsRender<'a> {
        DetailsRender {
            dir:           self.dir,
            files:         Vec::new(),
            theme:         self.theme,
            file_style:    self.file_style,
            opts:          self.details,
            recurse:       None,
            filter:        self.filter,
            git_ignoring:  self.git_ignoring,
            git:           self.git,
        }
    }

    /// Create a Details render for when this grid-details render doesn’t fit
    /// in the terminal (or something has gone wrong) and we have given up, or
    /// when the user asked for a grid-details view but the terminal width is
    /// not available, so we downgrade.
    pub fn give_up(self) -> DetailsRender<'a> {
        DetailsRender {
            dir:           self.dir,
            files:         self.files,
            theme:         self.theme,
            file_style:    self.file_style,
            opts:          self.details,
            recurse:       None,
            filter:        self.filter,
            git_ignoring:  self.git_ignoring,
            git:           self.git,
        }
    }

    // This doesn’t take an IgnoreCache even though the details one does
    // because grid-details has no tree view.

    pub fn render<W: Write>(mut self, w: &mut W) -> io::Result<()> {
        if let Some((grid, width)) = self.find_fitting_grid() {
            write!(w, "{}", grid.fit_into_columns(width))
        }
        else {
            self.give_up().render(w)
        }
    }

    pub fn find_fitting_grid(&mut self) -> Option<(grid::Grid, grid::Width)> {
        let options = self.details.table.as_ref().expect("Details table options not given!");

        let drender = self.details_for_column();

        let (first_table, _) = self.make_table(options, &drender);

        let rows = self.files.iter()
                       .map(|file| first_table.row_for_file(file, file_has_xattrs(file)))
                       .collect::<Vec<_>>();

        let file_names = self.files.iter()
                             .map(|file| self.file_style.for_file(file, self.theme).paint().promote())
                             .collect::<Vec<_>>();

        let mut last_working_grid = self.make_grid(1, options, &file_names, rows.clone(), &drender);

        if file_names.len() == 1 {
            return Some((last_working_grid, 1));
        }

        // If we can’t fit everything in a grid 100 columns wide, then
        // something has gone seriously awry
        for column_count in 2..100 {
            let grid = self.make_grid(column_count, options, &file_names, rows.clone(), &drender);

            let the_grid_fits = {
                let d = grid.fit_into_columns(column_count);
                d.width() <= self.console_width
            };

            if the_grid_fits {
                if column_count == file_names.len() {
                    return Some((grid, column_count));
                } else {
                    last_working_grid = grid;
                }
            } else {
                // If we’ve figured out how many columns can fit in the user’s
                // terminal, and it turns out there aren’t enough rows to
                // make it worthwhile, then just resort to the lines view.
                if let RowThreshold::MinimumRows(thresh) = self.row_threshold {
                    if last_working_grid.fit_into_columns(column_count - 1).row_count() < thresh {
                        return None;
                    }
                }

                return Some((last_working_grid, column_count - 1));
            }
        }

        None
    }

    fn make_table(&mut self, options: &'a TableOptions, drender: &DetailsRender<'_>) -> (Table<'a>, Vec<DetailsRow>) {
        match (self.git, self.dir) {
            (Some(g), Some(d))  => if ! g.has_anything_for(&d.path) { self.git = None },
            (Some(g), None)     => if ! self.files.iter().any(|f| g.has_anything_for(&f.path)) { self.git = None },
            (None,    _)        => {/* Keep Git how it is */},
        }

        let mut table = Table::new(options, self.git, &self.theme);
        let mut rows = Vec::new();

        if self.details.header {
            let row = table.header_row();
            table.add_widths(&row);
            rows.push(drender.render_header(row));
        }

        (table, rows)
    }

    fn make_grid(&mut self, column_count: usize, options: &'a TableOptions, file_names: &[TextCell], rows: Vec<TableRow>, drender: &DetailsRender<'_>) -> grid::Grid {
        let mut tables = Vec::new();
        for _ in 0 .. column_count {
            tables.push(self.make_table(options, drender));
        }

        let mut num_cells = rows.len();
        if self.details.header {
            num_cells += column_count;
        }

        let original_height = divide_rounding_up(rows.len(), column_count);
        let height = divide_rounding_up(num_cells, column_count);

        for (i, (file_name, row)) in file_names.iter().zip(rows.into_iter()).enumerate() {
            let index = if self.grid.across {
                    i % column_count
                }
                else {
                    i / original_height
                };

            let (ref mut table, ref mut rows) = tables[index];
            table.add_widths(&row);
            let details_row = drender.render_file(row, file_name.clone(), TreeParams::new(TreeDepth::root(), false));
            rows.push(details_row);
        }

        let columns = tables
            .into_iter()
            .map(|(table, details_rows)| {
                drender.iterate_with_table(table, details_rows)
                       .collect::<Vec<_>>()
                })
            .collect::<Vec<_>>();

        let direction = if self.grid.across { grid::Direction::LeftToRight }
                                       else { grid::Direction::TopToBottom };

        let filling = grid::Filling::Spaces(4);
        let mut grid = grid::Grid::new(grid::GridOptions { direction, filling });

        if self.grid.across {
            for row in 0 .. height {
                for column in &columns {
                    if row < column.len() {
                        let cell = grid::Cell {
                            contents: ANSIStrings(&column[row].contents).to_string(),
                            width:    *column[row].width,
                        };

                        grid.add(cell);
                    }
                }
            }
        }
        else {
            for column in &columns {
                for cell in column.iter() {
                    let cell = grid::Cell {
                        contents: ANSIStrings(&cell.contents).to_string(),
                        width:    *cell.width,
                    };

                    grid.add(cell);
                }
            }
        }

        grid
    }
}

fn divide_rounding_up(a: usize, b: usize) -> usize {
    let mut result = a / b;

    if a % b != 0 {
        result += 1;
    }

    result
}

fn file_has_xattrs(file: &File<'_>) -> bool {
    match file.path.attributes() {
        Ok(attrs)  => ! attrs.is_empty(),
        Err(_)     => false,
    }
}
<commit_msg>Fix EXA_GRID_ROWS not working in some cases<commit_after>//! The grid-details view lists several details views side-by-side.

use std::io::{self, Write};

use ansi_term::ANSIStrings;
use term_grid as grid;

use crate::fs::{Dir, File};
use crate::fs::feature::git::GitCache;
use crate::fs::feature::xattr::FileAttributes;
use crate::fs::filter::FileFilter;
use crate::output::cell::TextCell;
use crate::output::details::{Options as DetailsOptions, Row as DetailsRow, Render as DetailsRender};
use crate::output::file_name::Options as FileStyle;
use crate::output::grid::Options as GridOptions;
use crate::output::table::{Table, Row as TableRow, Options as TableOptions};
use crate::output::tree::{TreeParams, TreeDepth};
use crate::theme::Theme;

#[derive(PartialEq, Debug)]
pub struct Options {
    pub grid: GridOptions,
    pub details: DetailsOptions,
    pub row_threshold: RowThreshold,
}

impl Options {
    pub fn to_details_options(&self) -> &DetailsOptions {
        &self.details
    }
}

/// The grid-details view can be configured to revert to just a details view
/// (with one column) if it wouldn’t produce enough rows of output.
///
/// Doing this makes the resulting output look a bit better: when listing a
/// small directory of four files in four columns, the files just look spaced
/// out and it’s harder to see what’s going on. So it can be enabled just for
/// larger directory listings.
#[derive(PartialEq, Debug, Copy, Clone)]
pub enum RowThreshold {

    /// Only use grid-details view if it would result in at least this many
    /// rows of output.
    MinimumRows(usize),

    /// Use the grid-details view no matter what.
    AlwaysGrid,
}

pub struct Render<'a> {

    /// The directory that’s being rendered here.
    /// We need this to know which columns to put in the output.
    pub dir: Option<&'a Dir>,

    /// The files that have been read from the directory. They should all
    /// hold a reference to it.
    pub files: Vec<File<'a>>,

    /// How to colour various pieces of text.
    pub theme: &'a Theme,

    /// How to format filenames.
    pub file_style: &'a FileStyle,

    /// The grid part of the grid-details view.
    pub grid: &'a GridOptions,

    /// The details part of the grid-details view.
    pub details: &'a DetailsOptions,

    /// How to filter files after listing a directory. The files in this
    /// render will already have been filtered and sorted, but any directories
    /// that we recurse into will have to have this applied.
    pub filter: &'a FileFilter,

    /// The minimum number of rows that there need to be before grid-details
    /// mode is activated.
    pub row_threshold: RowThreshold,

    /// Whether we are skipping Git-ignored files.
    pub git_ignoring: bool,

    pub git: Option<&'a GitCache>,

    pub console_width: usize,
}

impl<'a> Render<'a> {

    /// Create a temporary Details render that gets used for the columns of
    /// the grid-details render that’s being generated.
    ///
    /// This includes an empty files vector because the files get added to
    /// the table in *this* file, not in details: we only want to insert every
    /// *n* files into each column’s table, not all of them.
    fn details_for_column(&self) -> DetailsRender<'a> {
        DetailsRender {
            dir:           self.dir,
            files:         Vec::new(),
            theme:         self.theme,
            file_style:    self.file_style,
            opts:          self.details,
            recurse:       None,
            filter:        self.filter,
            git_ignoring:  self.git_ignoring,
            git:           self.git,
        }
    }

    /// Create a Details render for when this grid-details render doesn’t fit
    /// in the terminal (or something has gone wrong) and we have given up, or
    /// when the user asked for a grid-details view but the terminal width is
    /// not available, so we downgrade.
    pub fn give_up(self) -> DetailsRender<'a> {
        DetailsRender {
            dir:           self.dir,
            files:         self.files,
            theme:         self.theme,
            file_style:    self.file_style,
            opts:          self.details,
            recurse:       None,
            filter:        self.filter,
            git_ignoring:  self.git_ignoring,
            git:           self.git,
        }
    }

    // This doesn’t take an IgnoreCache even though the details one does
    // because grid-details has no tree view.

    pub fn render<W: Write>(mut self, w: &mut W) -> io::Result<()> {
        if let Some((grid, width)) = self.find_fitting_grid() {
            write!(w, "{}", grid.fit_into_columns(width))
        }
        else {
            self.give_up().render(w)
        }
    }

    pub fn find_fitting_grid(&mut self) -> Option<(grid::Grid, grid::Width)> {
        let options = self.details.table.as_ref().expect("Details table options not given!");

        let drender = self.details_for_column();

        let (first_table, _) = self.make_table(options, &drender);

        let rows = self.files.iter()
                       .map(|file| first_table.row_for_file(file, file_has_xattrs(file)))
                       .collect::<Vec<_>>();

        let file_names = self.files.iter()
                             .map(|file| self.file_style.for_file(file, self.theme).paint().promote())
                             .collect::<Vec<_>>();

        let mut last_working_grid = self.make_grid(1, options, &file_names, rows.clone(), &drender);

        if file_names.len() == 1 {
            return Some((last_working_grid, 1));
        }

        // If we can’t fit everything in a grid 100 columns wide, then
        // something has gone seriously awry
        for column_count in 2..100 {
            let grid = self.make_grid(column_count, options, &file_names, rows.clone(), &drender);

            let the_grid_fits = {
                let d = grid.fit_into_columns(column_count);
                d.width() <= self.console_width
            };

            if the_grid_fits {
                last_working_grid = grid;
            }

            if !the_grid_fits || column_count == file_names.len() {
                let last_column_count = if the_grid_fits { column_count } else { column_count - 1 };
                // If we’ve figured out how many columns can fit in the user’s terminal,
                // and it turns out there aren’t enough rows to make it worthwhile
                // (according to EXA_GRID_ROWS), then just resort to the lines view.
                if let RowThreshold::MinimumRows(thresh) = self.row_threshold {
                    if last_working_grid.fit_into_columns(last_column_count).row_count() < thresh {
                        return None;
                    }
                }

                return Some((last_working_grid, last_column_count));
            }
        }

        None
    }

    fn make_table(&mut self, options: &'a TableOptions, drender: &DetailsRender<'_>) -> (Table<'a>, Vec<DetailsRow>) {
        match (self.git, self.dir) {
            (Some(g), Some(d))  => if ! g.has_anything_for(&d.path) { self.git = None },
            (Some(g), None)     => if ! self.files.iter().any(|f| g.has_anything_for(&f.path)) { self.git = None },
            (None,    _)        => {/* Keep Git how it is */},
        }

        let mut table = Table::new(options, self.git, &self.theme);
        let mut rows = Vec::new();

        if self.details.header {
            let row = table.header_row();
            table.add_widths(&row);
            rows.push(drender.render_header(row));
        }

        (table, rows)
    }

    fn make_grid(&mut self, column_count: usize, options: &'a TableOptions, file_names: &[TextCell], rows: Vec<TableRow>, drender: &DetailsRender<'_>) -> grid::Grid {
        let mut tables = Vec::new();
        for _ in 0 .. column_count {
            tables.push(self.make_table(options, drender));
        }

        let mut num_cells = rows.len();
        if self.details.header {
            num_cells += column_count;
        }

        let original_height = divide_rounding_up(rows.len(), column_count);
        let height = divide_rounding_up(num_cells, column_count);

        for (i, (file_name, row)) in file_names.iter().zip(rows.into_iter()).enumerate() {
            let index = if self.grid.across {
                    i % column_count
                }
                else {
                    i / original_height
                };

            let (ref mut table, ref mut rows) = tables[index];
            table.add_widths(&row);
            let details_row = drender.render_file(row, file_name.clone(), TreeParams::new(TreeDepth::root(), false));
            rows.push(details_row);
        }

        let columns = tables
            .into_iter()
            .map(|(table, details_rows)| {
                drender.iterate_with_table(table, details_rows)
                       .collect::<Vec<_>>()
                })
            .collect::<Vec<_>>();

        let direction = if self.grid.across { grid::Direction::LeftToRight }
                                       else { grid::Direction::TopToBottom };

        let filling = grid::Filling::Spaces(4);
        let mut grid = grid::Grid::new(grid::GridOptions { direction, filling });

        if self.grid.across {
            for row in 0 .. height {
                for column in &columns {
                    if row < column.len() {
                        let cell = grid::Cell {
                            contents: ANSIStrings(&column[row].contents).to_string(),
                            width:    *column[row].width,
                        };

                        grid.add(cell);
                    }
                }
            }
        }
        else {
            for column in &columns {
                for cell in column.iter() {
                    let cell = grid::Cell {
                        contents: ANSIStrings(&cell.contents).to_string(),
                        width:    *cell.width,
                    };

                    grid.add(cell);
                }
            }
        }

        grid
    }
}

fn divide_rounding_up(a: usize, b: usize) -> usize {
    let mut result = a / b;

    if a % b != 0 {
        result += 1;
    }

    result
}

fn file_has_xattrs(file: &File<'_>) -> bool {
    match file.path.attributes() {
        Ok(attrs)  => ! attrs.is_empty(),
        Err(_)     => false,
    }
}
<|endoftext|>


<commit_before>extern crate x11;

use std::collections::HashMap;
use std::io::prelude::*;
use std::io::BufReader;
use std::io::Lines;
use std::fs::File;
use std::path::PathBuf;
use std::process::Command;
use std::ffi;
use std::env;
use x11::xlib;
use std::boxed::Box;

use super::layout;
use super::handler::{ KeyBind, Handler };
use super::handler::{ ExecHandler, LayoutHandler, WorkspaceHandler, WindowToWorkspaceHandler, WindowFocusHandler };

pub struct Config {
    mod_key: u32,
    pub bindsyms: HashMap<KeyBind, Box<Handler>>,
}

#[test]
fn test_map() {
    let mut bindsyms: HashMap<KeyBind, i32> = HashMap::new();
    let b = KeyBind {
        key: 0,
        mask: 0
    };
    bindsyms.insert(b, 1);

    let c = KeyBind {
        key: 0,
        mask: 0
    };
    assert!(bindsyms.contains_key(&c), true);
}

impl Config {
    pub fn load() -> Config {
        let mut config = Config::default();

        let home = match env::var_os("HOME") {
            Some(v) => v,
            None => {
                // can't find HOME, return default config
                return config;
            }
        };

        let mut pathbuf = PathBuf::from(home);
        pathbuf.push(".rustile");
        match File::open(pathbuf.as_path()) {
            Ok(f) => {
                let buf = BufReader::new(f);
                for line in buf.lines() {
                    match line {
                        Ok(s) => {
                            config.read_line(s);
                        }
                        Err(err) => {
                            // do nothing
                        }
                    }
                }
            }
            Err(err) => {
                // use default config
                println!("no config file");
            }
        }
        config
    }

    pub fn default() -> Config {
        let mut config = Config {
            mod_key: xlib::Mod4Mask,
            bindsyms: HashMap::new(),
        };
        // let dmenu = vec!["$mod+c", "exec", "dmenu_run"];
        // let split = vec!["$mod+b", "layout", "split"];
        // config.bind_sym(&dmenu);
        // config.bind_sym(&split);
        config
    }

    fn read_line(&mut self, line: String) {
        // # is comment
        if !line.starts_with("#") {
            let tokens: Vec<&str> = line.split(' ').collect();
            let (cmd, args) = tokens.split_at(1);
            match cmd[0] {
                "set" => {
                    if args.len() > 1 {
                        debug!("set var");
                        self.set_var(args[0], args[1]);
                    }
                }
                "exec" => {
                    let mut handler = ExecHandler::new(args);
                    handler.cmd.spawn();
                }
                "bind" => {
                    self.bind_sym(args);
                }
                _ => {
                    // not supported cmd, ignore
                }
            }
        }
    }

    fn bind_sym(&mut self, args: &[&str]) {
        let (keyseq, cmd) = args.split_at(1);
        let keys: Vec<&str> = keyseq[0].split("+").collect();

        let bind = KeyBind::build(self.mod_key, &keys);

        let (name, args) = cmd.split_at(1);
        match name[0] {
            "exec" => {
                println!("exec");
                let handler = ExecHandler::new(args);
                self.bindsyms.insert(bind, Box::new(handler));
            }
            "layout" => {
                println!("layout");
                let layout = args[0];
                match layout {
                    "split" => {
                        let handler = LayoutHandler::new(layout::Type::Tiling);
                        self.bindsyms.insert(bind, Box::new(handler));
                    }
                    _ => {}
                }
            }
            "workspace" => {
                println!("workspace");
                let c = args[0].chars().nth(0);
                match c {
                    Some(v) => {
                        let handler = WorkspaceHandler {
                            key: v,
                        };
                        self.bindsyms.insert(bind, Box::new(handler));
                    }
                    None => {}
                }
            }
            "window" => {
                let c = args[0].chars().nth(0);
                match c {
                    Some(v) => {
                        println!("window");
                        let handler = WindowToWorkspaceHandler {
                            key: v,
                        };
                        self.bindsyms.insert(bind, Box::new(handler));
                    }
                    None => {}
                }
            }
            "focus" => {
                let direction = match args[0] {
                    "left" => layout::Direction::Left,
                    "right" => layout::Direction::Right,
                    "up" => layout::Direction::Up,
                    "down" => layout::Direction::Down,
                    _ => layout::Direction::Right
                };
                let handler = WindowFocusHandler {
                    direction: direction
                };
                self.bindsyms.insert(bind, Box::new(handler));
            }
            "kill" => {
                let handler = WindowCloseHandler;
                self.bindsyms.insert(bind, Box::new(handler));
            }
            _ => {}
        };
    }

    fn set_var(&mut self, key: &str, val: &str) {
        match key {
            "$mod" => {
                self.mod_key = match val {
                    "Shift" => xlib::ShiftMask,
                    "Ctrl"  => xlib::ControlMask,
                    "Mod1"  => xlib::Mod1Mask,
                    "Mod2" => xlib::Mod2Mask,
                    "Mod3" => xlib::Mod3Mask,
                    "Mod4" => xlib::Mod4Mask,
                    "Mod5" => xlib::Mod5Mask,
                    _ => xlib::Mod4Mask
                };
            }
            _ => {}
        }
    }
}
<commit_msg>reorganize code<commit_after>extern crate x11;

use std::collections::HashMap;
use std::io::prelude::*;
use std::io::BufReader;
use std::io::Lines;
use std::fs::File;
use std::path::PathBuf;
use std::process::Command;
use std::ffi;
use std::env;
use x11::xlib;
use std::boxed::Box;

use super::layout;
use super::handler::{
    KeyBind,
    Handler,
    ExecHandler,
    LayoutHandler,
    WorkspaceHandler,
    WindowToWorkspaceHandler,
    WindowFocusHandler,
    WindowCloseHandler};

pub struct Config {
    mod_key: u32,
    pub bindsyms: HashMap<KeyBind, Box<Handler>>,
}

impl Config {
    pub fn load() -> Config {
        let mut config = Config::default();

        let home = match env::var_os("HOME") {
            Some(v) => v,
            None => {
                // can't find HOME, return default config
                return config;
            }
        };

        let mut pathbuf = PathBuf::from(home);
        pathbuf.push(".rustile");
        match File::open(pathbuf.as_path()) {
            Ok(f) => {
                let buf = BufReader::new(f);
                for line in buf.lines() {
                    match line {
                        Ok(s) => {
                            config.read_line(s);
                        }
                        Err(err) => {
                            // do nothing
                        }
                    }
                }
            }
            Err(err) => {
                // use default config
                println!("no config file");
            }
        }
        config
    }

    pub fn default() -> Config {
        let mut config = Config {
            mod_key: xlib::Mod4Mask,
            bindsyms: HashMap::new(),
        };
        // let dmenu = vec!["$mod+c", "exec", "dmenu_run"];
        // let split = vec!["$mod+b", "layout", "split"];
        // config.bind_sym(&dmenu);
        // config.bind_sym(&split);
        config
    }

    fn read_line(&mut self, line: String) {
        // # is comment
        if !line.starts_with("#") {
            let tokens: Vec<&str> = line.split(' ').collect();
            let (cmd, args) = tokens.split_at(1);
            match cmd[0] {
                "set" => {
                    if args.len() > 1 {
                        self.set_var(args[0], args[1]);
                    }
                }
                "exec" => {
                    let mut handler = ExecHandler::new(args);
                    handler.cmd.spawn();
                }
                "bind" => {
                    self.bind_sym(args);
                }
                _ => {
                    // not supported cmd, ignore
                }
            }
        }
    }

    fn bind_sym(&mut self, args: &[&str]) {
        let (keyseq, cmd) = args.split_at(1);
        let keys: Vec<&str> = keyseq[0].split("+").collect();

        let bind = KeyBind::build(self.mod_key, &keys);

        let (name, args) = cmd.split_at(1);
        match name[0] {
            "exec" => {
                println!("exec");
                let handler = ExecHandler::new(args);
                self.bindsyms.insert(bind, Box::new(handler));
            }
            "layout" => {
                println!("layout");
                let layout = args[0];
                match layout {
                    "split" => {
                        let handler = LayoutHandler::new(layout::Type::Tiling);
                        self.bindsyms.insert(bind, Box::new(handler));
                    }
                    _ => {}
                }
            }
            "workspace" => {
                println!("workspace");
                let c = args[0].chars().nth(0);
                match c {
                    Some(v) => {
                        let handler = WorkspaceHandler {
                            key: v,
                        };
                        self.bindsyms.insert(bind, Box::new(handler));
                    }
                    None => {}
                }
            }
            "window" => {
                let c = args[0].chars().nth(0);
                match c {
                    Some(v) => {
                        println!("window");
                        let handler = WindowToWorkspaceHandler {
                            key: v,
                        };
                        self.bindsyms.insert(bind, Box::new(handler));
                    }
                    None => {}
                }
            }
            "focus" => {
                let direction = match args[0] {
                    "left" => layout::Direction::Left,
                    "right" => layout::Direction::Right,
                    "up" => layout::Direction::Up,
                    "down" => layout::Direction::Down,
                    _ => layout::Direction::Right
                };
                let handler = WindowFocusHandler {
                    direction: direction
                };
                self.bindsyms.insert(bind, Box::new(handler));
            }
            "kill" => {
                let handler = WindowCloseHandler;
                self.bindsyms.insert(bind, Box::new(handler));
            }
            _ => {}
        };
    }

    fn set_var(&mut self, key: &str, val: &str) {
        match key {
            "$mod" => {
                self.mod_key = match val {
                    "Shift" => xlib::ShiftMask,
                    "Ctrl"  => xlib::ControlMask,
                    "Mod1"  => xlib::Mod1Mask,
                    "Mod2" => xlib::Mod2Mask,
                    "Mod3" => xlib::Mod3Mask,
                    "Mod4" => xlib::Mod4Mask,
                    "Mod5" => xlib::Mod5Mask,
                    _ => xlib::Mod4Mask
                };
            }
            _ => {}
        }
    }
}

#[test]
fn test_map() {
    let mut bindsyms: HashMap<KeyBind, i32> = HashMap::new();
    let b = KeyBind {
        key: 0,
        mask: 0
    };
    bindsyms.insert(b, 1);

    let c = KeyBind {
        key: 0,
        mask: 0
    };
    assert!(bindsyms.contains_key(&c), true);
}
<|endoftext|>


<commit_before>// Test for <https://github.com/rust-lang/rust/issues/66756>

// check-pass

#![feature(const_if_match)]

enum E {
    A,
    B,
    C
}

const fn f(e: E) {
    match e {
        E::A => {}
        E::B => {}
        E::C => {}
    }
}

const fn g(e: E) {
    match e {
        _ => {}
    }
}

fn main() {}
<commit_msg>Remove test for #66758<commit_after>// Test for <https://github.com/rust-lang/rust/issues/66756>

// check-pass

#![feature(const_if_match)]

enum E {
    A,
    B,
    C
}

const fn f(e: E) {
    match e {
        E::A => {}
        E::B => {}
        E::C => {}
    }
}

fn main() {}
<|endoftext|>


<commit_before>#![feature(proc_macro)]
#[macro_use] extern crate clap;
#[macro_use] extern crate serde_derive;
extern crate mio;
extern crate mio_uds;
extern crate nix;
extern crate libc;
extern crate time;
extern crate toml;
extern crate serde;
extern crate serde_json;
extern crate sozu_lib as sozu;

mod config;

use mio_uds::UnixStream;
use std::net::{UdpSocket,ToSocketAddrs};
use std::collections::HashMap;
use clap::{App,Arg,SubCommand};
use sozu::messages::Command;
use sozu::command::CommandChannel;

#[derive(Debug,Clone,PartialEq,Eq,Hash,Serialize,Deserialize)]
 pub enum ConfigMessageStatus {
   Ok,
   Processing,
   Error
 }

#[derive(Debug,Clone,PartialEq,Eq,Hash, Serialize)]
pub enum ConfigCommand {
  ProxyConfiguration(Command),
  SaveState(String),
  LoadState(String),
  DumpState,
}

//FIXME: maybe need a custom serialize here
#[derive(Debug,Clone,PartialEq,Eq,Hash,Serialize)]
pub struct ConfigMessage {
  pub id:       String,
  pub data:     ConfigCommand,
  pub listener: Option<String>,
}

#[derive(Debug,Clone,PartialEq,Eq,Hash,Serialize,Deserialize)]
pub struct ConfigMessageAnswer {
  pub id:      String,
  pub status:  ConfigMessageStatus,
  pub message: String
}

fn main() {
  let matches = App::new("sozuctl")
                        .version(crate_version!())
                        .about("hot reconfigurable proxy")
                        .arg(Arg::with_name("config")
                            .short("c")
                            .long("config")
                            .value_name("FILE")
                            .help("Sets a custom config file")
                            .takes_value(true)
                            .required(true))
                        .subcommand(SubCommand::with_name("shutdown")
                                    .about("shuts down the proxy")
                                    .arg(Arg::with_name("hard").long("hard")
                                         .help("shuts down the proxy without waiting for connections to finish")))
                        .subcommand(SubCommand::with_name("state")
                                    .about("state management")
                                    .subcommand(SubCommand::with_name("save")
                                                .arg(Arg::with_name("file")
                                                    .short("f")
                                                    .long("file")
                                                    .value_name("state file")
                                                    .help("Save state to that file")
                                                    .takes_value(true)
                                                    .required(true)))
                                    .subcommand(SubCommand::with_name("load")
                                                .arg(Arg::with_name("file")
                                                    .short("f")
                                                    .long("file")
                                                    .value_name("state file")
                                                    .help("Save state to that file")
                                                    .takes_value(true)))
                                    .subcommand(SubCommand::with_name("dump")))
                        .get_matches();

  if let Some(matches) = matches.subcommand_matches("worker") {
    let fd  = matches.value_of("fd").expect("needs a file descriptor")
      .parse::<i32>().expect("the file descriptor must be a number");
    let id  = matches.value_of("id").expect("needs a worker id");
    let tag = matches.value_of("tag").expect("needs a configuration tag");

    return;
  }

  let config_file = matches.value_of("config").expect("required config file");

  let config = config::Config::load_from_path(config_file).expect("could not parse configuration file");
  let stream = UnixStream::connect(config.command_socket).expect("could not connect to the command unix socket");
  let mut channel: CommandChannel<ConfigMessage,ConfigMessageAnswer> = CommandChannel::new(stream, 10000, 20000);
  channel.set_nonblocking(false);

  match matches.subcommand() {
    ("shutdown", Some(sub)) => {
      let hard_shutdown = sub.is_present("hard");
    },
    ("state", Some(sub))    => {
      match sub.subcommand() {
        ("save", Some(state_sub)) => {
          let file = state_sub.value_of("file").expect("missing target file");
        },
        ("load", Some(state_sub)) => {
          let file = state_sub.value_of("file").expect("missing target file");
        },
        ("dump", _) => {
        },
        _                   => println!("unknown state management command")
      }
    },
    _                => println!("unknown subcommand")
  }

}
<commit_msg>add an example of sending a message to the proxy<commit_after>#![feature(proc_macro)]
#[macro_use] extern crate clap;
#[macro_use] extern crate serde_derive;
extern crate mio;
extern crate mio_uds;
extern crate nix;
extern crate libc;
extern crate time;
extern crate toml;
extern crate serde;
extern crate serde_json;
extern crate sozu_lib as sozu;

mod config;

use mio_uds::UnixStream;
use std::net::{UdpSocket,ToSocketAddrs};
use std::collections::HashMap;
use clap::{App,Arg,SubCommand};
use sozu::messages::Command;
use sozu::command::CommandChannel;

#[derive(Debug,Clone,PartialEq,Eq,Hash,Serialize,Deserialize)]
 pub enum ConfigMessageStatus {
   Ok,
   Processing,
   Error
 }

#[derive(Debug,Clone,PartialEq,Eq,Hash, Serialize)]
pub enum ConfigCommand {
  ProxyConfiguration(Command),
  SaveState(String),
  LoadState(String),
  DumpState,
}

//FIXME: maybe need a custom serialize here
#[derive(Debug,Clone,PartialEq,Eq,Hash,Serialize)]
pub struct ConfigMessage {
  pub id:       String,
  pub data:     ConfigCommand,
  pub listener: Option<String>,
}

#[derive(Debug,Clone,PartialEq,Eq,Hash,Serialize,Deserialize)]
pub struct ConfigMessageAnswer {
  pub id:      String,
  pub status:  ConfigMessageStatus,
  pub message: String
}

fn main() {
  let matches = App::new("sozuctl")
                        .version(crate_version!())
                        .about("hot reconfigurable proxy")
                        .arg(Arg::with_name("config")
                            .short("c")
                            .long("config")
                            .value_name("FILE")
                            .help("Sets a custom config file")
                            .takes_value(true)
                            .required(true))
                        .subcommand(SubCommand::with_name("shutdown")
                                    .about("shuts down the proxy")
                                    .arg(Arg::with_name("hard").long("hard")
                                         .help("shuts down the proxy without waiting for connections to finish")))
                        .subcommand(SubCommand::with_name("state")
                                    .about("state management")
                                    .subcommand(SubCommand::with_name("save")
                                                .arg(Arg::with_name("file")
                                                    .short("f")
                                                    .long("file")
                                                    .value_name("state file")
                                                    .help("Save state to that file")
                                                    .takes_value(true)
                                                    .required(true)))
                                    .subcommand(SubCommand::with_name("load")
                                                .arg(Arg::with_name("file")
                                                    .short("f")
                                                    .long("file")
                                                    .value_name("state file")
                                                    .help("Save state to that file")
                                                    .takes_value(true)))
                                    .subcommand(SubCommand::with_name("dump")))
                        .get_matches();

  if let Some(matches) = matches.subcommand_matches("worker") {
    let fd  = matches.value_of("fd").expect("needs a file descriptor")
      .parse::<i32>().expect("the file descriptor must be a number");
    let id  = matches.value_of("id").expect("needs a worker id");
    let tag = matches.value_of("tag").expect("needs a configuration tag");

    return;
  }

  let config_file = matches.value_of("config").expect("required config file");

  let config = config::Config::load_from_path(config_file).expect("could not parse configuration file");
  let stream = UnixStream::connect(config.command_socket).expect("could not connect to the command unix socket");
  let mut channel: CommandChannel<ConfigMessage,ConfigMessageAnswer> = CommandChannel::new(stream, 10000, 20000);
  channel.set_nonblocking(false);

  match matches.subcommand() {
    ("shutdown", Some(sub)) => {
      let hard_shutdown = sub.is_present("hard");
    },
    ("state", Some(sub))    => {
      match sub.subcommand() {
        ("save", Some(state_sub)) => {
          let file = state_sub.value_of("file").expect("missing target file");
        },
        ("load", Some(state_sub)) => {
          let file = state_sub.value_of("file").expect("missing target file");
        },
        ("dump", _) => {
          channel.write_message(&ConfigMessage {
            //FIXME: make a random id generator
            id:       "hello".to_string(),
            data:     ConfigCommand::DumpState,
            listener: None,
          });

          match channel.read_message() {
            None          => println!("the proxy didn't answer"),
            Some(message) => {
              //FIXME: verify that the message id is correct
              match message.status {
                ConfigMessageStatus::Processing => {
                  // do nothing here
                  // for other messages, we would loop over read_message
                  // until an error or ok message was sent
                },
                ConfigMessageStatus::Error => {
                  println!("could not dump proxy state: {}", message.message);
                },
                ConfigMessageStatus::Ok => {
                  println!("Proxy state:\n{}", message.message);
                }
              }
            }
          }
        },
        _                   => println!("unknown state management command")
      }
    },
    _                => println!("unknown subcommand")
  }

}
<|endoftext|>


<commit_before>#![crate_name = "rust-hl-lua"]
#![crate_type = "lib"]
#![comment = "Lua bindings for Rust"]
#![license = "MIT"]
#![allow(visible_private_types)]
#![feature(macro_rules)]
#![feature(unsafe_destructor)]

extern crate libc;
extern crate collections;

use std::kinds::marker::ContravariantLifetime;

pub use lua_tables::LuaTable;
pub use functions_read::LuaFunction;

pub mod any;
pub mod functions_read;
pub mod lua_tables;
pub mod userdata;

mod ffi;
mod functions_write;
mod rust_tables;
mod tuples;
mod values;

/// Main object of the library.
/// The lifetime parameter corresponds to the lifetime of the Lua object itself.
#[unstable]
pub struct Lua<'lua> {
    lua: *mut ffi::lua_State,
    marker: ContravariantLifetime<'lua>,
    must_be_closed: bool,
    inside_callback: bool           // if true, we are inside a callback
}

/// Trait for objects that have access to a Lua context.
/// The lifetime parameter is the lifetime of the Lua context.
pub trait HasLua<'lua> {
    fn use_lua(&mut self) -> *mut ffi::lua_State;
}

impl<'lua> HasLua<'lua> for Lua<'lua> {
    fn use_lua(&mut self) -> *mut ffi::lua_State {
        self.lua
    }
}

/// Object which allows access to a Lua variable.
struct LoadedVariable<'var, L> {
    lua: &'var mut L,
    size: uint,       // number of elements over "lua"
}

impl<'var, 'lua, L: HasLua<'lua>> HasLua<'lua> for LoadedVariable<'var, L> {
    fn use_lua(&mut self) -> *mut ffi::lua_State {
        self.lua.use_lua()
    }
}

/// Should be implemented by whatever type is pushable on the Lua stack.
#[unstable]
pub trait Push<L> {
    /// Pushes the value on the top of the stack.
    /// Must return the number of elements pushed.
    ///
    /// You can implement this for any type you want by redirecting to call to
    /// another implementation (for example `5.push_to_lua`) or by calling `userdata::push_userdata`
    fn push_to_lua(self, lua: &mut L) -> uint;
}

/// Should be implemented by types that can be read by consomming a LoadedVariable.
#[unstable]
pub trait ConsumeRead<'a, L> {
    /// Returns the LoadedVariable in case of failure.
    fn read_from_variable(var: LoadedVariable<'a, L>) -> Result<Self, LoadedVariable<'a, L>>;
}

/// Should be implemented by whatever type can be read by copy from the Lua stack.
#[unstable]
pub trait CopyRead<L> {
    /// Reads an object from the Lua stack.
    ///
    /// Similar to Push, you can implement this trait for your own types either by
    /// redirecting the calls to another implementation or by calling userdata::read_copy_userdata
    ///
    /// # Arguments
    ///  * `lua` - The Lua object to read from
    ///  * `index` - The index on the stack to read from
    fn read_from_lua(lua: &mut L, index: i32) -> Option<Self>;
}

/// Types that can be indices in Lua tables.
#[unstable]
pub trait Index<L>: Push<L> + CopyRead<L> {
}

/// Error that can happen when executing Lua code.
#[deriving(Show)]
#[unstable]
pub enum LuaError {
    /// There was a syntax error when parsing the Lua code.
    SyntaxError(String),

    /// There was an error during execution of the Lua code
    /// (for example not enough parameters for a function call).
    ExecutionError(String),

    /// The call to `execute` has requested the wrong type of data.
    WrongType
}

// this alloc function is required to create a lua state.
extern "C" fn alloc(_ud: *mut libc::c_void, ptr: *mut libc::c_void, _osize: libc::size_t, nsize: libc::size_t) -> *mut libc::c_void {
    unsafe {
        if nsize == 0 {
            libc::free(ptr as *mut libc::c_void);
            std::ptr::mut_null()
        } else {
            libc::realloc(ptr, nsize)
        }
    }
}

// called whenever lua encounters an unexpected error.
extern "C" fn panic(lua: *mut ffi::lua_State) -> libc::c_int {
    let err = unsafe { ffi::lua_tostring(lua, -1) };
    fail!("PANIC: unprotected error in call to Lua API ({})\n", err);
}

impl<'lua> Lua<'lua> {
    /// Builds a new Lua context.
    ///
    /// # Failure
    /// The function fails if lua_newstate fails (which indicates lack of memory).
    #[stable]
    pub fn new() -> Lua {
        let lua = unsafe { ffi::lua_newstate(alloc, std::ptr::mut_null()) };
        if lua.is_null() {
            fail!("lua_newstate failed");
        }

        unsafe { ffi::lua_atpanic(lua, panic) };

        Lua {
            lua: lua,
            marker: ContravariantLifetime,
            must_be_closed: true,
            inside_callback: false
        }
    }

    /// Takes an existing lua_State and build a Lua object from it.
    ///
    /// # Arguments
    ///  * close_at_the_end: if true, lua_close will be called on the lua_State on the destructor
    #[unstable]
    pub unsafe fn from_existing_state<T>(lua: *mut T, close_at_the_end: bool) -> Lua {
        Lua {
            lua: std::mem::transmute(lua),
            marker: ContravariantLifetime,
            must_be_closed: close_at_the_end,
            inside_callback: false
        }
    }

    /// Opens all standard Lua libraries.
    /// This is done by calling `luaL_openlibs`.
    #[unstable]
    pub fn openlibs(&mut self) {
        unsafe { ffi::luaL_openlibs(self.lua) }
    }

    /// Executes some Lua code on the context.
    #[unstable]
    pub fn execute<'a, T: CopyRead<LoadedVariable<'a, Lua<'lua>>>>(&'a mut self, code: &str) -> Result<T, LuaError> {
        let mut f = try!(functions_read::LuaFunction::load(self, code));
        f.call()
    }

    /// Executes some Lua code on the context.
    #[unstable]
    pub fn execute_from_reader<'a, T: CopyRead<LoadedVariable<'a, Lua<'lua>>>, R: std::io::Reader + 'static>(&'a mut self, code: R) -> Result<T, LuaError> {
        let mut f = try!(functions_read::LuaFunction::load_from_reader(self, code));
        f.call()
    }

    /// Loads the value of a global variable.
    #[unstable]
    pub fn load<'a, I: Str, V: ConsumeRead<'a, Lua<'lua>>>(&'a mut self, index: I) -> Option<V> {
        unsafe { ffi::lua_getglobal(self.lua, index.as_slice().to_c_str().unwrap()); }
        ConsumeRead::read_from_variable(LoadedVariable { lua: self, size: 1 }).ok()
    }

    /// Reads the value of a global variable by copying it.
    #[unstable]
    pub fn get<I: Str, V: CopyRead<Lua<'lua>>>(&mut self, index: I) -> Option<V> {
        unsafe { ffi::lua_getglobal(self.lua, index.as_slice().to_c_str().unwrap()); }
        CopyRead::read_from_lua(self, -1)
    }

    /// Modifies the value of a global variable.
    #[unstable]
    pub fn set<I: Str, V: Push<Lua<'lua>>>(&mut self, index: I, value: V) {
        value.push_to_lua(self);
        unsafe { ffi::lua_setglobal(self.lua, index.as_slice().to_c_str().unwrap()); }
    }

    #[unstable]
    pub fn load_new_table<'var>(&'var mut self) -> LuaTable<'var, Lua<'lua>> {
        unsafe { ffi::lua_newtable(self.lua) };
        ConsumeRead::read_from_variable(LoadedVariable { lua: self, size: 1 }).ok().unwrap()
    }
}

#[unsafe_destructor]
impl<'lua> Drop for Lua<'lua> {
    fn drop(&mut self) {
        if self.must_be_closed {
            unsafe { ffi::lua_close(self.lua) }
        }
    }
}

// TODO: crashes the compiler
/*#[unsafe_destructor]
impl<'a, 'lua, L: HasLua<'lua>> Drop for LoadedVariable<'a, L> {
    fn drop(&mut self) {
        unsafe { ffi::lua_pop(self.use_lua(), self.size as libc::c_int) }
    }
}*/
<commit_msg>Update for Rust nightly<commit_after>#![crate_name = "rust-hl-lua"]
#![crate_type = "lib"]
#![comment = "Lua bindings for Rust"]
#![license = "MIT"]
#![allow(visible_private_types)]
#![feature(macro_rules)]
#![feature(unsafe_destructor)]

extern crate libc;
extern crate collections;

use std::kinds::marker::ContravariantLifetime;

pub use lua_tables::LuaTable;
pub use functions_read::LuaFunction;

pub mod any;
pub mod functions_read;
pub mod lua_tables;
pub mod userdata;

mod ffi;
mod functions_write;
mod rust_tables;
mod tuples;
mod values;

/// Main object of the library.
/// The lifetime parameter corresponds to the lifetime of the Lua object itself.
#[unstable]
pub struct Lua<'lua> {
    lua: *mut ffi::lua_State,
    marker: ContravariantLifetime<'lua>,
    must_be_closed: bool,
    inside_callback: bool           // if true, we are inside a callback
}

/// Trait for objects that have access to a Lua context.
/// The lifetime parameter is the lifetime of the Lua context.
pub trait HasLua<'lua> {
    fn use_lua(&mut self) -> *mut ffi::lua_State;
}

impl<'lua> HasLua<'lua> for Lua<'lua> {
    fn use_lua(&mut self) -> *mut ffi::lua_State {
        self.lua
    }
}

/// Object which allows access to a Lua variable.
struct LoadedVariable<'var, L> {
    lua: &'var mut L,
    size: uint,       // number of elements over "lua"
}

impl<'var, 'lua, L: HasLua<'lua>> HasLua<'lua> for LoadedVariable<'var, L> {
    fn use_lua(&mut self) -> *mut ffi::lua_State {
        self.lua.use_lua()
    }
}

/// Should be implemented by whatever type is pushable on the Lua stack.
#[unstable]
pub trait Push<L> {
    /// Pushes the value on the top of the stack.
    /// Must return the number of elements pushed.
    ///
    /// You can implement this for any type you want by redirecting to call to
    /// another implementation (for example `5.push_to_lua`) or by calling `userdata::push_userdata`
    fn push_to_lua(self, lua: &mut L) -> uint;
}

/// Should be implemented by types that can be read by consomming a LoadedVariable.
#[unstable]
pub trait ConsumeRead<'a, L> {
    /// Returns the LoadedVariable in case of failure.
    fn read_from_variable(var: LoadedVariable<'a, L>) -> Result<Self, LoadedVariable<'a, L>>;
}

/// Should be implemented by whatever type can be read by copy from the Lua stack.
#[unstable]
pub trait CopyRead<L> {
    /// Reads an object from the Lua stack.
    ///
    /// Similar to Push, you can implement this trait for your own types either by
    /// redirecting the calls to another implementation or by calling userdata::read_copy_userdata
    ///
    /// # Arguments
    ///  * `lua` - The Lua object to read from
    ///  * `index` - The index on the stack to read from
    fn read_from_lua(lua: &mut L, index: i32) -> Option<Self>;
}

/// Types that can be indices in Lua tables.
#[unstable]
pub trait Index<L>: Push<L> + CopyRead<L> {
}

/// Error that can happen when executing Lua code.
#[deriving(Show)]
#[unstable]
pub enum LuaError {
    /// There was a syntax error when parsing the Lua code.
    SyntaxError(String),

    /// There was an error during execution of the Lua code
    /// (for example not enough parameters for a function call).
    ExecutionError(String),

    /// The call to `execute` has requested the wrong type of data.
    WrongType
}

// this alloc function is required to create a lua state.
extern "C" fn alloc(_ud: *mut libc::c_void, ptr: *mut libc::c_void, _osize: libc::size_t, nsize: libc::size_t) -> *mut libc::c_void {
    unsafe {
        if nsize == 0 {
            libc::free(ptr as *mut libc::c_void);
            std::ptr::mut_null()
        } else {
            libc::realloc(ptr, nsize)
        }
    }
}

// called whenever lua encounters an unexpected error.
extern "C" fn panic(lua: *mut ffi::lua_State) -> libc::c_int {
    let err = unsafe { ffi::lua_tostring(lua, -1) };
    fail!("PANIC: unprotected error in call to Lua API ({})\n", err);
}

impl<'lua> Lua<'lua> {
    /// Builds a new Lua context.
    ///
    /// # Failure
    /// The function fails if lua_newstate fails (which indicates lack of memory).
    #[stable]
    pub fn new() -> Lua<'lua> {
        let lua = unsafe { ffi::lua_newstate(alloc, std::ptr::mut_null()) };
        if lua.is_null() {
            fail!("lua_newstate failed");
        }

        unsafe { ffi::lua_atpanic(lua, panic) };

        Lua {
            lua: lua,
            marker: ContravariantLifetime,
            must_be_closed: true,
            inside_callback: false
        }
    }

    /// Takes an existing lua_State and build a Lua object from it.
    ///
    /// # Arguments
    ///  * close_at_the_end: if true, lua_close will be called on the lua_State on the destructor
    #[unstable]
    pub unsafe fn from_existing_state<T>(lua: *mut T, close_at_the_end: bool) -> Lua<'lua> {
        Lua {
            lua: std::mem::transmute(lua),
            marker: ContravariantLifetime,
            must_be_closed: close_at_the_end,
            inside_callback: false
        }
    }

    /// Opens all standard Lua libraries.
    /// This is done by calling `luaL_openlibs`.
    #[unstable]
    pub fn openlibs(&mut self) {
        unsafe { ffi::luaL_openlibs(self.lua) }
    }

    /// Executes some Lua code on the context.
    #[unstable]
    pub fn execute<'a, T: CopyRead<LoadedVariable<'a, Lua<'lua>>>>(&'a mut self, code: &str) -> Result<T, LuaError> {
        let mut f = try!(functions_read::LuaFunction::load(self, code));
        f.call()
    }

    /// Executes some Lua code on the context.
    #[unstable]
    pub fn execute_from_reader<'a, T: CopyRead<LoadedVariable<'a, Lua<'lua>>>, R: std::io::Reader + 'static>(&'a mut self, code: R) -> Result<T, LuaError> {
        let mut f = try!(functions_read::LuaFunction::load_from_reader(self, code));
        f.call()
    }

    /// Loads the value of a global variable.
    #[unstable]
    pub fn load<'a, I: Str, V: ConsumeRead<'a, Lua<'lua>>>(&'a mut self, index: I) -> Option<V> {
        unsafe { ffi::lua_getglobal(self.lua, index.as_slice().to_c_str().unwrap()); }
        ConsumeRead::read_from_variable(LoadedVariable { lua: self, size: 1 }).ok()
    }

    /// Reads the value of a global variable by copying it.
    #[unstable]
    pub fn get<I: Str, V: CopyRead<Lua<'lua>>>(&mut self, index: I) -> Option<V> {
        unsafe { ffi::lua_getglobal(self.lua, index.as_slice().to_c_str().unwrap()); }
        CopyRead::read_from_lua(self, -1)
    }

    /// Modifies the value of a global variable.
    #[unstable]
    pub fn set<I: Str, V: Push<Lua<'lua>>>(&mut self, index: I, value: V) {
        value.push_to_lua(self);
        unsafe { ffi::lua_setglobal(self.lua, index.as_slice().to_c_str().unwrap()); }
    }

    #[unstable]
    pub fn load_new_table<'var>(&'var mut self) -> LuaTable<'var, Lua<'lua>> {
        unsafe { ffi::lua_newtable(self.lua) };
        ConsumeRead::read_from_variable(LoadedVariable { lua: self, size: 1 }).ok().unwrap()
    }
}

#[unsafe_destructor]
impl<'lua> Drop for Lua<'lua> {
    fn drop(&mut self) {
        if self.must_be_closed {
            unsafe { ffi::lua_close(self.lua) }
        }
    }
}

// TODO: crashes the compiler
/*#[unsafe_destructor]
impl<'a, 'lua, L: HasLua<'lua>> Drop for LoadedVariable<'a, L> {
    fn drop(&mut self) {
        unsafe { ffi::lua_pop(self.use_lua(), self.size as libc::c_int) }
    }
}*/
<|endoftext|>


<commit_before>extern crate sfml;
extern crate nalgebra as na;

use sfml::system::Vector2f;
use sfml::window::{ContextSettings, VideoMode, event, Close};
use sfml::graphics::{RenderWindow, Texture, Sprite, Color};

use na::{Vec2};

fn main() {
    let mut env = SFMLEnv::new(800, 600);

    while env.win.is_open() {
        for event in env.win.events() {
            match event {
                event::Closed => env.win.close(),
                _ => { }
            }
        }

        env.clear();

        env.win.display();
    }
}

struct SFMLEnv {
    win: RenderWindow,
    width: u32,
    height: u32,
    shipTexture: Texture
}

impl SFMLEnv {
    fn new(width: u32, height: u32) -> SFMLEnv {
        let mut window = RenderWindow::new(VideoMode::new_init(width, height, 32),
                                           "SFML Example",
                                           Close,
                                           &ContextSettings::default())
            .expect("Cannot create a new Render Window.");
        window.set_vertical_sync_enabled(true);
        let mut t = Texture::new_from_file("plane.png");
        t.set_smooth(true);
        SFMLEnv {
            win: window,
            width: width,
            height: height,
            shipTexture: t
        }
    }

    fn clear(&mut self) {
        self.win.clear(&Color::black());
    }
}

struct Boid<'a> {
    pos: Vec2<f32>,
    vel: Vec2<f32>,
    acc: Vec2<f32>,
    sprite: Sprite<'a>,
    maxSpeed: f32,
    maxSteer: f32
}

impl Boid {

    fn new(env: SFMLEnv) -> Boid<'a> {
        let mut s = Sprite::new_with_texture(env.shipTexture).expect("Cannot create ship sprite.");
        let rect = s.get_local_bounds();
        s.set_origin2f(rect.width / 2.0,
                       rect.height / 2.0);
        Boid {
            pos: Vec2::new(0, 0),
            vel: Vec2::new(0, 0),
            acc: Vec2::new(0, 0),
            sprite: s,
            maxSpeed: 5,
            maxSteer: 0.2
        }
    }

}
<commit_msg>fix lifetimes<commit_after>extern crate sfml;
extern crate nalgebra as na;

use sfml::system::Vector2f;
use sfml::window::{ContextSettings, VideoMode, event, Close};
use sfml::graphics::{RenderWindow, Texture, Sprite, Color};

use na::{Vec2};

fn main() {
    let mut env = SFMLEnv::new(800, 600);

    while env.win.is_open() {
        for event in env.win.events() {
            match event {
                event::Closed => env.win.close(),
                _ => { }
            }
        }

        env.clear();

        env.win.display();
    }
}

struct SFMLEnv {
    win: RenderWindow,
    width: u32,
    height: u32,
    shipTexture: Texture
}

impl SFMLEnv {
    fn new(width: u32, height: u32) -> SFMLEnv {
        let mut window = RenderWindow::new(VideoMode::new_init(width, height, 32),
                                           "SFML Example",
                                           Close,
                                           &ContextSettings::default())
            .expect("Cannot create a new Render Window.");
        window.set_vertical_sync_enabled(true);
        let mut t = Texture::new_from_file("plane.png")
            .expect("Cannot create Texture");
        t.set_smooth(true);
        SFMLEnv {
            win: window,
            width: width,
            height: height,
            shipTexture: t
        }
    }

    fn clear(&mut self) {
        self.win.clear(&Color::black());
    }
}

struct Boid<'a> {
    pos: Vec2<f32>,
    vel: Vec2<f32>,
    acc: Vec2<f32>,
    sprite: Sprite<'a>,
    maxSpeed: f32,
    maxSteer: f32
}

impl<'a> Boid<'a> {

    fn new(env: SFMLEnv) -> Boid<'a> {
        let mut s = Sprite::new_with_texture(env.shipTexture).expect("Cannot create ship sprite.");
        let rect = s.get_local_bounds();
        s.set_origin2f(rect.width / 2.0,
                       rect.height / 2.0);
        Boid {
            pos: Vec2::new(0.0, 0.0),
            vel: Vec2::new(0.0, 0.0),
            acc: Vec2::new(0.0, 0.0),
            sprite: s,
            maxSpeed: 5.0,
            maxSteer: 0.2
        }
    }

}
<|endoftext|>