<commit_before>extern crate orbtk;

use orbtk::{Button, Point, Rect, TextBox, Window};
use orbtk::callback::{Click, Enter};
use orbtk::place::Place;

#[derive(Debug, Clone)]
pub enum Token {
    Plus,
    Minus,
    Divide,
    Multiply,
    Exponent,
    OpenParen,
    CloseParen,
    Number(String),
}

impl Token {
    pub fn to_str(&self) -> &'static str {
        match self {
            &Token::Plus       => "Plus",
            &Token::Minus      => "Minus",
            &Token::Divide     => "Divide",
            &Token::Multiply   => "Multiply",
            &Token::Exponent   => "Exponent",
            &Token::OpenParen  => "OpenParen",
            &Token::CloseParen => "CloseParen",
            &Token::Number(_)  => "Number",
        }
    }

    pub fn to_string(&self) -> String {
        self.to_str().to_owned()
    }
}

#[derive(Debug,  Clone)]
pub enum ParseError {
    InvalidNumber(String),
    UnrecognizedToken(String),
    UnexpectedToken(String, &'static str),
    UnexpectedEndOfInput,
    OtherError(String),
}

#[derive(Clone,Debug)]
pub struct IntermediateResult {
    value: f64,
    tokens_read: usize,
}

impl IntermediateResult {
    fn new(value: f64, tokens_read: usize) -> Self {
        IntermediateResult {
            value: value,
            tokens_read: tokens_read,
        }
    }
}

pub trait OperatorFunctions {
    fn is_operator(self) -> bool;
    fn operator_type(self) -> Token;
}

impl OperatorFunctions for char {
    fn is_operator(self) -> bool {
        self == '+' ||
        self == '-' ||
        self == '*' ||
        self == '/' ||
        self == '^' ||
        self == '(' ||
        self == ')'
    }

    fn operator_type(self) -> Token {
        match self {
            '+' => Token::Plus,
            '-' => Token::Minus,
            '/' => Token::Divide,
            '*' => Token::Multiply,
            '^' => Token::Exponent,
            '(' => Token::OpenParen,
            ')' => Token::CloseParen,
            _   => panic!("Invalid operator")
        }
    }
}

pub fn tokenize(input: &str) -> Result<Vec<Token>, ParseError> {
    // CONSIDER: input.len() too generous?
    let mut tokens = Vec::with_capacity(input.len());

    // TODO: Not this. Modify to use iterator
    let chars: Vec<char> = input.chars().collect();

    let input_length = chars.len();
    let mut current_pos = 0;
    while current_pos < input_length {
        let c = chars[current_pos];
        if c.is_digit(10) {
            let token_string = consume_number(&chars[current_pos..]);
            current_pos += token_string.len();
            tokens.push(Token::Number(token_string));
        } else if c.is_operator() {
            tokens.push(c.operator_type());
            current_pos += 1;
        } else if c.is_whitespace() {
            current_pos += 1;
        } else {
            let token_string = consume_until_new_token(&chars[current_pos..]);
            return Err(ParseError::UnrecognizedToken(token_string));
        }
    }
    Ok(tokens)
}

fn consume_number(input: &[char]) -> String {
    // CONSIDER: input.len seems a bit generous
    let mut number = String::with_capacity(input.len());
    let mut has_decimal_point = false;
    for &c in input {
        if c == '.' {
            if has_decimal_point {
                break;
            } else {
                number.push(c);
                has_decimal_point = true;
            }
        } else if c.is_digit(10) {
            number.push(c);
        } else {
            break;
        }
    }
    number
}

fn consume_until_new_token(input: &[char]) -> String {
    input.iter()
         .take_while(|c| !(c.is_whitespace() || c.is_operator() || c.is_digit(10)))
         .map(|&c| c)
         .collect()
}

// Addition and subtraction
pub fn e_expr(token_list: &[Token]) -> Result<IntermediateResult, ParseError> {
    let mut t1 = try!(t_expr(token_list));
    let mut index = t1.tokens_read;

    while index < token_list.len() {
        match token_list[index] {
            Token::Plus => {
                let t2 = try!(t_expr(&token_list[index+1..]));
                t1.value += t2.value;
                t1.tokens_read += t2.tokens_read + 1;
            }
            Token::Minus => {
                let t2 = try!(t_expr(&token_list[index+1..]));
                t1.value -= t2.value;
                t1.tokens_read += t2.tokens_read + 1;
            }
            Token::Number(ref n) => return Err(ParseError::UnexpectedToken(n.clone(),"operator")),
            _ => break,
        };
        index = t1.tokens_read;
    }
    Ok(t1)
}

// Multiplication and division
pub fn t_expr(token_list: &[Token]) -> Result<IntermediateResult, ParseError> {
    let mut f1 = try!(f_expr(token_list));
    let mut index = f1.tokens_read;

    while index < token_list.len() {
        match token_list[index] {
            Token::Multiply => {
                let f2 = try!(f_expr(&token_list[index+1..]));
                f1.value *= f2.value;
                f1.tokens_read += f2.tokens_read + 1;
            }
            Token::Divide => {
                let f2 = try!(f_expr(&token_list[index+1..]));
                if f2.value == 0.0 {
                    return Err(ParseError::OtherError("Divide by zero error".to_owned()));
                } else {
                    f1.value /= f2.value;
                    f1.tokens_read += f2.tokens_read + 1;
                }
            }
            Token::Number(ref n) => return Err(ParseError::UnexpectedToken(n.clone(),"operator")),
            _ => break,
        }
        index = f1.tokens_read;
    }
    Ok(f1)
}

// Exponentiation
#[cfg(not(target_os = "redox"))]
pub fn f_expr(token_list: &[Token]) -> Result<IntermediateResult, ParseError> {
    let mut g1 = try!(g_expr(token_list));
    let mut index = g1.tokens_read;
    let token_len = token_list.len();
    while index < token_len {
        match token_list[index] {
            Token::Exponent => {
                let f = try!(f_expr(&token_list[index+1..]));
                g1.value = g1.value.powf(f.value);
                g1.tokens_read += f.tokens_read + 1;
            }
            Token::Number(ref n) => return Err(ParseError::UnexpectedToken(n.clone(),"operator")),
            _ => break,
        }
        index = g1.tokens_read;
    }
    Ok(g1)
}

#[cfg(target_os = "redox")]
pub fn f_expr(_token_list: &[Token]) -> Result<IntermediateResult, ParseError> {
    Err(ParseError::UnexpectedEndOfInput)
}

// Numbers and parenthesized expressions
pub fn g_expr(token_list: &[Token]) -> Result<IntermediateResult, ParseError> {
    if !token_list.is_empty() {
        match token_list[0] {
            Token::Number(ref n) => {
                n.parse::<f64>()
                 .map_err(|_| ParseError::InvalidNumber(n.clone()))
                 .and_then(|num| Ok(IntermediateResult::new(num, 1)))
            }
            Token::Minus => {
                if token_list.len() > 1 {
                    if let Token::Number(ref n) = token_list[1] {
                        n.parse::<f64>()
                         .map_err(|_| ParseError::InvalidNumber(n.clone()))
                         .and_then(|num| Ok(IntermediateResult::new(-1.0 * num, 2)))
                    } else {
                        Err(ParseError::UnexpectedToken(token_list[1].to_string(), "number"))
                    }
                } else {
                    Err(ParseError::UnexpectedEndOfInput)
                }
            }
            Token::OpenParen => {
                let expr = e_expr(&token_list[1..]);
                match expr {
                    Ok(ir) => {
                        let close_paren = ir.tokens_read + 1;
                        if close_paren < token_list.len() {
                            match token_list[close_paren] {
                                Token::CloseParen => Ok(IntermediateResult::new(ir.value, close_paren+1)),
                                _ => Err(ParseError::UnexpectedToken(token_list[close_paren].to_string(), ")")),
                            }
                        } else {
                            Err(ParseError::OtherError("no matching close parenthesis found.".to_owned()))
                        }
                    }
                    Err(e) => Err(e),
                }
            }
            _ => Err(ParseError::UnexpectedToken(token_list[0].to_string(), "number"))
        }
    } else {
        Err(ParseError::UnexpectedEndOfInput)
    }
}

pub fn parse(tokens: Vec<Token>) -> Result<String, ParseError> {
    e_expr(&tokens).map(|answer| answer.value.to_string())
}

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

    #[test]
    fn simple_addition() {
        assert_eq!(tokenize("12+3").and_then(parse).unwrap(), "15");
    }

    #[test]
    fn addition() {
        assert_eq!(tokenize("12+3+5").and_then(parse).unwrap(), "20");
    }

    #[test]
    fn simple_subtraction() {
        assert_eq!(tokenize("12-3").and_then(parse).unwrap(), "9");
    }

    #[test]
    fn subtraction() {
        assert_eq!(tokenize("12-3-4").and_then(parse).unwrap(), "5");
    }

    #[test]
    fn mixed_addition_and_subtraction() {
        assert_eq!(tokenize("12+3-4+8-2-3").and_then(parse).unwrap(), "14");
    }

    #[test]
    fn simple_parentheses() {
        assert_eq!(tokenize("((3))").and_then(parse).unwrap(), "3");
        assert_eq!(tokenize("(12+(2+3))").and_then(parse).unwrap(), "17");
        assert_eq!(tokenize("12+(2+3)").and_then(parse).unwrap(), "17");
    }

    #[test]
    fn parentheses() {
        assert_eq!(tokenize("12+(2+(3+5))+4+(((6)))").and_then(parse).unwrap(), "32");
    }

    #[test]
    fn multiplication() {
        assert_eq!(tokenize("3*3").and_then(parse).unwrap(), "9");
        assert_eq!(tokenize("3*5").and_then(parse).unwrap(), "15");
        assert_eq!(tokenize("0*5").and_then(parse).unwrap(), "0");
        assert_eq!(tokenize("5*4*3*2*1").and_then(parse).unwrap(), "120");
        assert_eq!(tokenize("(5*4)*3*(2*1)").and_then(parse).unwrap(), "120");
    }

    #[test]
    fn division() {
        assert_eq!(tokenize("12/4").and_then(parse).unwrap(), "3");
        assert_eq!(tokenize("12/3").and_then(parse).unwrap(), "4");
        assert_eq!(tokenize("5/2").and_then(parse).unwrap(), "2.5");
        assert_eq!(tokenize("120/5/4/3/2").and_then(parse).unwrap(), "1");
        assert_eq!(tokenize("(120/5)/4/(3/2)").and_then(parse).unwrap(), "4");
    }

    #[test]
    fn exponentiation() {
        assert_eq!(tokenize("3^2").and_then(parse).unwrap(), "9");
        assert_eq!(tokenize("2^3^2").and_then(parse).unwrap(), "512");
        assert_eq!(tokenize("2^(2+1)^2").and_then(parse).unwrap(), "512");
    }
}

fn eval(input: &str) -> String {
    match tokenize(input).and_then(parse) {
        Ok(s) => s,
        Err(e) => match e {
            ParseError::InvalidNumber(s) => ["Error: Invalid number: ", s.as_str() ].concat(),
            ParseError::UnrecognizedToken(s) => ["Error: Unrecognized token: ", s.as_str()].concat(),
            ParseError::UnexpectedToken(found, expected) => ["Error: Unexpected token: expected [", expected, "] but found '", found.as_str(), "'"].concat(),
            ParseError::UnexpectedEndOfInput => "Error: Unexpected end of input.".to_owned(),
            ParseError::OtherError(s) => s,
        }
    }
}

fn main(){
    let mut window = Window::new(Rect::new(100, 100, 148, 200), "Calculator");

    {
        let text_box = TextBox::new()
            .position(0, 0)
            .size(300, 16)
            .on_enter(move |text_box: &TextBox| {
                let input = text_box.text.get();
                let result = eval(&input);
                println!("{}={}", input, result);
                text_box.text_i.set(result.len());
                text_box.text.set(result);
            })
            .place(&mut window);

        let mut col = 0;
        let mut row = 0;

        {
            let mut btn = |name| {
                let text_box_clone = text_box.clone();
                Button::new()
                    .position(col * 36 + 4, row * 36 + 20)
                    .size(32, 32)
                    .text(name)
                    .text_offset(12, 8)
                    .on_click(move |_button: &Button, _point: Point| {
                        let text_i = text_box_clone.text_i.get();

                        let text = text_box_clone.text.get();

                        let mut new_text = String::new();
                        new_text.push_str(&text[.. text_i]);
                        new_text.push_str(name);
                        new_text.push_str(&text[text_i ..]);

                        text_box_clone.text.set(new_text);

                        text_box_clone.text_i.set(text_i + name.len());
                    })
                    .place(&mut window);
                col += 1;
                if col >= 4 {
                    col = 0;
                    row += 1;
                }
            };

            btn("("); btn(")"); btn("^"); btn("/");
            btn("7"); btn("8"); btn("9"); btn("*");
            btn("4"); btn("5"); btn("6"); btn("-");
            btn("1"); btn("2"); btn("3"); btn("+");
            btn("0"); btn("0"); btn(".");
        }

        {
            let text_box_clone = text_box.clone();
            Button::new()
                .position(col * 36 + 4, row * 36 + 20)
                .size(32, 32)
                .text("=")
                .text_offset(12, 8)
                .on_click(move |_button: &Button, _point: Point| {
                    text_box_clone.emit_enter();
                })
                .place(&mut window);
        }
    }

    window.exec();
}
<commit_msg>Fix exponentiation on redox<commit_after>extern crate orbtk;

use orbtk::{Button, Point, Rect, TextBox, Window};
use orbtk::callback::{Click, Enter};
use orbtk::place::Place;

#[derive(Debug, Clone)]
pub enum Token {
    Plus,
    Minus,
    Divide,
    Multiply,
    Exponent,
    OpenParen,
    CloseParen,
    Number(String),
}

impl Token {
    pub fn to_str(&self) -> &'static str {
        match self {
            &Token::Plus       => "Plus",
            &Token::Minus      => "Minus",
            &Token::Divide     => "Divide",
            &Token::Multiply   => "Multiply",
            &Token::Exponent   => "Exponent",
            &Token::OpenParen  => "OpenParen",
            &Token::CloseParen => "CloseParen",
            &Token::Number(_)  => "Number",
        }
    }

    pub fn to_string(&self) -> String {
        self.to_str().to_owned()
    }
}

#[derive(Debug,  Clone)]
pub enum ParseError {
    InvalidNumber(String),
    UnrecognizedToken(String),
    UnexpectedToken(String, &'static str),
    UnexpectedEndOfInput,
    OtherError(String),
}

#[derive(Clone,Debug)]
pub struct IntermediateResult {
    value: f64,
    tokens_read: usize,
}

impl IntermediateResult {
    fn new(value: f64, tokens_read: usize) -> Self {
        IntermediateResult {
            value: value,
            tokens_read: tokens_read,
        }
    }
}

pub trait OperatorFunctions {
    fn is_operator(self) -> bool;
    fn operator_type(self) -> Token;
}

impl OperatorFunctions for char {
    fn is_operator(self) -> bool {
        self == '+' ||
        self == '-' ||
        self == '*' ||
        self == '/' ||
        self == '^' ||
        self == '(' ||
        self == ')'
    }

    fn operator_type(self) -> Token {
        match self {
            '+' => Token::Plus,
            '-' => Token::Minus,
            '/' => Token::Divide,
            '*' => Token::Multiply,
            '^' => Token::Exponent,
            '(' => Token::OpenParen,
            ')' => Token::CloseParen,
            _   => panic!("Invalid operator")
        }
    }
}

pub fn tokenize(input: &str) -> Result<Vec<Token>, ParseError> {
    // CONSIDER: input.len() too generous?
    let mut tokens = Vec::with_capacity(input.len());

    // TODO: Not this. Modify to use iterator
    let chars: Vec<char> = input.chars().collect();

    let input_length = chars.len();
    let mut current_pos = 0;
    while current_pos < input_length {
        let c = chars[current_pos];
        if c.is_digit(10) {
            let token_string = consume_number(&chars[current_pos..]);
            current_pos += token_string.len();
            tokens.push(Token::Number(token_string));
        } else if c.is_operator() {
            tokens.push(c.operator_type());
            current_pos += 1;
        } else if c.is_whitespace() {
            current_pos += 1;
        } else {
            let token_string = consume_until_new_token(&chars[current_pos..]);
            return Err(ParseError::UnrecognizedToken(token_string));
        }
    }
    Ok(tokens)
}

fn consume_number(input: &[char]) -> String {
    // CONSIDER: input.len seems a bit generous
    let mut number = String::with_capacity(input.len());
    let mut has_decimal_point = false;
    for &c in input {
        if c == '.' {
            if has_decimal_point {
                break;
            } else {
                number.push(c);
                has_decimal_point = true;
            }
        } else if c.is_digit(10) {
            number.push(c);
        } else {
            break;
        }
    }
    number
}

fn consume_until_new_token(input: &[char]) -> String {
    input.iter()
         .take_while(|c| !(c.is_whitespace() || c.is_operator() || c.is_digit(10)))
         .map(|&c| c)
         .collect()
}

// Addition and subtraction
pub fn e_expr(token_list: &[Token]) -> Result<IntermediateResult, ParseError> {
    let mut t1 = try!(t_expr(token_list));
    let mut index = t1.tokens_read;

    while index < token_list.len() {
        match token_list[index] {
            Token::Plus => {
                let t2 = try!(t_expr(&token_list[index+1..]));
                t1.value += t2.value;
                t1.tokens_read += t2.tokens_read + 1;
            }
            Token::Minus => {
                let t2 = try!(t_expr(&token_list[index+1..]));
                t1.value -= t2.value;
                t1.tokens_read += t2.tokens_read + 1;
            }
            Token::Number(ref n) => return Err(ParseError::UnexpectedToken(n.clone(),"operator")),
            _ => break,
        };
        index = t1.tokens_read;
    }
    Ok(t1)
}

// Multiplication and division
pub fn t_expr(token_list: &[Token]) -> Result<IntermediateResult, ParseError> {
    let mut f1 = try!(f_expr(token_list));
    let mut index = f1.tokens_read;

    while index < token_list.len() {
        match token_list[index] {
            Token::Multiply => {
                let f2 = try!(f_expr(&token_list[index+1..]));
                f1.value *= f2.value;
                f1.tokens_read += f2.tokens_read + 1;
            }
            Token::Divide => {
                let f2 = try!(f_expr(&token_list[index+1..]));
                if f2.value == 0.0 {
                    return Err(ParseError::OtherError("Divide by zero error".to_owned()));
                } else {
                    f1.value /= f2.value;
                    f1.tokens_read += f2.tokens_read + 1;
                }
            }
            Token::Number(ref n) => return Err(ParseError::UnexpectedToken(n.clone(),"operator")),
            _ => break,
        }
        index = f1.tokens_read;
    }
    Ok(f1)
}

// Exponentiation
#[cfg(not(target_os = "redox"))]
pub fn f_expr(token_list: &[Token]) -> Result<IntermediateResult, ParseError> {
    let mut g1 = try!(g_expr(token_list));
    let mut index = g1.tokens_read;
    let token_len = token_list.len();
    while index < token_len {
        match token_list[index] {
            Token::Exponent => {
                let f = try!(f_expr(&token_list[index+1..]));
                g1.value = g1.value.powf(f.value);
                g1.tokens_read += f.tokens_read + 1;
            }
            Token::Number(ref n) => return Err(ParseError::UnexpectedToken(n.clone(),"operator")),
            _ => break,
        }
        index = g1.tokens_read;
    }
    Ok(g1)
}

#[cfg(target_os = "redox")]
pub fn f_expr(token_list: &[Token]) -> Result<IntermediateResult, ParseError> {
    let mut g1 = try!(g_expr(token_list));
    let mut index = g1.tokens_read;
    let token_len = token_list.len();
    while index < token_len {
        match token_list[index] {
            Token::Exponent => {
                let f = try!(f_expr(&token_list[index+1..]));
                //TODO: g1.value = g1.value.powf(f.value);
                g1.tokens_read += f.tokens_read + 1;
            }
            Token::Number(ref n) => return Err(ParseError::UnexpectedToken(n.clone(),"operator")),
            _ => break,
        }
        index = g1.tokens_read;
    }
    Ok(g1)
}

// Numbers and parenthesized expressions
pub fn g_expr(token_list: &[Token]) -> Result<IntermediateResult, ParseError> {
    if !token_list.is_empty() {
        match token_list[0] {
            Token::Number(ref n) => {
                n.parse::<f64>()
                 .map_err(|_| ParseError::InvalidNumber(n.clone()))
                 .and_then(|num| Ok(IntermediateResult::new(num, 1)))
            }
            Token::Minus => {
                if token_list.len() > 1 {
                    if let Token::Number(ref n) = token_list[1] {
                        n.parse::<f64>()
                         .map_err(|_| ParseError::InvalidNumber(n.clone()))
                         .and_then(|num| Ok(IntermediateResult::new(-1.0 * num, 2)))
                    } else {
                        Err(ParseError::UnexpectedToken(token_list[1].to_string(), "number"))
                    }
                } else {
                    Err(ParseError::UnexpectedEndOfInput)
                }
            }
            Token::OpenParen => {
                let expr = e_expr(&token_list[1..]);
                match expr {
                    Ok(ir) => {
                        let close_paren = ir.tokens_read + 1;
                        if close_paren < token_list.len() {
                            match token_list[close_paren] {
                                Token::CloseParen => Ok(IntermediateResult::new(ir.value, close_paren+1)),
                                _ => Err(ParseError::UnexpectedToken(token_list[close_paren].to_string(), ")")),
                            }
                        } else {
                            Err(ParseError::OtherError("no matching close parenthesis found.".to_owned()))
                        }
                    }
                    Err(e) => Err(e),
                }
            }
            _ => Err(ParseError::UnexpectedToken(token_list[0].to_string(), "number"))
        }
    } else {
        Err(ParseError::UnexpectedEndOfInput)
    }
}

pub fn parse(tokens: Vec<Token>) -> Result<String, ParseError> {
    e_expr(&tokens).map(|answer| answer.value.to_string())
}

fn eval(input: &str) -> String {
    match tokenize(input).and_then(parse) {
        Ok(s) => s,
        Err(_e) => "Syntax Error".to_string()
    }
}

fn main(){
    let mut window = Window::new(Rect::new(100, 100, 148, 200), "Calculator");

    {
        let text_box = TextBox::new()
            .position(0, 0)
            .size(300, 16)
            .on_enter(move |text_box: &TextBox| {
                let input = text_box.text.get();
                let result = eval(&input);
                println!("{}={}", input, result);
                text_box.text_i.set(result.len());
                text_box.text.set(result);
            })
            .place(&mut window);

        let mut col = 0;
        let mut row = 0;

        {
            let mut btn = |name| {
                let text_box_clone = text_box.clone();
                Button::new()
                    .position(col * 36 + 4, row * 36 + 20)
                    .size(32, 32)
                    .text(name)
                    .text_offset(12, 8)
                    .on_click(move |_button: &Button, _point: Point| {
                        let text_i = text_box_clone.text_i.get();

                        let text = text_box_clone.text.get();

                        let mut new_text = String::new();
                        new_text.push_str(&text[.. text_i]);
                        new_text.push_str(name);
                        new_text.push_str(&text[text_i ..]);

                        text_box_clone.text.set(new_text);

                        text_box_clone.text_i.set(text_i + name.len());
                    })
                    .place(&mut window);
                col += 1;
                if col >= 4 {
                    col = 0;
                    row += 1;
                }
            };

            btn("("); btn(")"); btn("^"); btn("/");
            btn("7"); btn("8"); btn("9"); btn("*");
            btn("4"); btn("5"); btn("6"); btn("-");
            btn("1"); btn("2"); btn("3"); btn("+");
            btn("0"); btn("0"); btn(".");
        }

        {
            let text_box_clone = text_box.clone();
            Button::new()
                .position(col * 36 + 4, row * 36 + 20)
                .size(32, 32)
                .text("=")
                .text_offset(12, 8)
                .on_click(move |_button: &Button, _point: Point| {
                    text_box_clone.emit_enter();
                })
                .place(&mut window);
        }
    }

    window.exec();
}
<|endoftext|>


<commit_before>// See LICENSE file for copyright and license details.

use std;
use gl;
use gl::types::{GLint, GLchar, GLuint, GLenum};
use cgmath::matrix::{Matrix, Mat4};
use core::types::MInt;
use core::misc::read_file;
use visualizer::types::{MatId, MFloat};

pub struct Shader {
    priv id: GLuint,
}

impl Shader {
    pub fn new(vs: &str, fs: &str) -> Shader {
        compile_program(
            read_file(&Path::new(vs)),
            read_file(&Path::new(fs)),
        )
    }

    pub fn activate(&self) {
        gl::UseProgram(self.id);
    }

    pub fn enable_attr(&self, name: &str, components_count: MInt) {
        let mut attr_id = 0;
        unsafe {
            name.with_c_str(|name| {
                attr_id = gl::GetAttribLocation(self.id, name);
            });
        }
        gl::EnableVertexAttribArray(attr_id as GLuint);
        let normalized = gl::FALSE;
        let stride = 0;
        unsafe {
            gl::VertexAttribPointer(
                attr_id as GLuint,
                components_count,
                gl::FLOAT,
                normalized,
                stride,
                std::ptr::null(),
            );
        }
    }

    pub fn uniform_mat4f(&self, mat_id: MatId, mat: &Mat4<MFloat>) {
        unsafe {
            let MatId(id) = mat_id;
            gl::UniformMatrix4fv(id as MInt, 1, gl::FALSE, mat.cr(0, 0));
        }
    }

    pub fn get_uniform(&self, name: &str) -> GLuint {
        unsafe {
            name.with_c_str(|name| {
                gl::GetUniformLocation(self.id, name) as GLuint
            })
        }
    }
}

impl Drop for Shader {
    fn drop(&mut self) {
        gl::DeleteProgram(self.id);
    }
}

fn compile_shader(src: &str, shader_type: GLenum) -> GLuint {
    let shader = gl::CreateShader(shader_type);
    unsafe {
        src.with_c_str(|src| {
            gl::ShaderSource(shader, 1, &src, std::ptr::null());
        });
        gl::CompileShader(shader);
        let mut status = gl::FALSE as GLint;
        gl::GetShaderiv(shader, gl::COMPILE_STATUS, &mut status);
        if status != (gl::TRUE as GLint) {
            let mut len = 0;
            gl::GetShaderiv(shader, gl::INFO_LOG_LENGTH, &mut len);
            // subtract 1 to skip the trailing null character
            let mut buf = std::vec::from_elem(len as uint - 1, 0u8);
            gl::GetShaderInfoLog(shader, len, std::ptr::mut_null(),
                buf.as_mut_ptr() as *mut GLchar
            );
            fail!("compile_shader(): " + std::str::raw::from_utf8(buf));
        }
    }
    shader
}

fn link_program(vertex_shader: GLuint, fragment_shader: GLuint) -> GLuint {
    let program = gl::CreateProgram();
    gl::AttachShader(program, vertex_shader);
    gl::AttachShader(program, fragment_shader);
    gl::LinkProgram(program);
    unsafe {
        let mut status = gl::FALSE as GLint;
        gl::GetProgramiv(program, gl::LINK_STATUS, &mut status);
        if status != (gl::TRUE as GLint) {
            let mut len = 0;
            gl::GetProgramiv(program, gl::INFO_LOG_LENGTH, &mut len);
            // subtract 1 to skip the trailing null character
            let mut buf = std::vec::from_elem(len as uint - 1, 0u8);
            gl::GetProgramInfoLog(program, len, std::ptr::mut_null(),
                buf.as_mut_ptr() as *mut GLchar
            );
            fail!("link_program(): " + std::str::raw::from_utf8(buf));
        }
    }
    program
}

fn compile_program(vertex_shader_src: &str, frag_shader_src: &str) -> Shader {
    let vertex_shader = compile_shader(
        vertex_shader_src, gl::VERTEX_SHADER);
    let fragment_shader = compile_shader(
        frag_shader_src, gl::FRAGMENT_SHADER);
    let program = link_program(vertex_shader, fragment_shader);
    // mark shaders for deletion after program deletion
    gl::DeleteShader(fragment_shader);
    gl::DeleteShader(vertex_shader);
    Shader{id: program}
}

// vim: set tabstop=4 shiftwidth=4 softtabstop=4 expandtab:
<commit_msg>shader.rs: Fixed ~[] warning<commit_after>// See LICENSE file for copyright and license details.

use std;
use std::vec_ng::Vec;
use gl;
use gl::types::{GLint, GLchar, GLuint, GLenum};
use cgmath::matrix::{Matrix, Mat4};
use core::types::MInt;
use core::misc::read_file;
use visualizer::types::{MatId, MFloat};

pub struct Shader {
    priv id: GLuint,
}

impl Shader {
    pub fn new(vs: &str, fs: &str) -> Shader {
        compile_program(
            read_file(&Path::new(vs)),
            read_file(&Path::new(fs)),
        )
    }

    pub fn activate(&self) {
        gl::UseProgram(self.id);
    }

    pub fn enable_attr(&self, name: &str, components_count: MInt) {
        let mut attr_id = 0;
        unsafe {
            name.with_c_str(|name| {
                attr_id = gl::GetAttribLocation(self.id, name);
            });
        }
        gl::EnableVertexAttribArray(attr_id as GLuint);
        let normalized = gl::FALSE;
        let stride = 0;
        unsafe {
            gl::VertexAttribPointer(
                attr_id as GLuint,
                components_count,
                gl::FLOAT,
                normalized,
                stride,
                std::ptr::null(),
            );
        }
    }

    pub fn uniform_mat4f(&self, mat_id: MatId, mat: &Mat4<MFloat>) {
        unsafe {
            let MatId(id) = mat_id;
            gl::UniformMatrix4fv(id as MInt, 1, gl::FALSE, mat.cr(0, 0));
        }
    }

    pub fn get_uniform(&self, name: &str) -> GLuint {
        unsafe {
            name.with_c_str(|name| {
                gl::GetUniformLocation(self.id, name) as GLuint
            })
        }
    }
}

impl Drop for Shader {
    fn drop(&mut self) {
        gl::DeleteProgram(self.id);
    }
}

fn compile_shader(src: &str, shader_type: GLenum) -> GLuint {
    let shader = gl::CreateShader(shader_type);
    unsafe {
        src.with_c_str(|src| {
            gl::ShaderSource(shader, 1, &src, std::ptr::null());
        });
        gl::CompileShader(shader);
        let mut status = gl::FALSE as GLint;
        gl::GetShaderiv(shader, gl::COMPILE_STATUS, &mut status);
        if status != (gl::TRUE as GLint) {
            let mut len = 0;
            gl::GetShaderiv(shader, gl::INFO_LOG_LENGTH, &mut len);
            // subtract 1 to skip the trailing null character
            let mut buf = Vec::from_elem(len as uint - 1, 0u8);
            gl::GetShaderInfoLog(shader, len, std::ptr::mut_null(),
                buf.as_mut_ptr() as *mut GLchar
            );
            fail!("compile_shader(): " + std::str::raw::from_utf8(buf.as_slice()));
        }
    }
    shader
}

fn link_program(vertex_shader: GLuint, fragment_shader: GLuint) -> GLuint {
    let program = gl::CreateProgram();
    gl::AttachShader(program, vertex_shader);
    gl::AttachShader(program, fragment_shader);
    gl::LinkProgram(program);
    unsafe {
        let mut status = gl::FALSE as GLint;
        gl::GetProgramiv(program, gl::LINK_STATUS, &mut status);
        if status != (gl::TRUE as GLint) {
            let mut len = 0;
            gl::GetProgramiv(program, gl::INFO_LOG_LENGTH, &mut len);
            // subtract 1 to skip the trailing null character
            let mut buf = Vec::from_elem(len as uint - 1, 0u8);
            gl::GetProgramInfoLog(program, len, std::ptr::mut_null(),
                buf.as_mut_ptr() as *mut GLchar
            );
            fail!("link_program(): " + std::str::raw::from_utf8(buf.as_slice()));
        }
    }
    program
}

fn compile_program(vertex_shader_src: &str, frag_shader_src: &str) -> Shader {
    let vertex_shader = compile_shader(
        vertex_shader_src, gl::VERTEX_SHADER);
    let fragment_shader = compile_shader(
        frag_shader_src, gl::FRAGMENT_SHADER);
    let program = link_program(vertex_shader, fragment_shader);
    // mark shaders for deletion after program deletion
    gl::DeleteShader(fragment_shader);
    gl::DeleteShader(vertex_shader);
    Shader{id: program}
}

// vim: set tabstop=4 shiftwidth=4 softtabstop=4 expandtab:
<|endoftext|>


<commit_before>use structopt::StructOpt;

use codespan::Files;
use codespan_reporting::termcolor::StandardStream;
use codespan_reporting::{emit, ColorArg, Diagnostic, Label};

#[derive(Debug, StructOpt)]
#[structopt(name = "emit")]
pub struct Opts {
    /// Configure coloring of output
    #[structopt(
        long = "color",
        parse(try_from_str),
        default_value = "auto",
        raw(possible_values = "ColorArg::VARIANTS", case_insensitive = "true")
    )]
    pub color: ColorArg,
}

fn main() {
    let opts = Opts::from_args();
    let mut files = Files::new();

    let nat_file_id = files.add(
        "Data/Nat.fun",
        unindent::unindent(
            "
                module Data.Nat where

                data Nat : Type where
                    zero : Nat
                    succ : Nat → Nat

                {-# BUILTIN NATRAL Nat #-}

                infixl 6 _+_ _-_

                _+_ : Nat → Nat → Nat
                zero    + n₂ = n₂
                succ n₁ + n₂ = succ (n₁ + n₂)

                _-_ : Nat → Nat → Nat
                n₁      - zero    = n₁
                zero    - succ n₂ = zero
                succ n₁ - succ n₂ = n₁ - n₂
            ",
        ),
    );

    let test_file_id = files.add(
        "Test.fun",
        unindent::unindent(
            r#"
                module Test where

                _ : Nat
                _ = 123 + "hello"

                id : {A : Type} → A → A
                id a = a
            "#,
        ),
    );

    let diagnostics = [
        Diagnostic::new_error(
            "unknown builtin: `NATRAL`",
            Label::new(nat_file_id, 96..102, "unknown builtin"),
        )
        .with_secondary_labels(vec![Label::new(
            nat_file_id,
            96..102,
            "perhaps you meant: `NATURAL`",
        )]),

        Diagnostic::new_warning(
            "unused parameter pattern: `n₂`",
            Label::new(nat_file_id, 285..289, ""),
        )
        .with_secondary_labels(vec![Label::new(
            nat_file_id,
            285..289,
            "consider using a wildcard pattern: `_`",
        )]),

        Diagnostic::new_error(
            "unexpected type in application of `_+_`",
            Label::new(test_file_id, 37..44, "expected `Nat` but found `String`"),
        )
        .with_code("E0001")
        .with_secondary_labels(vec![Label::new(
            nat_file_id,
            130..155,
            "based on the definition of `_+_`",
        )]),

        Diagnostic::new_warning(
            "`id` is never used",
            Label::new(test_file_id, 46..82, "definition is never used"),
        ),
    ];

    let writer = StandardStream::stderr(opts.color.into());
    let config = codespan_reporting::Config::default();
    for diagnostic in &diagnostics {
        emit(&mut writer.lock(), &config, &files, &diagnostic).unwrap();
    }
}
<commit_msg>Add case example to emitter<commit_after>use structopt::StructOpt;

use codespan::Files;
use codespan_reporting::termcolor::StandardStream;
use codespan_reporting::{emit, ColorArg, Diagnostic, Label};

#[derive(Debug, StructOpt)]
#[structopt(name = "emit")]
pub struct Opts {
    /// Configure coloring of output
    #[structopt(
        long = "color",
        parse(try_from_str),
        default_value = "auto",
        raw(possible_values = "ColorArg::VARIANTS", case_insensitive = "true")
    )]
    pub color: ColorArg,
}

fn main() {
    let opts = Opts::from_args();
    let mut files = Files::new();

    let nat_file_id = files.add(
        "Data/Nat.fun",
        unindent::unindent(
            "
                module Data.Nat where

                data Nat : Type where
                    zero : Nat
                    succ : Nat → Nat

                {-# BUILTIN NATRAL Nat #-}

                infixl 6 _+_ _-_

                _+_ : Nat → Nat → Nat
                zero    + n₂ = n₂
                succ n₁ + n₂ = succ (n₁ + n₂)

                _-_ : Nat → Nat → Nat
                n₁      - zero    = n₁
                zero    - succ n₂ = zero
                succ n₁ - succ n₂ = n₁ - n₂
            ",
        ),
    );

    let test_file_id = files.add(
        "Test.fun",
        unindent::unindent(
            r#"
                module Test where

                _ : Nat
                _ = 123 + "hello"
            "#,
        ),
    );

    let fizz_buzz_file_id = files.add(
        "FizzBuzz.fun",
        unindent::unindent(
            r#"
                module FizzBuzz where

                fizz₁ : Nat → String
                fizz₁ num = case (mod num 5) (mod num 3) of
                    0 0 => "FizzBuzz"
                    0 _ => "Fizz"
                    _ 0 => "Buzz"
                    _ _ => num

                fizz₂ num =
                    case (mod num 5) (mod num 3) of
                        0 0 => "FizzBuzz"
                        0 _ => "Fizz"
                        _ 0 => "Buzz"
                        _ _ => num
            "#,
        ),
    );

    let diagnostics = [
        // Unknown builtin error
        Diagnostic::new_error(
            "unknown builtin: `NATRAL`",
            Label::new(nat_file_id, 96..102, "unknown builtin"),
        )
        // .with_notes(vec!["there is a builtin with a similar name: `NATURAL`".to_owned()])
        .with_secondary_labels(vec![Label::new(
            nat_file_id,
            96..102,
            "perhaps you meant: `NATURAL`",
        )]),
        // Unused parameter warning
        Diagnostic::new_warning(
            "unused parameter pattern: `n₂`",
            Label::new(nat_file_id, 285..289, "unused parameter"),
        ),
        // .with_notes(vec!["consider using a wildcard pattern: `_`".to_owned()])
        // Unexpected type error
        Diagnostic::new_error(
            "unexpected type in application of `_+_`",
            Label::new(test_file_id, 37..44, "expected `Nat`, found `String`"),
        )
        .with_code("E0001")
        .with_secondary_labels(vec![Label::new(
            nat_file_id,
            130..155,
            "based on the definition of `_+_`",
        )]),
        // Incompatible match clause error
        Diagnostic::new_error(
            "`case` clauses have incompatible types",
            Label::new(
                fizz_buzz_file_id,
                163..166,
                "expected `String`, found `Nat`",
            ),
        )
        .with_code("E0308")
        // .with_notes(vec![unindent::unindent(
        //     "
        //         expected type `String`
        //            found type `Nat`
        //     ",
        // )])
        .with_secondary_labels(vec![
            Label::new(
                fizz_buzz_file_id,
                62..166,
                "`case` clauses have incompatible types",
            ),
            Label::new(
                fizz_buzz_file_id,
                41..47,
                "expected type `String` found here",
            ),
        ]),
        // Incompatible match clause error
        Diagnostic::new_error(
            "`case` clauses have incompatible types",
            Label::new(
                fizz_buzz_file_id,
                303..306,
                "expected `String`, found `Nat`",
            ),
        )
        .with_code("E0308")
        // .with_notes(vec![unindent::unindent(
        //     "
        //         expected type `String`
        //            found type `Nat`
        //     ",
        // )])
        .with_secondary_labels(vec![
            Label::new(
                fizz_buzz_file_id,
                186..306,
                "`case` clauses have incompatible types",
            ),
            Label::new(
                fizz_buzz_file_id,
                233..243,
                "this is found to be of type `String`",
            ),
            Label::new(
                fizz_buzz_file_id,
                259..265,
                "this is found to be of type `String`",
            ),
            Label::new(
                fizz_buzz_file_id,
                281..287,
                "this is found to be of type `String`",
            ),
        ]),
    ];

    let writer = StandardStream::stderr(opts.color.into());
    let config = codespan_reporting::Config::default();
    for diagnostic in &diagnostics {
        emit(&mut writer.lock(), &config, &files, &diagnostic).unwrap();
    }
}
<|endoftext|>


<commit_before>// allow(const_err) to work around a bug in warnings
#[allow(const_err)]
static FOO: fn() = || { assert_ne!(42, 43) };
#[allow(const_err)]
static BAR: fn(i32, i32) = |a, b| { assert_ne!(a, b) };

// use to first make the closure FnOnce() before making it fn()
fn magic0<R, F: FnOnce() -> R>(f: F) -> F { f }
fn magic1<T, R, F: FnOnce(T) -> R>(f: F) -> F { f }

fn main() {
    FOO();
    BAR(44, 45);
    let bar: unsafe fn(i32, i32) = BAR;
    unsafe { bar(46, 47) };
    let boo: &dyn Fn(i32, i32) = &BAR;
    boo(48, 49);

    let f: fn() = ||{};
    f();
    let f = magic0(||{}) as fn();
    f();

    let g: fn(i32) = |i| assert_eq!(i, 2);
    g(2);
    let g = magic1(|i| assert_eq!(i, 2)) as fn(i32);
    g(2);

    // FIXME: This fails with "invalid use of NULL pointer"
    //let h: fn() -> ! = || std::process::exit(0);
    //h();
    // FIXME: This does not even compile?!? <https://github.com/rust-lang/rust/issues/66738>
    //let h = magic0(|| std::process::exit(0)) as fn() -> !;
    //h();
    // Once these tests pass, they should be in separate files as they terminate the process.
}
<commit_msg>and another reference<commit_after>// allow(const_err) to work around a bug in warnings
#[allow(const_err)]
static FOO: fn() = || { assert_ne!(42, 43) };
#[allow(const_err)]
static BAR: fn(i32, i32) = |a, b| { assert_ne!(a, b) };

// use to first make the closure FnOnce() before making it fn()
fn magic0<R, F: FnOnce() -> R>(f: F) -> F { f }
fn magic1<T, R, F: FnOnce(T) -> R>(f: F) -> F { f }

fn main() {
    FOO();
    BAR(44, 45);
    let bar: unsafe fn(i32, i32) = BAR;
    unsafe { bar(46, 47) };
    let boo: &dyn Fn(i32, i32) = &BAR;
    boo(48, 49);

    let f: fn() = ||{};
    f();
    let f = magic0(||{}) as fn();
    f();

    let g: fn(i32) = |i| assert_eq!(i, 2);
    g(2);
    let g = magic1(|i| assert_eq!(i, 2)) as fn(i32);
    g(2);

    // FIXME: This fails with "invalid use of NULL pointer" <https://github.com/rust-lang/miri/issues/1075>
    //let h: fn() -> ! = || std::process::exit(0);
    //h();
    // FIXME: This does not even compile?!? <https://github.com/rust-lang/rust/issues/66738>
    //let h = magic0(|| std::process::exit(0)) as fn() -> !;
    //h();
    // Once these tests pass, they should be in separate files as they terminate the process.
}
<|endoftext|>


<commit_before>vec![
    [52.48803, 13.37053],
    [52.48941, 13.37067],
    [52.49048, 13.37073],
    [52.49072, 13.37078],
    [52.49267, 13.37093],
    [52.49158, 13.37628],
    [52.49153, 13.37638],
    [52.49148, 13.37659],
    [52.49148, 13.37659],
    [52.49169, 13.37758],
    [52.49224, 13.37934],
    [52.49335, 13.38273],
    [52.49352, 13.38349],
    [52.49516, 13.38402],
    [52.49849, 13.38521],
    [52.49755, 13.38921],
    [52.49746, 13.38986],
    [52.49739, 13.39063],
    [52.49737, 13.39139],
    [52.4974, 13.39203],
    [52.49742, 13.39278],
    [52.49761, 13.39486],
    [52.49781, 13.3956],
    [52.49793, 13.39586],
    [52.49812, 13.39593],
    [52.49837, 13.39594],
    [52.49877, 13.39584],
    [52.499, 13.39574],
    [52.50068, 13.39474],
    [52.50094, 13.39461],
    [52.50141, 13.39448],
    [52.50165, 13.39448],
    [52.50186, 13.39451],
    [52.5022, 13.39463],
    [52.50246, 13.39478],
    [52.50283, 13.39508],
    [52.50319, 13.39543],
    [52.50355, 13.39571],
    [52.50533, 13.39703],
    [52.5055, 13.39712],
    [52.50585, 13.39734],
    [52.50616, 13.39757],
    [52.50635, 13.39775],
    [52.50708, 13.39829],
    [52.5073, 13.39842],
    [52.50754, 13.39859],
    [52.50819, 13.3991],
    [52.5095, 13.40001],
    [52.50968, 13.40019],
    [52.51031, 13.40099],
    [52.51056, 13.40126],
    [52.51065, 13.40131],
    [52.51082, 13.40134],
    [52.51101, 13.40131],
    [52.51122, 13.40126],
    [52.51125, 13.40142],
    [52.51135, 13.40173],
    [52.51137, 13.4018],
    [52.5116, 13.40231],
    [52.51215, 13.40318],
    [52.51319, 13.40468],
    [52.51402, 13.40582],
    [52.51534, 13.40746],
    [52.51576, 13.40796],
    [52.51653, 13.40894],
    [52.5168, 13.40927],
    [52.51819, 13.41087],
    [52.51858, 13.41141],
    [52.51899, 13.41215],
    [52.51915, 13.41236],
    [52.51927, 13.41256],
    [52.52009, 13.41429],
    [52.52021, 13.4145],
    [52.52033, 13.41468],
    [52.52087, 13.41532],
    [52.52194, 13.41641],
    [52.52341, 13.41802],
    [52.52366, 13.41832],
    [52.52398, 13.4188],
    [52.52498, 13.41996],
    [52.52522, 13.42022],
    [52.52593, 13.41848]
];
<commit_msg>Fix test fixture<commit_after>vec![
    [52.48803, 13.37053],
    [52.48941, 13.37067],
    [52.49048, 13.37073],
    [52.49072, 13.37078],
    [52.49267, 13.37093],
    [52.49158, 13.37628],
    [52.49153, 13.37638],
    [52.49148, 13.37659],
    [52.49148, 13.37659],
    [52.49169, 13.37758],
    [52.49224, 13.37934],
    [52.49335, 13.38273],
    [52.49352, 13.38349],
    [52.49516, 13.38402],
    [52.49849, 13.38521],
    [52.49755, 13.38921],
    [52.49746, 13.38986],
    [52.49739, 13.39063],
    [52.49737, 13.39139],
    [52.4974, 13.39203],
    [52.49742, 13.39278],
    [52.49761, 13.39486],
    [52.49781, 13.3956],
    [52.49793, 13.39586],
    [52.49812, 13.39593],
    [52.49837, 13.39594],
    [52.49877, 13.39584],
    [52.499, 13.39574],
    [52.50068, 13.39474],
    [52.50094, 13.39461],
    [52.50141, 13.39448],
    [52.50165, 13.39448],
    [52.50186, 13.39451],
    [52.5022, 13.39463],
    [52.50246, 13.39478],
    [52.50283, 13.39508],
    [52.50319, 13.39543],
    [52.50355, 13.39571],
    [52.50533, 13.39703],
    [52.5055, 13.39712],
    [52.50585, 13.39734],
    [52.50616, 13.39757],
    [52.50635, 13.39775],
    [52.50708, 13.39829],
    [52.5073, 13.39842],
    [52.50754, 13.39859],
    [52.50819, 13.3991],
    [52.5095, 13.40001],
    [52.50968, 13.40019],
    [52.51031, 13.40099],
    [52.51056, 13.40126],
    [52.51065, 13.40131],
    [52.51082, 13.40134],
    [52.51101, 13.40131],
    [52.51122, 13.40126],
    [52.51125, 13.40142],
    [52.51135, 13.40173],
    [52.51137, 13.4018],
    [52.5116, 13.40231],
    [52.51215, 13.40318],
    [52.51319, 13.40468],
    [52.51402, 13.40582],
    [52.51534, 13.40746],
    [52.51576, 13.40796],
    [52.51653, 13.40894],
    [52.5168, 13.40927],
    [52.51819, 13.41087],
    [52.51858, 13.41141],
    [52.51899, 13.41215],
    [52.51915, 13.41236],
    [52.51927, 13.41256],
    [52.52009, 13.41429],
    [52.52021, 13.4145],
    [52.52033, 13.41468],
    [52.52087, 13.41532],
    [52.52194, 13.41641],
    [52.52341, 13.41802],
    [52.52366, 13.41832],
    [52.52398, 13.4188],
    [52.52498, 13.41996],
    [52.52522, 13.42022],
    [52.52593, 13.41848]
]
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use dom::baseaudiocontext::BaseAudioContext;
use dom::bindings::codegen::Bindings::AudioParamBinding;
use dom::bindings::codegen::Bindings::AudioParamBinding::{AudioParamMethods, AutomationRate};
use dom::bindings::num::Finite;
use dom::bindings::reflector::{Reflector, reflect_dom_object};
use dom::bindings::root::{Dom, DomRoot};
use dom::window::Window;
use dom_struct::dom_struct;
use servo_media::audio::graph::NodeId;
use servo_media::audio::node::AudioNodeMessage;
use servo_media::audio::param::{ParamRate, ParamType, RampKind, UserAutomationEvent};
use std::cell::Cell;

#[dom_struct]
pub struct AudioParam {
    reflector_: Reflector,
    context: Dom<BaseAudioContext>,
    #[ignore_malloc_size_of = "servo_media"]
    node: NodeId,
    #[ignore_malloc_size_of = "servo_media"]
    param: ParamType,
    automation_rate: Cell<AutomationRate>,
    default_value: f32,
    min_value: f32,
    max_value: f32,
}

impl AudioParam {
    pub fn new_inherited(
        context: &BaseAudioContext,
        node: NodeId,
        param: ParamType,
        automation_rate: AutomationRate,
        default_value: f32,
        min_value: f32,
        max_value: f32,
    ) -> AudioParam {
        AudioParam {
            reflector_: Reflector::new(),
            context: Dom::from_ref(context),
            node,
            param,
            automation_rate: Cell::new(automation_rate),
            default_value,
            min_value,
            max_value,
        }
    }

    #[allow(unrooted_must_root)]
    pub fn new(
        window: &Window,
        context: &BaseAudioContext,
        node: NodeId,
        param: ParamType,
        automation_rate: AutomationRate,
        default_value: f32,
        min_value: f32,
        max_value: f32,
    ) -> DomRoot<AudioParam> {
        let audio_param = AudioParam::new_inherited(
            context,
            node,
            param,
            automation_rate,
            default_value,
            min_value,
            max_value,
        );
        reflect_dom_object(Box::new(audio_param), window, AudioParamBinding::Wrap)
    }
}

impl AudioParamMethods for AudioParam {
    // https://webaudio.github.io/web-audio-api/#dom-audioparam-automationrate
    fn AutomationRate(&self) -> AutomationRate {
        self.automation_rate.get()
    }

    // https://webaudio.github.io/web-audio-api/#dom-audioparam-automationrate
    fn SetAutomationRate(&self, automation_rate: AutomationRate) {
        self.automation_rate.set(automation_rate);
        self.context.audio_context_impl().message_node(
            self.node,
            AudioNodeMessage::SetParamRate(self.param, automation_rate.into()),
        );
    }

    // https://webaudio.github.io/web-audio-api/#dom-audioparam-value
    fn Value(&self) -> Finite<f32> {
        // XXX
        Finite::wrap(0.)
    }

    // https://webaudio.github.io/web-audio-api/#dom-audioparam-value
    fn SetValue(&self, value: Finite<f32>) {
        self.context.audio_context_impl().message_node(
            self.node,
            AudioNodeMessage::SetParam(self.param, UserAutomationEvent::SetValue(*value)),
        );
    }

    // https://webaudio.github.io/web-audio-api/#dom-audioparam-defaultvalue
    fn DefaultValue(&self) -> Finite<f32> {
        Finite::wrap(self.default_value)
    }

    // https://webaudio.github.io/web-audio-api/#dom-audioparam-minvalue
    fn MinValue(&self) -> Finite<f32> {
        Finite::wrap(self.min_value)
    }

    // https://webaudio.github.io/web-audio-api/#dom-audioparam-maxvalue
    fn MaxValue(&self) -> Finite<f32> {
        Finite::wrap(self.max_value)
    }

    // https://webaudio.github.io/web-audio-api/#dom-audioparam-setvalueattime
    fn SetValueAtTime(&self, value: Finite<f32>, start_time: Finite<f64>) -> DomRoot<AudioParam> {
        self.context.audio_context_impl().message_node(
            self.node,
            AudioNodeMessage::SetParam(
                self.param,
                UserAutomationEvent::SetValueAtTime(*value, *start_time),
            ),
        );
        DomRoot::from_ref(self)
    }

    // https://webaudio.github.io/web-audio-api/#dom-audioparam-linearramptovalueattime
    fn LinearRampToValueAtTime(
        &self,
        value: Finite<f32>,
        end_time: Finite<f64>,
    ) -> DomRoot<AudioParam> {
        self.context.audio_context_impl().message_node(
            self.node,
            AudioNodeMessage::SetParam(
                self.param,
                UserAutomationEvent::RampToValueAtTime(RampKind::Linear, *value, *end_time),
            ),
        );
        DomRoot::from_ref(self)
    }

    // https://webaudio.github.io/web-audio-api/#dom-audioparam-exponentialramptovalueattime
    fn ExponentialRampToValueAtTime(
        &self,
        value: Finite<f32>,
        end_time: Finite<f64>,
    ) -> DomRoot<AudioParam> {
        self.context.audio_context_impl().message_node(
            self.node,
            AudioNodeMessage::SetParam(
                self.param,
                UserAutomationEvent::RampToValueAtTime(RampKind::Exponential, *value, *end_time),
            ),
        );
        DomRoot::from_ref(self)
    }

    // https://webaudio.github.io/web-audio-api/#dom-audioparam-settargetattime
    fn SetTargetAtTime(
        &self,
        target: Finite<f32>,
        start_time: Finite<f64>,
        time_constant: Finite<f32>,
    ) -> DomRoot<AudioParam> {
        self.context.audio_context_impl().message_node(
            self.node,
            AudioNodeMessage::SetParam(
                self.param,
                UserAutomationEvent::SetTargetAtTime(*target, *start_time, (*time_constant).into()),
            ),
        );
        DomRoot::from_ref(self)
    }

    // https://webaudio.github.io/web-audio-api/#dom-audioparam-cancelscheduledvalues
    fn CancelScheduledValues(&self, cancel_time: Finite<f64>) -> DomRoot<AudioParam> {
        self.context.audio_context_impl().message_node(
            self.node,
            AudioNodeMessage::SetParam(
                self.param,
                UserAutomationEvent::CancelScheduledValues(*cancel_time),
            ),
        );
        DomRoot::from_ref(self)
    }

    // https://webaudio.github.io/web-audio-api/#dom-audioparam-cancelandholdattime
    fn CancelAndHoldAtTime(&self, cancel_time: Finite<f64>) -> DomRoot<AudioParam> {
        self.context.audio_context_impl().message_node(
            self.node,
            AudioNodeMessage::SetParam(
                self.param,
                UserAutomationEvent::CancelAndHoldAtTime(*cancel_time),
            ),
        );
        DomRoot::from_ref(self)
    }
}

// https://webaudio.github.io/web-audio-api/#enumdef-automationrate
impl From<AutomationRate> for ParamRate {
    fn from(rate: AutomationRate) -> Self {
        match rate {
            AutomationRate::A_rate => ParamRate::ARate,
            AutomationRate::K_rate => ParamRate::KRate,
        }
    }
}
<commit_msg>AudioParam value getter<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use dom::baseaudiocontext::BaseAudioContext;
use dom::bindings::codegen::Bindings::AudioParamBinding;
use dom::bindings::codegen::Bindings::AudioParamBinding::{AudioParamMethods, AutomationRate};
use dom::bindings::num::Finite;
use dom::bindings::reflector::{Reflector, reflect_dom_object};
use dom::bindings::root::{Dom, DomRoot};
use dom::window::Window;
use dom_struct::dom_struct;
use servo_media::audio::graph::NodeId;
use servo_media::audio::node::AudioNodeMessage;
use servo_media::audio::param::{ParamRate, ParamType, RampKind, UserAutomationEvent};
use std::cell::Cell;
use std::sync::mpsc;

#[dom_struct]
pub struct AudioParam {
    reflector_: Reflector,
    context: Dom<BaseAudioContext>,
    #[ignore_malloc_size_of = "servo_media"]
    node: NodeId,
    #[ignore_malloc_size_of = "servo_media"]
    param: ParamType,
    automation_rate: Cell<AutomationRate>,
    default_value: f32,
    min_value: f32,
    max_value: f32,
}

impl AudioParam {
    pub fn new_inherited(
        context: &BaseAudioContext,
        node: NodeId,
        param: ParamType,
        automation_rate: AutomationRate,
        default_value: f32,
        min_value: f32,
        max_value: f32,
    ) -> AudioParam {
        AudioParam {
            reflector_: Reflector::new(),
            context: Dom::from_ref(context),
            node,
            param,
            automation_rate: Cell::new(automation_rate),
            default_value,
            min_value,
            max_value,
        }
    }

    #[allow(unrooted_must_root)]
    pub fn new(
        window: &Window,
        context: &BaseAudioContext,
        node: NodeId,
        param: ParamType,
        automation_rate: AutomationRate,
        default_value: f32,
        min_value: f32,
        max_value: f32,
    ) -> DomRoot<AudioParam> {
        let audio_param = AudioParam::new_inherited(
            context,
            node,
            param,
            automation_rate,
            default_value,
            min_value,
            max_value,
        );
        reflect_dom_object(Box::new(audio_param), window, AudioParamBinding::Wrap)
    }

    fn message_node(&self, message: AudioNodeMessage) {
        self.context.audio_context_impl().message_node(self.node, message);
    }
}

impl AudioParamMethods for AudioParam {
    // https://webaudio.github.io/web-audio-api/#dom-audioparam-automationrate
    fn AutomationRate(&self) -> AutomationRate {
        self.automation_rate.get()
    }

    // https://webaudio.github.io/web-audio-api/#dom-audioparam-automationrate
    fn SetAutomationRate(&self, automation_rate: AutomationRate) {
        self.automation_rate.set(automation_rate);
        self.message_node(
            AudioNodeMessage::SetParamRate(self.param, automation_rate.into())
        );
    }

    // https://webaudio.github.io/web-audio-api/#dom-audioparam-value
    fn Value(&self) -> Finite<f32> {
        let (tx, rx) = mpsc::channel();
        self.message_node(
            AudioNodeMessage::GetParamValue(self.param, tx)
        );
        Finite::wrap(rx.recv().unwrap())
    }

    // https://webaudio.github.io/web-audio-api/#dom-audioparam-value
    fn SetValue(&self, value: Finite<f32>) {
        self.message_node(
            AudioNodeMessage::SetParam(self.param, UserAutomationEvent::SetValue(*value)),
        );
    }

    // https://webaudio.github.io/web-audio-api/#dom-audioparam-defaultvalue
    fn DefaultValue(&self) -> Finite<f32> {
        Finite::wrap(self.default_value)
    }

    // https://webaudio.github.io/web-audio-api/#dom-audioparam-minvalue
    fn MinValue(&self) -> Finite<f32> {
        Finite::wrap(self.min_value)
    }

    // https://webaudio.github.io/web-audio-api/#dom-audioparam-maxvalue
    fn MaxValue(&self) -> Finite<f32> {
        Finite::wrap(self.max_value)
    }

    // https://webaudio.github.io/web-audio-api/#dom-audioparam-setvalueattime
    fn SetValueAtTime(&self, value: Finite<f32>, start_time: Finite<f64>) -> DomRoot<AudioParam> {
        self.message_node(
            AudioNodeMessage::SetParam(
                self.param,
                UserAutomationEvent::SetValueAtTime(*value, *start_time),
            )
        );
        DomRoot::from_ref(self)
    }

    // https://webaudio.github.io/web-audio-api/#dom-audioparam-linearramptovalueattime
    fn LinearRampToValueAtTime(
        &self,
        value: Finite<f32>,
        end_time: Finite<f64>,
    ) -> DomRoot<AudioParam> {
        self.message_node(
            AudioNodeMessage::SetParam(
                self.param,
                UserAutomationEvent::RampToValueAtTime(RampKind::Linear, *value, *end_time),
            ),
        );
        DomRoot::from_ref(self)
    }

    // https://webaudio.github.io/web-audio-api/#dom-audioparam-exponentialramptovalueattime
    fn ExponentialRampToValueAtTime(
        &self,
        value: Finite<f32>,
        end_time: Finite<f64>,
    ) -> DomRoot<AudioParam> {
        self.message_node(
            AudioNodeMessage::SetParam(
                self.param,
                UserAutomationEvent::RampToValueAtTime(RampKind::Exponential, *value, *end_time),
            ),
        );
        DomRoot::from_ref(self)
    }

    // https://webaudio.github.io/web-audio-api/#dom-audioparam-settargetattime
    fn SetTargetAtTime(
        &self,
        target: Finite<f32>,
        start_time: Finite<f64>,
        time_constant: Finite<f32>,
    ) -> DomRoot<AudioParam> {
        self.message_node(
            AudioNodeMessage::SetParam(
                self.param,
                UserAutomationEvent::SetTargetAtTime(*target, *start_time, (*time_constant).into()),
            ),
        );
        DomRoot::from_ref(self)
    }

    // https://webaudio.github.io/web-audio-api/#dom-audioparam-cancelscheduledvalues
    fn CancelScheduledValues(&self, cancel_time: Finite<f64>) -> DomRoot<AudioParam> {
        self.message_node(
            AudioNodeMessage::SetParam(
                self.param,
                UserAutomationEvent::CancelScheduledValues(*cancel_time),
            ),
        );
        DomRoot::from_ref(self)
    }

    // https://webaudio.github.io/web-audio-api/#dom-audioparam-cancelandholdattime
    fn CancelAndHoldAtTime(&self, cancel_time: Finite<f64>) -> DomRoot<AudioParam> {
        self.message_node(
            AudioNodeMessage::SetParam(
                self.param,
                UserAutomationEvent::CancelAndHoldAtTime(*cancel_time),
            ),
        );
        DomRoot::from_ref(self)
    }
}

// https://webaudio.github.io/web-audio-api/#enumdef-automationrate
impl From<AutomationRate> for ParamRate {
    fn from(rate: AutomationRate) -> Self {
        match rate {
            AutomationRate::A_rate => ParamRate::ARate,
            AutomationRate::K_rate => ParamRate::KRate,
        }
    }
}
<|endoftext|>


<commit_before>use super::command::ZmqCommand;
use super::error::CodecError;
use super::greeting::ZmqGreeting;
use super::Message;
use crate::ZmqMessage;

use bytes::{Buf, BufMut, Bytes, BytesMut};
use futures_codec::{Decoder, Encoder};
use std::convert::TryFrom;

#[derive(Debug, Clone, Copy)]
struct Frame {
    command: bool,
    long: bool,
    more: bool,
}

#[derive(Debug)]
enum DecoderState {
    Greeting,
    FrameHeader,
    FrameLen(Frame),
    Frame(Frame),
}

#[derive(Debug)]
pub struct ZmqCodec {
    state: DecoderState,
    waiting_for: usize, // Number of bytes needed to decode frame
    // Needed to store incoming multipart message
    // This allows to incapsulate it's processing inside codec and not expose
    // internal details to higher levels
    buffered_message: Option<Vec<Bytes>>,
}

impl ZmqCodec {
    pub fn new() -> Self {
        Self {
            state: DecoderState::Greeting,
            waiting_for: 64, // len of the greeting frame,
            buffered_message: None,
        }
    }
}

impl Default for ZmqCodec {
    fn default() -> Self {
        Self::new()
    }
}

impl Decoder for ZmqCodec {
    type Error = CodecError;
    type Item = Message;

    fn decode(&mut self, src: &mut BytesMut) -> Result<Option<Self::Item>, Self::Error> {
        if src.len() < self.waiting_for {
            src.reserve(self.waiting_for - src.len());
            return Ok(None);
        }
        match self.state {
            DecoderState::Greeting => {
                if src[0] != 0xff {
                    return Err(CodecError::Decode("Bad first byte of greeting"));
                }
                self.state = DecoderState::FrameHeader;
                self.waiting_for = 1;
                Ok(Some(Message::Greeting(ZmqGreeting::try_from(
                    src.split_to(64).freeze(),
                )?)))
            }
            DecoderState::FrameHeader => {
                let flags = src.get_u8();
                let command = (flags & 0b0000_0100) != 0;
                let long = (flags & 0b0000_0010) != 0;
                let more = (flags & 0b0000_0001) != 0;

                if self.buffered_message.is_none() {
                    let v: Vec<Bytes> = Vec::new();
                    self.buffered_message = Some(v);
                }
                let frame = Frame {
                    command,
                    long,
                    more,
                };
                self.state = DecoderState::FrameLen(frame);
                self.waiting_for = if frame.long { 8 } else { 1 };
                self.decode(src)
            }
            DecoderState::FrameLen(frame) => {
                self.state = DecoderState::Frame(frame);
                self.waiting_for = if frame.long {
                    src.get_u64() as usize
                } else {
                    src.get_u8() as usize
                };
                self.decode(src)
            }
            DecoderState::Frame(frame) => {
                let data = src.split_to(self.waiting_for);
                self.state = DecoderState::FrameHeader;
                self.waiting_for = 1;
                if frame.command {
                    Ok(Some(Message::Command(ZmqCommand::try_from(data)?)))
                } else if frame.more {
                    // cache incoming multipart message
                    match &mut self.buffered_message {
                        Some(v) => v.push(data.freeze()),
                        _ => panic!("Corrupted decoder state"),
                    }
                    self.decode(src)
                } else if let Some(mut v) = self.buffered_message.take() {
                    v.push(data.freeze());
                    match ZmqMessage::try_from(v) {
                        Ok(m) => Ok(Some(Message::Message(m))),
                        Err(_) => Err(CodecError::Other("Can't encode an empty message")),
                    }
                } else {
                    panic!("Corrupted decoder state");
                }
            }
        }
    }
}

impl ZmqCodec {
    fn _encode_frame(&mut self, frame: &Bytes, dst: &mut BytesMut, more: bool) {
        let mut flags: u8 = 0;
        if more {
            flags |= 0b0000_0001;
        }
        let len = frame.len();
        if len > 255 {
            flags |= 0b0000_0010;
            dst.reserve(len + 9);
        } else {
            dst.reserve(len + 2);
        }
        dst.put_u8(flags);
        if len > 255 {
            dst.put_u64(len as u64);
        } else {
            dst.put_u8(len as u8);
        }
        dst.extend_from_slice(frame.as_ref());
    }
}

impl Encoder for ZmqCodec {
    type Error = CodecError;
    type Item = Message;

    fn encode(&mut self, message: Self::Item, dst: &mut BytesMut) -> Result<(), Self::Error> {
        match message {
            Message::Greeting(payload) => dst.unsplit(payload.into()),
            Message::Command(command) => dst.unsplit(command.into()),
            Message::Message(message) => {
                let last_element = message.len() - 1;
                for (idx, part) in message.iter().enumerate() {
                    self._encode_frame(part, dst, idx != last_element);
                }
            }
        }
        Ok(())
    }
}
<commit_msg>Minor refactoring of codec code.<commit_after>use super::command::ZmqCommand;
use super::error::CodecError;
use super::greeting::ZmqGreeting;
use super::Message;
use crate::ZmqMessage;

use bytes::{Buf, BufMut, Bytes, BytesMut};
use futures_codec::{Decoder, Encoder};
use std::convert::TryFrom;

#[derive(Debug, Clone, Copy)]
struct Frame {
    command: bool,
    long: bool,
    more: bool,
}

#[derive(Debug)]
enum DecoderState {
    Greeting,
    FrameHeader,
    FrameLen(Frame),
    Frame(Frame),
}

#[derive(Debug)]
pub struct ZmqCodec {
    state: DecoderState,
    waiting_for: usize, // Number of bytes needed to decode frame
    // Needed to store incoming multipart message
    // This allows to incapsulate it's processing inside codec and not expose
    // internal details to higher levels
    buffered_message: Option<ZmqMessage>,
}

impl ZmqCodec {
    pub fn new() -> Self {
        Self {
            state: DecoderState::Greeting,
            waiting_for: 64, // len of the greeting frame,
            buffered_message: None,
        }
    }
}

impl Default for ZmqCodec {
    fn default() -> Self {
        Self::new()
    }
}

impl Decoder for ZmqCodec {
    type Error = CodecError;
    type Item = Message;

    fn decode(&mut self, src: &mut BytesMut) -> Result<Option<Self::Item>, Self::Error> {
        if src.len() < self.waiting_for {
            src.reserve(self.waiting_for - src.len());
            return Ok(None);
        }
        match self.state {
            DecoderState::Greeting => {
                if src[0] != 0xff {
                    return Err(CodecError::Decode("Bad first byte of greeting"));
                }
                self.state = DecoderState::FrameHeader;
                self.waiting_for = 1;
                Ok(Some(Message::Greeting(ZmqGreeting::try_from(
                    src.split_to(64).freeze(),
                )?)))
            }
            DecoderState::FrameHeader => {
                let flags = src.get_u8();

                let frame = Frame {
                    command: (flags & 0b0000_0100) != 0,
                    long: (flags & 0b0000_0010) != 0,
                    more: (flags & 0b0000_0001) != 0,
                };
                self.state = DecoderState::FrameLen(frame);
                self.waiting_for = if frame.long { 8 } else { 1 };
                self.decode(src)
            }
            DecoderState::FrameLen(frame) => {
                self.state = DecoderState::Frame(frame);
                self.waiting_for = if frame.long {
                    src.get_u64() as usize
                } else {
                    src.get_u8() as usize
                };
                self.decode(src)
            }
            DecoderState::Frame(frame) => {
                let data = src.split_to(self.waiting_for);
                self.state = DecoderState::FrameHeader;
                self.waiting_for = 1;
                if frame.command {
                    return Ok(Some(Message::Command(ZmqCommand::try_from(data)?)));
                }

                // process incoming message frame
                match &mut self.buffered_message {
                    Some(v) => v.push_back(data.freeze()),
                    None => self.buffered_message = Some(ZmqMessage::from(data.freeze())),
                }

                if frame.more {
                    self.decode(src)
                } else {
                    // Quoth the Raven “Nevermore.”
                    Ok(Some(Message::Message(
                        self.buffered_message
                            .take()
                            .expect("Corrupted decoder state"),
                    )))
                }
            }
        }
    }
}

impl ZmqCodec {
    fn _encode_frame(&mut self, frame: &Bytes, dst: &mut BytesMut, more: bool) {
        let mut flags: u8 = 0;
        if more {
            flags |= 0b0000_0001;
        }
        let len = frame.len();
        if len > 255 {
            flags |= 0b0000_0010;
            dst.reserve(len + 9);
        } else {
            dst.reserve(len + 2);
        }
        dst.put_u8(flags);
        if len > 255 {
            dst.put_u64(len as u64);
        } else {
            dst.put_u8(len as u8);
        }
        dst.extend_from_slice(frame.as_ref());
    }
}

impl Encoder for ZmqCodec {
    type Error = CodecError;
    type Item = Message;

    fn encode(&mut self, message: Self::Item, dst: &mut BytesMut) -> Result<(), Self::Error> {
        match message {
            Message::Greeting(payload) => dst.unsplit(payload.into()),
            Message::Command(command) => dst.unsplit(command.into()),
            Message::Message(message) => {
                let last_element = message.len() - 1;
                for (idx, part) in message.iter().enumerate() {
                    self._encode_frame(part, dst, idx != last_element);
                }
            }
        }
        Ok(())
    }
}
<|endoftext|>


<commit_before>use std::collections::HashSet;
use std::io::{Result, Write};

use analysis::general::StatusedTypeId;
use config::Config;
use git::repo_hash;

pub fn start_comments<W: Write>(conf: &Config, w: &mut W) -> Result<()>{
    try!(writeln!(w, "// This file was generated by gir (???) from gir-files ({})",
            repo_hash(&conf.girs_dir).unwrap_or_else(|_| "???".into())));
    try!(writeln!(w, "// DO NOT EDIT"));

    Ok(())
}

pub fn uses<W: Write>(w: &mut W, used_types: &HashSet<String>) -> Result<()>{
    let v = vec![
        "",
        "use glib::translate::*;",
        "use glib::types;",
        "use ffi;",
        "",
        "use object::*;",
    ];
    for s in v {
        try!(writeln!(w, "{}", s));
    }

    let mut used_types: Vec<String> = used_types.iter()
        .map(|s| s.clone()).collect();
    used_types.sort_by(|a, b| a.cmp(b));

    for name in used_types {
        try!(writeln!(w, "use {};", name));
    }

    Ok(())
}

pub fn objects_child_type<W: Write>(w: &mut W, type_name: &str, glib_name: &str) -> Result<()>{
    try!(writeln!(w, ""));
    try!(writeln!(w, "pub type {} = Object<ffi::{}>;", type_name, glib_name));

    Ok(())
}

pub fn impl_parents<W: Write>(w: &mut W, type_name: &str, parents: &Vec<StatusedTypeId>) -> Result<()>{
    try!(writeln!(w, ""));
    for stid in parents {
        //TODO: don't generate for parents without traits
        try!(writeln!(w, "unsafe impl Upcast<{}> for {} {{ }}", stid.name, type_name));
    }

    Ok(())
}

pub fn impl_interfaces<W: Write>(w: &mut W, type_name: &str, implements: &Vec<StatusedTypeId>) -> Result<()>{
    try!(writeln!(w, ""));
    for stid in implements {
        try!(writeln!(w, "unsafe impl Upcast<{}> for {} {{ }}", stid.name, type_name));
    }

    Ok(())
}

pub fn impl_static_type<W: Write>(w: &mut W, type_name: &str, glib_func_name: &str) -> Result<()>{
    try!(writeln!(w, ""));
    try!(writeln!(w, "impl types::StaticType for {} {{", type_name));
    try!(writeln!(w, "{}#[inline]", tabs(1)));
    try!(writeln!(w, "{}fn static_type() -> types::Type {{", tabs(1)));
    try!(writeln!(w, "{}unsafe {{ from_glib(ffi::{}()) }}", tabs(2), glib_func_name));
    try!(writeln!(w, "{}}}", tabs(1)));
    try!(writeln!(w, "}}"));

    Ok(())
}

//TODO: convert to macro with usage
//format!(indent!(5, "format:{}"), 6)
pub fn tabs(num: i32) -> String {
    (0..num).map(|_| "    ").collect::<String>()
}
<commit_msg>Put the gir commit hash into the output files headers<commit_after>use std::collections::HashSet;
use std::io::{Result, Write};

use analysis::general::StatusedTypeId;
use config::Config;
use git::repo_hash;
use version::VERSION;

pub fn start_comments<W: Write>(conf: &Config, w: &mut W) -> Result<()>{
    try!(writeln!(w, "// This file was generated by gir ({}) from gir-files ({})",
            VERSION, repo_hash(&conf.girs_dir).unwrap_or_else(|_| "???".into())));
    try!(writeln!(w, "// DO NOT EDIT"));

    Ok(())
}

pub fn uses<W: Write>(w: &mut W, used_types: &HashSet<String>) -> Result<()>{
    let v = vec![
        "",
        "use glib::translate::*;",
        "use glib::types;",
        "use ffi;",
        "",
        "use object::*;",
    ];
    for s in v {
        try!(writeln!(w, "{}", s));
    }

    let mut used_types: Vec<String> = used_types.iter()
        .map(|s| s.clone()).collect();
    used_types.sort_by(|a, b| a.cmp(b));

    for name in used_types {
        try!(writeln!(w, "use {};", name));
    }

    Ok(())
}

pub fn objects_child_type<W: Write>(w: &mut W, type_name: &str, glib_name: &str) -> Result<()>{
    try!(writeln!(w, ""));
    try!(writeln!(w, "pub type {} = Object<ffi::{}>;", type_name, glib_name));

    Ok(())
}

pub fn impl_parents<W: Write>(w: &mut W, type_name: &str, parents: &Vec<StatusedTypeId>) -> Result<()>{
    try!(writeln!(w, ""));
    for stid in parents {
        //TODO: don't generate for parents without traits
        try!(writeln!(w, "unsafe impl Upcast<{}> for {} {{ }}", stid.name, type_name));
    }

    Ok(())
}

pub fn impl_interfaces<W: Write>(w: &mut W, type_name: &str, implements: &Vec<StatusedTypeId>) -> Result<()>{
    try!(writeln!(w, ""));
    for stid in implements {
        try!(writeln!(w, "unsafe impl Upcast<{}> for {} {{ }}", stid.name, type_name));
    }

    Ok(())
}

pub fn impl_static_type<W: Write>(w: &mut W, type_name: &str, glib_func_name: &str) -> Result<()>{
    try!(writeln!(w, ""));
    try!(writeln!(w, "impl types::StaticType for {} {{", type_name));
    try!(writeln!(w, "{}#[inline]", tabs(1)));
    try!(writeln!(w, "{}fn static_type() -> types::Type {{", tabs(1)));
    try!(writeln!(w, "{}unsafe {{ from_glib(ffi::{}()) }}", tabs(2), glib_func_name));
    try!(writeln!(w, "{}}}", tabs(1)));
    try!(writeln!(w, "}}"));

    Ok(())
}

//TODO: convert to macro with usage
//format!(indent!(5, "format:{}"), 6)
pub fn tabs(num: i32) -> String {
    (0..num).map(|_| "    ").collect::<String>()
}
<|endoftext|>


<commit_before>use nom::character::complete::{multispace0, multispace1};
use std::fmt;
use std::str;

use common::statement_terminator;
use nom::branch::alt;
use nom::bytes::complete::{tag, tag_no_case};
use nom::combinator::{map, opt};
use nom::multi::many1;
use nom::sequence::{delimited, preceded, tuple};
use nom::IResult;
use order::{order_clause, OrderClause};
use select::{limit_clause, nested_selection, LimitClause, SelectStatement};

#[derive(Clone, Debug, Eq, Hash, PartialEq, Deserialize, Serialize)]
pub enum CompoundSelectOperator {
    Union,
    DistinctUnion,
    Intersect,
    Except,
}

impl fmt::Display for CompoundSelectOperator {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            CompoundSelectOperator::Union => write!(f, "UNION"),
            CompoundSelectOperator::DistinctUnion => write!(f, "UNION DISTINCT"),
            CompoundSelectOperator::Intersect => write!(f, "INTERSECT"),
            CompoundSelectOperator::Except => write!(f, "EXCEPT"),
        }
    }
}

#[derive(Clone, Debug, Eq, Hash, PartialEq, Deserialize, Serialize)]
pub struct CompoundSelectStatement {
    pub selects: Vec<(Option<CompoundSelectOperator>, SelectStatement)>,
    pub order: Option<OrderClause>,
    pub limit: Option<LimitClause>,
}

impl fmt::Display for CompoundSelectStatement {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        for (ref op, ref sel) in &self.selects {
            if op.is_some() {
                write!(f, " {}", op.as_ref().unwrap())?;
            }
            write!(f, " {}", sel)?;
        }
        if self.order.is_some() {
            write!(f, " {}", self.order.as_ref().unwrap())?;
        }
        if self.limit.is_some() {
            write!(f, " {}", self.order.as_ref().unwrap())?;
        }
        Ok(())
    }
}

// Parse compound operator
fn compound_op(i: &[u8]) -> IResult<&[u8], CompoundSelectOperator> {
    alt((
        map(
            preceded(
                tag_no_case("union"),
                opt(preceded(
                    multispace1,
                    alt((
                        map(tag_no_case("all"), |_| false),
                        map(tag_no_case("distinct"), |_| true),
                    )),
                )),
            ),
            |distinct| {
                match distinct {
                    // DISTINCT is the default in both MySQL and SQLite
                    None => CompoundSelectOperator::DistinctUnion,
                    Some(d) => {
                        if d {
                            CompoundSelectOperator::DistinctUnion
                        } else {
                            CompoundSelectOperator::Union
                        }
                    }
                }
            },
        ),
        map(tag_no_case("intersect"), |_| {
            CompoundSelectOperator::Intersect
        }),
        map(tag_no_case("except"), |_| CompoundSelectOperator::Except),
    ))(i)
}

fn other_selects(i: &[u8]) -> IResult<&[u8], (Option<CompoundSelectOperator>, SelectStatement)> {
    let (remaining_input, (_, op, _, _, _, select, _, _)) = tuple((
        multispace0,
        compound_op,
        multispace1,
        opt(tag("(")),
        multispace0,
        nested_selection,
        multispace0,
        opt(tag(")")),
    ))(i)?;

    Ok((remaining_input, (Some(op), select)))
}

// Parse compound selection
pub fn compound_selection(i: &[u8]) -> IResult<&[u8], CompoundSelectStatement> {
    let (remaining_input, (first_select, other_selects, _, order, limit, _)) = tuple((
        delimited(opt(tag("(")), nested_selection, opt(tag(")"))),
        many1(other_selects),
        multispace0,
        opt(order_clause),
        opt(limit_clause),
        statement_terminator,
    ))(i)?;

    let mut selects = vec![(None, first_select)];
    selects.extend(other_selects);

    Ok((
        remaining_input,
        CompoundSelectStatement {
            selects,
            order,
            limit,
        },
    ))
}

#[cfg(test)]
mod tests {
    use super::*;
    use column::Column;
    use common::{FieldDefinitionExpression, FieldValueExpression, Literal};
    use table::Table;

    #[test]
    fn union() {
        let qstr = "SELECT id, 1 FROM Vote UNION SELECT id, stars from Rating;";
        let qstr2 = "(SELECT id, 1 FROM Vote) UNION (SELECT id, stars from Rating);";
        let res = compound_selection(qstr.as_bytes());
        let res2 = compound_selection(qstr2.as_bytes());

        let first_select = SelectStatement {
            tables: vec![Table::from("Vote")],
            fields: vec![
                FieldDefinitionExpression::Col(Column::from("id")),
                FieldDefinitionExpression::Value(FieldValueExpression::Literal(
                    Literal::Integer(1).into(),
                )),
            ],
            ..Default::default()
        };
        let second_select = SelectStatement {
            tables: vec![Table::from("Rating")],
            fields: vec![
                FieldDefinitionExpression::Col(Column::from("id")),
                FieldDefinitionExpression::Col(Column::from("stars")),
            ],
            ..Default::default()
        };
        let expected = CompoundSelectStatement {
            selects: vec![
                (None, first_select),
                (Some(CompoundSelectOperator::DistinctUnion), second_select),
            ],
            order: None,
            limit: None,
        };

        assert_eq!(res.unwrap().1, expected);
        assert_eq!(res2.unwrap().1, expected);
    }

    #[test]
    fn multi_union() {
        let qstr = "SELECT id, 1 FROM Vote \
                    UNION SELECT id, stars from Rating \
                    UNION DISTINCT SELECT 42, 5 FROM Vote;";
        let res = compound_selection(qstr.as_bytes());

        let first_select = SelectStatement {
            tables: vec![Table::from("Vote")],
            fields: vec![
                FieldDefinitionExpression::Col(Column::from("id")),
                FieldDefinitionExpression::Value(FieldValueExpression::Literal(
                    Literal::Integer(1).into(),
                )),
            ],
            ..Default::default()
        };
        let second_select = SelectStatement {
            tables: vec![Table::from("Rating")],
            fields: vec![
                FieldDefinitionExpression::Col(Column::from("id")),
                FieldDefinitionExpression::Col(Column::from("stars")),
            ],
            ..Default::default()
        };
        let third_select = SelectStatement {
            tables: vec![Table::from("Vote")],
            fields: vec![
                FieldDefinitionExpression::Value(FieldValueExpression::Literal(
                    Literal::Integer(42).into(),
                )),
                FieldDefinitionExpression::Value(FieldValueExpression::Literal(
                    Literal::Integer(5).into(),
                )),
            ],
            ..Default::default()
        };

        let expected = CompoundSelectStatement {
            selects: vec![
                (None, first_select),
                (Some(CompoundSelectOperator::DistinctUnion), second_select),
                (Some(CompoundSelectOperator::DistinctUnion), third_select),
            ],
            order: None,
            limit: None,
        };

        assert_eq!(res.unwrap().1, expected);
    }

    #[test]
    fn union_all() {
        let qstr = "SELECT id, 1 FROM Vote UNION ALL SELECT id, stars from Rating;";
        let res = compound_selection(qstr.as_bytes());

        let first_select = SelectStatement {
            tables: vec![Table::from("Vote")],
            fields: vec![
                FieldDefinitionExpression::Col(Column::from("id")),
                FieldDefinitionExpression::Value(FieldValueExpression::Literal(
                    Literal::Integer(1).into(),
                )),
            ],
            ..Default::default()
        };
        let second_select = SelectStatement {
            tables: vec![Table::from("Rating")],
            fields: vec![
                FieldDefinitionExpression::Col(Column::from("id")),
                FieldDefinitionExpression::Col(Column::from("stars")),
            ],
            ..Default::default()
        };
        let expected = CompoundSelectStatement {
            selects: vec![
                (None, first_select),
                (Some(CompoundSelectOperator::Union), second_select),
            ],
            order: None,
            limit: None,
        };

        assert_eq!(res.unwrap().1, expected);
    }
}
<commit_msg>Remove unnecessary level of bracing<commit_after>use nom::character::complete::{multispace0, multispace1};
use std::fmt;
use std::str;

use common::statement_terminator;
use nom::branch::alt;
use nom::bytes::complete::{tag, tag_no_case};
use nom::combinator::{map, opt};
use nom::multi::many1;
use nom::sequence::{delimited, preceded, tuple};
use nom::IResult;
use order::{order_clause, OrderClause};
use select::{limit_clause, nested_selection, LimitClause, SelectStatement};

#[derive(Clone, Debug, Eq, Hash, PartialEq, Deserialize, Serialize)]
pub enum CompoundSelectOperator {
    Union,
    DistinctUnion,
    Intersect,
    Except,
}

impl fmt::Display for CompoundSelectOperator {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            CompoundSelectOperator::Union => write!(f, "UNION"),
            CompoundSelectOperator::DistinctUnion => write!(f, "UNION DISTINCT"),
            CompoundSelectOperator::Intersect => write!(f, "INTERSECT"),
            CompoundSelectOperator::Except => write!(f, "EXCEPT"),
        }
    }
}

#[derive(Clone, Debug, Eq, Hash, PartialEq, Deserialize, Serialize)]
pub struct CompoundSelectStatement {
    pub selects: Vec<(Option<CompoundSelectOperator>, SelectStatement)>,
    pub order: Option<OrderClause>,
    pub limit: Option<LimitClause>,
}

impl fmt::Display for CompoundSelectStatement {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        for (ref op, ref sel) in &self.selects {
            if op.is_some() {
                write!(f, " {}", op.as_ref().unwrap())?;
            }
            write!(f, " {}", sel)?;
        }
        if self.order.is_some() {
            write!(f, " {}", self.order.as_ref().unwrap())?;
        }
        if self.limit.is_some() {
            write!(f, " {}", self.order.as_ref().unwrap())?;
        }
        Ok(())
    }
}

// Parse compound operator
fn compound_op(i: &[u8]) -> IResult<&[u8], CompoundSelectOperator> {
    alt((
        map(
            preceded(
                tag_no_case("union"),
                opt(preceded(
                    multispace1,
                    alt((
                        map(tag_no_case("all"), |_| false),
                        map(tag_no_case("distinct"), |_| true),
                    )),
                )),
            ),
            |distinct| match distinct {
                // DISTINCT is the default in both MySQL and SQLite
                None => CompoundSelectOperator::DistinctUnion,
                Some(d) => {
                    if d {
                        CompoundSelectOperator::DistinctUnion
                    } else {
                        CompoundSelectOperator::Union
                    }
                }
            },
        ),
        map(tag_no_case("intersect"), |_| {
            CompoundSelectOperator::Intersect
        }),
        map(tag_no_case("except"), |_| CompoundSelectOperator::Except),
    ))(i)
}

fn other_selects(i: &[u8]) -> IResult<&[u8], (Option<CompoundSelectOperator>, SelectStatement)> {
    let (remaining_input, (_, op, _, _, _, select, _, _)) = tuple((
        multispace0,
        compound_op,
        multispace1,
        opt(tag("(")),
        multispace0,
        nested_selection,
        multispace0,
        opt(tag(")")),
    ))(i)?;

    Ok((remaining_input, (Some(op), select)))
}

// Parse compound selection
pub fn compound_selection(i: &[u8]) -> IResult<&[u8], CompoundSelectStatement> {
    let (remaining_input, (first_select, other_selects, _, order, limit, _)) = tuple((
        delimited(opt(tag("(")), nested_selection, opt(tag(")"))),
        many1(other_selects),
        multispace0,
        opt(order_clause),
        opt(limit_clause),
        statement_terminator,
    ))(i)?;

    let mut selects = vec![(None, first_select)];
    selects.extend(other_selects);

    Ok((
        remaining_input,
        CompoundSelectStatement {
            selects,
            order,
            limit,
        },
    ))
}

#[cfg(test)]
mod tests {
    use super::*;
    use column::Column;
    use common::{FieldDefinitionExpression, FieldValueExpression, Literal};
    use table::Table;

    #[test]
    fn union() {
        let qstr = "SELECT id, 1 FROM Vote UNION SELECT id, stars from Rating;";
        let qstr2 = "(SELECT id, 1 FROM Vote) UNION (SELECT id, stars from Rating);";
        let res = compound_selection(qstr.as_bytes());
        let res2 = compound_selection(qstr2.as_bytes());

        let first_select = SelectStatement {
            tables: vec![Table::from("Vote")],
            fields: vec![
                FieldDefinitionExpression::Col(Column::from("id")),
                FieldDefinitionExpression::Value(FieldValueExpression::Literal(
                    Literal::Integer(1).into(),
                )),
            ],
            ..Default::default()
        };
        let second_select = SelectStatement {
            tables: vec![Table::from("Rating")],
            fields: vec![
                FieldDefinitionExpression::Col(Column::from("id")),
                FieldDefinitionExpression::Col(Column::from("stars")),
            ],
            ..Default::default()
        };
        let expected = CompoundSelectStatement {
            selects: vec![
                (None, first_select),
                (Some(CompoundSelectOperator::DistinctUnion), second_select),
            ],
            order: None,
            limit: None,
        };

        assert_eq!(res.unwrap().1, expected);
        assert_eq!(res2.unwrap().1, expected);
    }

    #[test]
    fn multi_union() {
        let qstr = "SELECT id, 1 FROM Vote \
                    UNION SELECT id, stars from Rating \
                    UNION DISTINCT SELECT 42, 5 FROM Vote;";
        let res = compound_selection(qstr.as_bytes());

        let first_select = SelectStatement {
            tables: vec![Table::from("Vote")],
            fields: vec![
                FieldDefinitionExpression::Col(Column::from("id")),
                FieldDefinitionExpression::Value(FieldValueExpression::Literal(
                    Literal::Integer(1).into(),
                )),
            ],
            ..Default::default()
        };
        let second_select = SelectStatement {
            tables: vec![Table::from("Rating")],
            fields: vec![
                FieldDefinitionExpression::Col(Column::from("id")),
                FieldDefinitionExpression::Col(Column::from("stars")),
            ],
            ..Default::default()
        };
        let third_select = SelectStatement {
            tables: vec![Table::from("Vote")],
            fields: vec![
                FieldDefinitionExpression::Value(FieldValueExpression::Literal(
                    Literal::Integer(42).into(),
                )),
                FieldDefinitionExpression::Value(FieldValueExpression::Literal(
                    Literal::Integer(5).into(),
                )),
            ],
            ..Default::default()
        };

        let expected = CompoundSelectStatement {
            selects: vec![
                (None, first_select),
                (Some(CompoundSelectOperator::DistinctUnion), second_select),
                (Some(CompoundSelectOperator::DistinctUnion), third_select),
            ],
            order: None,
            limit: None,
        };

        assert_eq!(res.unwrap().1, expected);
    }

    #[test]
    fn union_all() {
        let qstr = "SELECT id, 1 FROM Vote UNION ALL SELECT id, stars from Rating;";
        let res = compound_selection(qstr.as_bytes());

        let first_select = SelectStatement {
            tables: vec![Table::from("Vote")],
            fields: vec![
                FieldDefinitionExpression::Col(Column::from("id")),
                FieldDefinitionExpression::Value(FieldValueExpression::Literal(
                    Literal::Integer(1).into(),
                )),
            ],
            ..Default::default()
        };
        let second_select = SelectStatement {
            tables: vec![Table::from("Rating")],
            fields: vec![
                FieldDefinitionExpression::Col(Column::from("id")),
                FieldDefinitionExpression::Col(Column::from("stars")),
            ],
            ..Default::default()
        };
        let expected = CompoundSelectStatement {
            selects: vec![
                (None, first_select),
                (Some(CompoundSelectOperator::Union), second_select),
            ],
            order: None,
            limit: None,
        };

        assert_eq!(res.unwrap().1, expected);
    }
}
<|endoftext|>