<commit_before>use token::{Token, Kind, Tokenizer};
use ast::Node;
use parser::Parser;
use std::collections::HashMap;

// # Interpreter
//
// Represents the interpreter that is responsible for interpret
// the Abstracted Sintax Tree generated by the Parser

pub struct Interpreter {
    pub simbol_table: HashMap<String, String>
}
impl Interpreter {
    pub fn new() -> Self {
        Interpreter {
            simbol_table: HashMap::new()
        }
    }
    // eval_tree
    //
    // It visits each node evaluating the binary operations returning the
    // result as String
    //
    // Example:
    //   The expression 3 * 5 + 5 will produce the follow tree and the result 20.
    //   It evaluates the left side first and applies a post-order calc
    //
    //         +-+
    //         |-|
    //     +---------+
    //     |         |
    //     v         v
    //    +-+       +-+
    //    |*|       |5|
    //  +-----+     +-+
    //  |     |
    //  v     v
    // ---   ---
    // |3|   |5|
    // +-+   +-+
    pub fn eval_tree(&mut self, tree: Node) -> String {
        match tree.clone().nodes() {
            (Some(lnode), Some(rnode)) => {
                match tree.clone().kind() {
                    Kind::Operator =>
                        return binary_operation(self.eval_tree(lnode),
                        tree.value(),
                        self.eval_tree(rnode)).to_string(),
                        _ => String::new()
                }
            },

            (Some(lnode), None) => self.eval_tree(lnode),

            (None, Some(rnode)) => match tree.clone().kind() {
                Kind::Operator =>
                    unary_operation(tree.value(), self.eval_tree(rnode)).to_string(),
                    _ => self.eval_tree(rnode)
            },

            (None, None) => tree.value()
        }
    }
}

// unary_operation
// Resolves the unary operations Example: --1 == 1, 1++-1==0
fn unary_operation(operator: String, operand: String) -> i32 {
    let ioperand = if let Ok(val) = operand.parse::<i32>() { val } else {
        panic!("Sintax error: invalid unary operand {}", operand)
    };
    match operator.as_ref() {
        "+" => ioperand,
        "-" => -(ioperand),
        _ => panic!("Sintax error: invalid unary operator {}", operator)
    }
}

// binary_operation
// Resolve binary expression for the given left, operator and right operand
fn binary_operation(operand: String, operator: String, operand2: String) -> i32 {
    let left = if let Ok(val) = operand.parse::<i32>() { val } else {
        panic!("Sintax error: invalid operand: {}", operand)
    };
    let right = if let Ok(val) = operand2.parse::<i32>() { val } else {
        panic!("Sintax error: invalid operand: {}", operand2)
    };
    match operator.as_ref() {
        "+" => left + right,
        "-" => left - right,
        "*" => left * right,
        "/" => left / right,
        _ => panic!("Sintax error: invalid operator {}", operator)
    }
}

#[test]
fn it_eval_tree_leaf() {
    let token = Token::build(Kind::Integer, String::from("10"));
    let leaf = Node::leaf(token);

    assert_eq!("10", Interpreter::new().eval_tree(leaf))
}

#[test]
fn it_eval_the_node_binary_operation() {
    // 3+5
    let left = Node::leaf(Token::build(Kind::Integer, String::from("3")));
    let operator = Token::build(Kind::Operator, String::from("+"));
    let right = Node::leaf(Token::build(Kind::Integer, String::from("5")));
    let node = Node::new(left, operator, right);

    assert_eq!("8", Interpreter::new().eval_tree(node))
}

#[test]
fn it_eval_complex_tree() {
    // 5+5*3
    let left = Node::leaf(Token::build(Kind::Integer, String::from("3")));
    let operator = Token::build(Kind::Operator, String::from("*"));
    let right = Node::leaf(Token::build(Kind::Integer, String::from("5")));
    let plusnode = Node::new(left, operator, right);

    let operator = Token::build(Kind::Operator, String::from("+"));
    let sumright = Node::leaf(Token::build(Kind::Integer, String::from("5")));
    let sumnode = Node::new(plusnode, operator, sumright);

    assert_eq!("20", Interpreter::new().eval_tree(sumnode))
}

#[test]
fn it_eval_unary_operations() {
    // 2 -- 2
    let rnode = Node::leaf(Token::build(Kind::Integer, String::from("2")));
    let negative_op = Token::build(Kind::Operator, String::from("-"));
    let unarynode = Node::unary(negative_op, rnode);

    let operator = Token::build(Kind::Operator, String::from("-"));
    let left = Node::leaf(Token::build(Kind::Integer, String::from("2")));
    let sumnode = Node::new(left, operator, unarynode);

    assert_eq!("4", Interpreter::new().eval_tree(sumnode))
}

#[test]
fn it_sums() {
    let text = "5+1";
    let tokenizer = Tokenizer::new(String::from(text));
    let mut parser = Parser::new(tokenizer);

    assert_eq!("6", Interpreter::new().eval_tree(parser.parse()));
}

#[test]
fn it_substract() {
    let text = "5-1";
    let tokenizer = Tokenizer::new(String::from(text));
    let mut parser = Parser::new(tokenizer);

    assert_eq!("4", Interpreter::new().eval_tree(parser.parse()));
}

#[test]
fn it_multiplies() {
    let text = "5*2";
    let tokenizer = Tokenizer::new(String::from(text));
    let mut parser = Parser::new(tokenizer);

    assert_eq!("10", Interpreter::new().eval_tree(parser.parse()));
}

#[test]
fn it_divide() {
    let text = "4/2";
    let tokenizer = Tokenizer::new(String::from(text));
    let mut parser = Parser::new(tokenizer);

    assert_eq!("2", Interpreter::new().eval_tree(parser.parse()));
}

#[test]
fn it_accepts_multiples_operation() {
    let text = "10+5-4-1";
    let tokenizer = Tokenizer::new(String::from(text));
    let mut parser = Parser::new(tokenizer);

    assert_eq!("10", Interpreter::new().eval_tree(parser.parse()));
}

#[test]
fn it_respect_precedence() {
    let text = "1+1*2";
    let tokenizer = Tokenizer::new(String::from(text));
    let mut parser = Parser::new(tokenizer);

    assert_eq!("3", Interpreter::new().eval_tree(parser.parse()));
}

#[test]
fn it_respects_grouped_expression() {
    let text = "4+(1+(1+1)*2)+1";
    let tokenizer = Tokenizer::new(String::from(text));
    let mut parser = Parser::new(tokenizer);

    assert_eq!("10", Interpreter::new().eval_tree(parser.parse()));
}

#[test]
fn it_accept_unary_operations() {
    let text = "(4+-1)--2";
    let tokenizer = Tokenizer::new(String::from(text));
    let mut parser = Parser::new(tokenizer);

    assert_eq!("5", Interpreter::new().eval_tree(parser.parse()));
}
<commit_msg>feature: interpreter eval assignments nodes<commit_after>use token::{Token, Kind, Tokenizer};
use ast::Node;
use parser::Parser;
use std::collections::HashMap;

// # Interpreter
//
// Represents the interpreter that is responsible for interpret
// the Abstracted Sintax Tree generated by the Parser

pub struct Interpreter {
    pub symbol_table: HashMap<String, String>
}
impl Interpreter {
    pub fn new() -> Self {
        Interpreter {
            symbol_table: HashMap::new()
        }
    }
    // eval_tree
    //
    // It visits each node evaluating the binary operations returning the
    // result as String
    //
    // Example:
    //   The expression 3 * 5 + 5 will produce the follow tree and the result 20.
    //   It evaluates the left side first and applies a post-order calc
    //
    //         +-+
    //         |-|
    //     +---------+
    //     |         |
    //     v         v
    //    +-+       +-+
    //    |*|       |5|
    //  +-----+     +-+
    //  |     |
    //  v     v
    // ---   ---
    // |3|   |5|
    // +-+   +-+
    pub fn eval_tree(&mut self, tree: Node) -> String {
        match tree.clone().nodes() {
            (Some(lnode), Some(rnode)) => {
                match tree.clone().kind() {
                    Kind::Operator =>
                        binary_operation(self.eval_tree(lnode),
                                         tree.value(),
                                         self.eval_tree(rnode)).to_string(),

                    Kind::Assign => {
                        let variable_value = self.eval_tree(rnode);
                        self.symbol_table.insert(lnode.value(),
                                                 variable_value.clone());
                        variable_value
                    },

                    _ => panic!("Interpreter error: unexpecte node kind {:?}",
                                tree)
                }
            },

            (Some(lnode), None) => self.eval_tree(lnode),

            (None, Some(rnode)) => match tree.clone().kind() {
                Kind::Operator =>
                    unary_operation(tree.value(), self.eval_tree(rnode)).to_string(),
                    _ => self.eval_tree(rnode)
            },

            (None, None) => {
                if let Some(statements) = tree.statements {
                    statements.iter().map(|n| self.eval_tree(n.clone()))
                              .fold(String::new(), |mut res, s|{
                                  s
                              })
                } else {
                    tree.value()
                }
            }
        }
    }
}

// unary_operation
// Resolves the unary operations Example: --1 == 1, 1++-1==0
fn unary_operation(operator: String, operand: String) -> i32 {
    let ioperand = if let Ok(val) = operand.parse::<i32>() { val } else {
        panic!("Sintax error: invalid unary operand {}", operand)
    };
    match operator.as_ref() {
        "+" => ioperand,
        "-" => -(ioperand),
        _ => panic!("Sintax error: invalid unary operator {}", operator)
    }
}

// binary_operation
// Resolve binary expression for the given left, operator and right operand
fn binary_operation(operand: String, operator: String, operand2: String) -> i32 {
    let left = if let Ok(val) = operand.parse::<i32>() { val } else {
        panic!("Sintax error: invalid operand: {}", operand)
    };
    let right = if let Ok(val) = operand2.parse::<i32>() { val } else {
        panic!("Sintax error: invalid operand: {}", operand2)
    };
    match operator.as_ref() {
        "+" => left + right,
        "-" => left - right,
        "*" => left * right,
        "/" => left / right,
        _ => panic!("Sintax error: invalid operator {}", operator)
    }
}

#[test]
fn it_eval_tree_leaf() {
    let token = Token::build(Kind::Integer, String::from("10"));
    let leaf = Node::leaf(token);

    assert_eq!("10", Interpreter::new().eval_tree(leaf))
}

#[test]
fn it_eval_the_node_binary_operation() {
    // 3+5
    let left = Node::leaf(Token::build(Kind::Integer, String::from("3")));
    let operator = Token::build(Kind::Operator, String::from("+"));
    let right = Node::leaf(Token::build(Kind::Integer, String::from("5")));
    let node = Node::new(left, operator, right);

    assert_eq!("8", Interpreter::new().eval_tree(node))
}

#[test]
fn it_eval_complex_tree() {
    // 5+5*3
    let left = Node::leaf(Token::build(Kind::Integer, String::from("3")));
    let operator = Token::build(Kind::Operator, String::from("*"));
    let right = Node::leaf(Token::build(Kind::Integer, String::from("5")));
    let plusnode = Node::new(left, operator, right);

    let operator = Token::build(Kind::Operator, String::from("+"));
    let sumright = Node::leaf(Token::build(Kind::Integer, String::from("5")));
    let sumnode = Node::new(plusnode, operator, sumright);

    assert_eq!("20", Interpreter::new().eval_tree(sumnode))
}

#[test]
fn it_eval_unary_operations() {
    // 2 -- 2
    let rnode = Node::leaf(Token::build(Kind::Integer, String::from("2")));
    let negative_op = Token::build(Kind::Operator, String::from("-"));
    let unarynode = Node::unary(negative_op, rnode);

    let operator = Token::build(Kind::Operator, String::from("-"));
    let left = Node::leaf(Token::build(Kind::Integer, String::from("2")));
    let sumnode = Node::new(left, operator, unarynode);

    assert_eq!("4", Interpreter::new().eval_tree(sumnode))
}

#[test]
fn it_sums() {
    let text = "5+1";
    let tokenizer = Tokenizer::new(String::from(text));
    let mut parser = Parser::new(tokenizer);

    assert_eq!("6", Interpreter::new().eval_tree(parser.parse()));
}

#[test]
fn it_substract() {
    let text = "5-1";
    let tokenizer = Tokenizer::new(String::from(text));
    let mut parser = Parser::new(tokenizer);

    assert_eq!("4", Interpreter::new().eval_tree(parser.parse()));
}

#[test]
fn it_multiplies() {
    let text = "5*2";
    let tokenizer = Tokenizer::new(String::from(text));
    let mut parser = Parser::new(tokenizer);

    assert_eq!("10", Interpreter::new().eval_tree(parser.parse()));
}

#[test]
fn it_divide() {
    let text = "4/2";
    let tokenizer = Tokenizer::new(String::from(text));
    let mut parser = Parser::new(tokenizer);

    assert_eq!("2", Interpreter::new().eval_tree(parser.parse()));
}

#[test]
fn it_accepts_multiples_operation() {
    let text = "10+5-4-1";
    let tokenizer = Tokenizer::new(String::from(text));
    let mut parser = Parser::new(tokenizer);

    assert_eq!("10", Interpreter::new().eval_tree(parser.parse()));
}

#[test]
fn it_respect_precedence() {
    let text = "1+1*2";
    let tokenizer = Tokenizer::new(String::from(text));
    let mut parser = Parser::new(tokenizer);

    assert_eq!("3", Interpreter::new().eval_tree(parser.parse()));
}

#[test]
fn it_respects_grouped_expression() {
    let text = "4+(1+(1+1)*2)+1";
    let tokenizer = Tokenizer::new(String::from(text));
    let mut parser = Parser::new(tokenizer);

    assert_eq!("10", Interpreter::new().eval_tree(parser.parse()));
}

#[test]
fn it_accept_unary_operations() {
    let text = "(4+-1)--2";
    let tokenizer = Tokenizer::new(String::from(text));
    let mut parser = Parser::new(tokenizer);

    assert_eq!("5", Interpreter::new().eval_tree(parser.parse()));
}

#[test]
fn it_eval_block_assigning_vars_to_symbol_table() {
    let text = "BEGIN x := 10 END";
    let tokenizer = Tokenizer::new(String::from(text));
    let mut parser = Parser::new(tokenizer);
    let mut interpreter = Interpreter::new();
    let _ = interpreter.eval_tree(parser.parse());

    assert_eq!("10", interpreter.symbol_table["x"]);
}
<|endoftext|>


<commit_before>// The elements of an array can be accessed by their indices
// arr[4]
#[test]
fn array_index() {
    let arr: [i32; 5] = [1, 2, 3, 4, 5];
    assert!(arr[__] == 1);
}

// A new fixed size array can be created by declaring the type of its elements
// along with its length
// [i32; 0] = []
#[test]
fn array_empty() {
    let arr: __;
    assert!(arr.len() == 0);
}

// Attempting to access an array at an index that is
// out of its bounds will cause an error. Let's cause
// that error in this example.
#[test]
#[should_panic]
#[allow(const_err)]
fn out_of_index() {
    let arr: [&'static str; 5] = ["rust", "is", "mostly", "for", "nerds"];
    arr[__];
}

// Elements can be replaced in an array at a certain index.
// hint: Without the 'mut' keyword, you won't be able to change data.
#[test]
fn insert_at_index() {
    let mut arr: [u8; 5] = [0, 1, 2, 3, 4];
    __ = 0;
    assert!(arr == [0, 1, 2, 3, 0]);
}

// Arrays can be iterated over.
#[test]
fn array_iteration() {
    let arr: [u8; 3] = [3, 2, 1];
    let mut iterator = arr.iter();
    assert!(iterator.next().unwrap() == &__);
    assert!(iterator.next().unwrap() == &__);
    assert!(iterator.next().unwrap() == &__);
}

// Arrays can also be mutated during iteration
#[test]
fn array_map() {
    let arr: [u32; 4] = [2, 5, 7, 4];
    let mut iterator = arr.iter().map(__);
    assert!(iterator.next() == Some(4));
    assert!(iterator.next() == Some(10));
    assert!(iterator.next() == Some(14));
    assert!(iterator.next() == Some(8));
}

// You can filter an array for results that match a given condition
#[test]
fn array_filter() {
    let arr: [u16; 5] = [1, 2, 3, 4, 5];
    let mut iterator = arr.iter().filter(__);
    assert!(iterator.next().unwrap() == &2);
    assert!(iterator.next().unwrap() == &4);
    assert!(iterator.next().is_none());
}

// Filter and map can be combined to do both at once
#[test]
fn array_filter_map() {
    let arr: [u8; 5] = [2, 1, 2, 1, 2];
    let mut iterator = arr.iter().filter_map(|&x| if x == 1 { Some(__) } else { None });
    assert!(iterator.next() == Some(3));
    assert!(iterator.next() == Some(3));
    assert!(iterator.next().is_none());
}

// This can be used for more complex logic as well
#[test]
fn complex_array_filter_map() {
    let arr: [u64; 4] = [4, 8, 16, 32];
    let mut iterator = arr.iter()
        .filter_map(|&x| if (x as f64).sqrt().floor() == (x as f64).sqrt() {
            Some((x as f64).sqrt() as u64)
        } else {
            None
        });
    assert!(iterator.next().unwrap() == __);
    assert!(iterator.next().unwrap() == __);
    assert!(iterator.next().is_none());
}

// Arrays can also be iterated through using a for loop
#[test]
fn for_loops() {
    let arr: [u64; 3] = [1, 2, 3];
    let mut y: u64 = 1;
    for x in &arr {
        assert!(*x == y);
    }
}

// Let's try iterating over an array of strings to build a sentence
#[test]
fn for_loops_two() {
    let words: [&'static str; 3] = ["I", "love", "Rust"];
    let mut sentence: String = String::new();
    for word in words.iter() {
        __
    }
    println!("{:?}", sentence);
    assert!(sentence == "I love Rust".to_string());
}
<commit_msg>Fix for #40<commit_after>// The elements of an array can be accessed by their indices
// arr[4]
#[test]
fn array_index() {
    let arr: [i32; 5] = [1, 2, 3, 4, 5];
    assert!(arr[__] == 1);
}

// A new fixed size array can be created by declaring the type of its elements
// along with its length
// [i32; 0] = []
#[test]
fn array_empty() {
    let arr: __;
    assert!(arr.len() == 0);
}

// Attempting to access an array at an index that is
// out of its bounds will cause an error. Let's cause
// that error in this example.
#[test]
#[should_panic]
#[allow(const_err)]
fn out_of_index() {
    let arr: [&'static str; 5] = ["rust", "is", "mostly", "for", "nerds"];
    arr[__];
}

// Elements can be replaced in an array at a certain index.
// hint: Without the 'mut' keyword, you won't be able to change data.
#[test]
fn insert_at_index() {
    let mut arr: [u8; 5] = [0, 1, 2, 3, 4];
    __ = 0;
    assert!(arr == [0, 1, 2, 3, 0]);
}

// Arrays can be iterated over.
#[test]
fn array_iteration() {
    let arr: [u8; 3] = [3, 2, 1];
    let mut iterator = arr.iter();
    assert!(iterator.next().unwrap() == &__);
    assert!(iterator.next().unwrap() == &__);
    assert!(iterator.next().unwrap() == &__);
}

// Arrays can also be mutated during iteration
#[test]
fn array_map() {
    let arr: [u32; 4] = [2, 5, 7, 4];
    let mut iterator = arr.iter().map(__);
    assert!(iterator.next() == Some(4));
    assert!(iterator.next() == Some(10));
    assert!(iterator.next() == Some(14));
    assert!(iterator.next() == Some(8));
}

// You can filter an array for results that match a given condition
#[test]
fn array_filter() {
    let arr: [u16; 5] = [1, 2, 3, 4, 5];
    let mut iterator = arr.iter().filter(__);
    assert!(iterator.next().unwrap() == &2);
    assert!(iterator.next().unwrap() == &4);
    assert!(iterator.next().is_none());
}

// Filter and map can be combined to do both at once
#[test]
fn array_filter_map() {
    let arr: [u8; 5] = [2, 1, 2, 1, 2];
    let mut iterator = arr.iter().filter_map(|&x| if x == 1 { Some(__) } else { None });
    assert!(iterator.next() == Some(3));
    assert!(iterator.next() == Some(3));
    assert!(iterator.next().is_none());
}

// This can be used for more complex logic as well
#[test]
fn complex_array_filter_map() {
    let arr: [u64; 4] = [4, 8, 16, 32];
    let mut iterator = arr.iter()
        .filter_map(|&x| if (x as f64).sqrt().floor() == (x as f64).sqrt() {
            Some((x as f64).sqrt() as u64)
        } else {
            None
        });
    assert!(iterator.next().unwrap() == __);
    assert!(iterator.next().unwrap() == __);
    assert!(iterator.next().is_none());
}

// Arrays can also be iterated through using a for loop
#[test]
fn for_loops() {
    let arr: [u64; 3] = [1, 2, 3];
    let mut y: u64 = 1;
    for x in &arr {
        assert!(*x == y);
        __
    }
}

// Let's try iterating over an array of strings to build a sentence
#[test]
fn for_loops_two() {
    let words: [&'static str; 3] = ["I", "love", "Rust"];
    let mut sentence: String = String::new();
    for word in words.iter() {
        __
    }
    println!("{:?}", sentence);
    assert!(sentence == "I love Rust".to_string());
}
<|endoftext|>


<commit_before>use buffer::{Content, Buffer, BufferAny, BufferType, BufferMode, BufferCreationError};
use buffer::{BufferSlice, BufferMutSlice};
use uniforms::{AsUniformValue, UniformBlock, UniformValue, LayoutMismatchError};
use program;

use gl;
use GlObject;

use std::ops::{Deref, DerefMut};

use backend::Facade;

/// Buffer that contains a uniform block.
#[derive(Debug)]
pub struct UniformBuffer<T: ?Sized> where T: Content {
    buffer: Buffer<T>,
}

/// Same as `UniformBuffer` but doesn't contain any information about the type.
#[derive(Debug)]
pub struct TypelessUniformBuffer {
    buffer: BufferAny,
}

impl<T: Copy> GlObject for UniformBuffer<T> {
    type Id = gl::types::GLuint;

    #[inline]
    fn get_id(&self) -> gl::types::GLuint {
        self.buffer.get_id()
    }
}

impl<T> UniformBuffer<T> where T: Copy {
    /// Uploads data in the uniforms buffer.
    #[inline]
    pub fn new<F>(facade: &F, data: T) -> Result<UniformBuffer<T>, BufferCreationError>
                  where F: Facade
    {
        UniformBuffer::new_impl(facade, data, BufferMode::Default)
    }

    /// Uploads data in the uniforms buffer.
    #[inline]
    pub fn dynamic<F>(facade: &F, data: T) -> Result<UniformBuffer<T>, BufferCreationError>
                      where F: Facade
    {
        UniformBuffer::new_impl(facade, data, BufferMode::Dynamic)
    }

    /// Uploads data in the uniforms buffer.
    #[inline]
    pub fn persistent<F>(facade: &F, data: T) -> Result<UniformBuffer<T>, BufferCreationError>
                  where F: Facade
    {
        UniformBuffer::new_impl(facade, data, BufferMode::Persistent)
    }

    /// Uploads data in the uniforms buffer.
    #[inline]
    pub fn immutable<F>(facade: &F, data: T) -> Result<UniformBuffer<T>, BufferCreationError>
                        where F: Facade
    {
        UniformBuffer::new_impl(facade, data, BufferMode::Immutable)
    }

    #[inline]
    fn new_impl<F>(facade: &F, data: T, mode: BufferMode)
                   -> Result<UniformBuffer<T>, BufferCreationError>
                   where F: Facade
    {
        let buffer = try!(Buffer::new(facade, &data, BufferType::UniformBuffer, mode));

        Ok(UniformBuffer {
            buffer: buffer,
        })
    }

    /// Creates an empty buffer.
    #[inline]
    pub fn empty<F>(facade: &F) -> Result<UniformBuffer<T>, BufferCreationError> where F: Facade {
        UniformBuffer::empty_impl(facade, BufferMode::Default)
    }

    /// Creates an empty buffer.
    #[inline]
    pub fn empty_dynamic<F>(facade: &F) -> Result<UniformBuffer<T>, BufferCreationError>
                            where F: Facade
    {
        UniformBuffer::empty_impl(facade, BufferMode::Dynamic)
    }

    /// Creates an empty buffer.
    #[inline]
    pub fn empty_persistent<F>(facade: &F) -> Result<UniformBuffer<T>, BufferCreationError>
                               where F: Facade
    {
        UniformBuffer::empty_impl(facade, BufferMode::Persistent)
    }

    /// Creates an empty buffer.
    #[inline]
    pub fn empty_immutable<F>(facade: &F) -> Result<UniformBuffer<T>, BufferCreationError>
                              where F: Facade
    {
        UniformBuffer::empty_impl(facade, BufferMode::Immutable)
    }

    #[inline]
    fn empty_impl<F>(facade: &F, mode: BufferMode) -> Result<UniformBuffer<T>, BufferCreationError>
                     where F: Facade
    {
        let buffer = try!(Buffer::empty(facade, BufferType::UniformBuffer, mode));

        Ok(UniformBuffer {
            buffer: buffer,
        })
    }
}

impl<T: ?Sized> UniformBuffer<T> where T: Content {
    /// Creates an empty buffer.
    ///
    /// # Panic
    ///
    /// Panicks if the size passed as parameter is not suitable for the type of data.
    ///
    #[inline]
    pub fn empty_unsized<F>(facade: &F, size: usize)
                            -> Result<UniformBuffer<T>, BufferCreationError>
                            where F: Facade
    {
        UniformBuffer::empty_unsized_impl(facade, size, BufferMode::Default)
    }

    /// Creates an empty buffer.
    ///
    /// # Panic
    ///
    /// Panicks if the size passed as parameter is not suitable for the type of data.
    ///
    #[inline]
    pub fn empty_unsized_dynamic<F>(facade: &F, size: usize)
                                    -> Result<UniformBuffer<T>, BufferCreationError>
                                    where F: Facade
    {
        UniformBuffer::empty_unsized_impl(facade, size, BufferMode::Dynamic)
    }

    /// Creates an empty buffer.
    ///
    /// # Panic
    ///
    /// Panicks if the size passed as parameter is not suitable for the type of data.
    ///
    #[inline]
    pub fn empty_unsized_persistent<F>(facade: &F, size: usize)
                                       -> Result<UniformBuffer<T>, BufferCreationError>
                                       where F: Facade
    {
        UniformBuffer::empty_unsized_impl(facade, size, BufferMode::Persistent)
    }

    /// Creates an empty buffer.
    ///
    /// # Panic
    ///
    /// Panicks if the size passed as parameter is not suitable for the type of data.
    ///
    #[inline]
    pub fn empty_unsized_immutable<F>(facade: &F, size: usize)
                                      -> Result<UniformBuffer<T>, BufferCreationError>
                                      where F: Facade
    {
        UniformBuffer::empty_unsized_impl(facade, size, BufferMode::Immutable)
    }

    #[inline]
    fn empty_unsized_impl<F>(facade: &F, size: usize, mode: BufferMode)
                             -> Result<UniformBuffer<T>, BufferCreationError>
                             where F: Facade
    {
        let buffer = try!(Buffer::empty_unsized(facade, BufferType::UniformBuffer, size, mode));

        Ok(UniformBuffer {
            buffer: buffer,
        })
    }
}

impl<T: ?Sized> Deref for UniformBuffer<T> where T: Content {
    type Target = Buffer<T>;

    #[inline]
    fn deref(&self) -> &Buffer<T> {
        &self.buffer
    }
}

impl<T: ?Sized> DerefMut for UniformBuffer<T> where T: Content {
    #[inline]
    fn deref_mut(&mut self) -> &mut Buffer<T> {
        &mut self.buffer
    }
}

impl<'a, T: ?Sized> From<&'a UniformBuffer<T>> for BufferSlice<'a, T> where T: Content {
    #[inline]
    fn from(b: &'a UniformBuffer<T>) -> BufferSlice<'a, T> {
        b.buffer.as_slice()
    }
}

impl<'a, T: ?Sized> From<&'a mut UniformBuffer<T>> for BufferMutSlice<'a, T> where T: Content {
    #[inline]
    fn from(b: &'a mut UniformBuffer<T>) -> BufferMutSlice<'a, T> {
        b.buffer.as_mut_slice()
    }
}

impl<'a, T: ?Sized> AsUniformValue for &'a UniformBuffer<T> where T: UniformBlock + Content {
    #[inline]
    fn as_uniform_value(&self) -> UniformValue {
        #[inline]
        fn f<T: ?Sized>(block: &program::UniformBlock)
                        -> Result<(), LayoutMismatchError> where T: UniformBlock + Content
        {
            // TODO: more checks?
            T::matches(&block.layout, 0)
        }

        UniformValue::Block(self.buffer.as_slice_any(), f::<T>)
    }
}
<commit_msg>fixed idiocy<commit_after>use buffer::{Content, Buffer, BufferAny, BufferType, BufferMode, BufferCreationError};
use buffer::{BufferSlice, BufferMutSlice};
use uniforms::{AsUniformValue, UniformBlock, UniformValue, LayoutMismatchError};
use program;

use gl;
use GlObject;

use std::ops::{Deref, DerefMut};

use backend::Facade;

/// Buffer that contains a uniform block.
#[derive(Debug)]
pub struct UniformBuffer<T: ?Sized> where T: Content {
    buffer: Buffer<T>,
}

/// Same as `UniformBuffer` but doesn't contain any information about the type.
#[derive(Debug)]
pub struct TypelessUniformBuffer {
    buffer: BufferAny,
}

impl<T: ?Sized + Content> GlObject for UniformBuffer<T> {
    type Id = gl::types::GLuint;

    #[inline]
    fn get_id(&self) -> gl::types::GLuint {
        self.buffer.get_id()
    }
}

impl<T> UniformBuffer<T> where T: Copy {
    /// Uploads data in the uniforms buffer.
    #[inline]
    pub fn new<F>(facade: &F, data: T) -> Result<UniformBuffer<T>, BufferCreationError>
                  where F: Facade
    {
        UniformBuffer::new_impl(facade, data, BufferMode::Default)
    }

    /// Uploads data in the uniforms buffer.
    #[inline]
    pub fn dynamic<F>(facade: &F, data: T) -> Result<UniformBuffer<T>, BufferCreationError>
                      where F: Facade
    {
        UniformBuffer::new_impl(facade, data, BufferMode::Dynamic)
    }

    /// Uploads data in the uniforms buffer.
    #[inline]
    pub fn persistent<F>(facade: &F, data: T) -> Result<UniformBuffer<T>, BufferCreationError>
                  where F: Facade
    {
        UniformBuffer::new_impl(facade, data, BufferMode::Persistent)
    }

    /// Uploads data in the uniforms buffer.
    #[inline]
    pub fn immutable<F>(facade: &F, data: T) -> Result<UniformBuffer<T>, BufferCreationError>
                        where F: Facade
    {
        UniformBuffer::new_impl(facade, data, BufferMode::Immutable)
    }

    #[inline]
    fn new_impl<F>(facade: &F, data: T, mode: BufferMode)
                   -> Result<UniformBuffer<T>, BufferCreationError>
                   where F: Facade
    {
        let buffer = try!(Buffer::new(facade, &data, BufferType::UniformBuffer, mode));

        Ok(UniformBuffer {
            buffer: buffer,
        })
    }

    /// Creates an empty buffer.
    #[inline]
    pub fn empty<F>(facade: &F) -> Result<UniformBuffer<T>, BufferCreationError> where F: Facade {
        UniformBuffer::empty_impl(facade, BufferMode::Default)
    }

    /// Creates an empty buffer.
    #[inline]
    pub fn empty_dynamic<F>(facade: &F) -> Result<UniformBuffer<T>, BufferCreationError>
                            where F: Facade
    {
        UniformBuffer::empty_impl(facade, BufferMode::Dynamic)
    }

    /// Creates an empty buffer.
    #[inline]
    pub fn empty_persistent<F>(facade: &F) -> Result<UniformBuffer<T>, BufferCreationError>
                               where F: Facade
    {
        UniformBuffer::empty_impl(facade, BufferMode::Persistent)
    }

    /// Creates an empty buffer.
    #[inline]
    pub fn empty_immutable<F>(facade: &F) -> Result<UniformBuffer<T>, BufferCreationError>
                              where F: Facade
    {
        UniformBuffer::empty_impl(facade, BufferMode::Immutable)
    }

    #[inline]
    fn empty_impl<F>(facade: &F, mode: BufferMode) -> Result<UniformBuffer<T>, BufferCreationError>
                     where F: Facade
    {
        let buffer = try!(Buffer::empty(facade, BufferType::UniformBuffer, mode));

        Ok(UniformBuffer {
            buffer: buffer,
        })
    }
}

impl<T: ?Sized> UniformBuffer<T> where T: Content {
    /// Creates an empty buffer.
    ///
    /// # Panic
    ///
    /// Panicks if the size passed as parameter is not suitable for the type of data.
    ///
    #[inline]
    pub fn empty_unsized<F>(facade: &F, size: usize)
                            -> Result<UniformBuffer<T>, BufferCreationError>
                            where F: Facade
    {
        UniformBuffer::empty_unsized_impl(facade, size, BufferMode::Default)
    }

    /// Creates an empty buffer.
    ///
    /// # Panic
    ///
    /// Panicks if the size passed as parameter is not suitable for the type of data.
    ///
    #[inline]
    pub fn empty_unsized_dynamic<F>(facade: &F, size: usize)
                                    -> Result<UniformBuffer<T>, BufferCreationError>
                                    where F: Facade
    {
        UniformBuffer::empty_unsized_impl(facade, size, BufferMode::Dynamic)
    }

    /// Creates an empty buffer.
    ///
    /// # Panic
    ///
    /// Panicks if the size passed as parameter is not suitable for the type of data.
    ///
    #[inline]
    pub fn empty_unsized_persistent<F>(facade: &F, size: usize)
                                       -> Result<UniformBuffer<T>, BufferCreationError>
                                       where F: Facade
    {
        UniformBuffer::empty_unsized_impl(facade, size, BufferMode::Persistent)
    }

    /// Creates an empty buffer.
    ///
    /// # Panic
    ///
    /// Panicks if the size passed as parameter is not suitable for the type of data.
    ///
    #[inline]
    pub fn empty_unsized_immutable<F>(facade: &F, size: usize)
                                      -> Result<UniformBuffer<T>, BufferCreationError>
                                      where F: Facade
    {
        UniformBuffer::empty_unsized_impl(facade, size, BufferMode::Immutable)
    }

    #[inline]
    fn empty_unsized_impl<F>(facade: &F, size: usize, mode: BufferMode)
                             -> Result<UniformBuffer<T>, BufferCreationError>
                             where F: Facade
    {
        let buffer = try!(Buffer::empty_unsized(facade, BufferType::UniformBuffer, size, mode));

        Ok(UniformBuffer {
            buffer: buffer,
        })
    }
}

impl<T: ?Sized> Deref for UniformBuffer<T> where T: Content {
    type Target = Buffer<T>;

    #[inline]
    fn deref(&self) -> &Buffer<T> {
        &self.buffer
    }
}

impl<T: ?Sized> DerefMut for UniformBuffer<T> where T: Content {
    #[inline]
    fn deref_mut(&mut self) -> &mut Buffer<T> {
        &mut self.buffer
    }
}

impl<'a, T: ?Sized> From<&'a UniformBuffer<T>> for BufferSlice<'a, T> where T: Content {
    #[inline]
    fn from(b: &'a UniformBuffer<T>) -> BufferSlice<'a, T> {
        b.buffer.as_slice()
    }
}

impl<'a, T: ?Sized> From<&'a mut UniformBuffer<T>> for BufferMutSlice<'a, T> where T: Content {
    #[inline]
    fn from(b: &'a mut UniformBuffer<T>) -> BufferMutSlice<'a, T> {
        b.buffer.as_mut_slice()
    }
}

impl<'a, T: ?Sized> AsUniformValue for &'a UniformBuffer<T> where T: UniformBlock + Content {
    #[inline]
    fn as_uniform_value(&self) -> UniformValue {
        #[inline]
        fn f<T: ?Sized>(block: &program::UniformBlock)
                        -> Result<(), LayoutMismatchError> where T: UniformBlock + Content
        {
            // TODO: more checks?
            T::matches(&block.layout, 0)
        }

        UniformValue::Block(self.buffer.as_slice_any(), f::<T>)
    }
}
<|endoftext|>


<commit_before>use sass::color_value::ColorValue;
use sass::number_value::NumberValue;
use sass::value_part::ValuePart;
use sass::op::Op;

use error::Result;

use std::borrow::Cow::Borrowed;

#[derive(Debug)]
pub struct ValueTokenizer<'a> {
    value_str: &'a str,
    bytes: &'a [u8],
    offset: usize,
}

impl<'a> ValueTokenizer<'a> {
    pub fn new(value_str: &'a str) -> ValueTokenizer<'a> {
        ValueTokenizer {
            value_str: &value_str,
            bytes: &value_str.as_bytes(),
            offset: 0,
        }
    }

    pub fn parse(&mut self) -> Result<Option<ValuePart<'a>>> {
        self.skip_leading_whitespace();

        let start = self.offset;
        let mut i = self.offset;
        let limit = self.value_str.len();

        let ret = if start == limit {
            None
        } else if is_operator(self.bytes[start]) {
            self.offset = start + 1;
            Some(ValuePart::Operator(self.value_str[start..start + 1].parse().unwrap_or(Op::Plus)))
        } else if is_number(self.bytes[start]) {
            i += self.scan_while(&self.value_str[i..limit], is_number);
            self.offset = i;
            if i < limit && valid_unit_char(self.bytes[i]) {
                let unit_start = i;
                i += self.scan_while(&self.value_str[i..limit], valid_unit_char);
                self.offset = i;
                Some(ValuePart::Number(NumberValue::with_units(
                    self.value_str[start..unit_start].parse().unwrap_or(0.0),
                    Borrowed(&self.value_str[unit_start..i]),
                )))
            }
            else {
                Some(ValuePart::Number(NumberValue::from_scalar(
                    self.value_str[start..i].parse().unwrap_or(0.0)
                )))
            }
        } else if self.bytes[start] == b'$' {
            i += self.scan_while(&self.value_str[i..limit], isnt_space);
            self.offset = i;
            Some(ValuePart::Variable(Borrowed(&self.value_str[start..i])))
        } else if self.bytes[start] == b'#' {
            i += 1;
            i += self.scan_while(&self.value_str[i..limit], valid_hex_char);
            self.offset = i;
            match ColorValue::from_hex(Borrowed(&self.value_str[start..i])) {
                Ok(v) => Some(ValuePart::Color(v)),
                Err(e) => return Err(e),
            }
        } else if self.eat("rgb(") {
            let r = self.eat_color_u8();
            self.eat(",");
            let g = self.eat_color_u8();
            self.eat(",");
            let b = self.eat_color_u8();
            self.eat(")");

            Some(ValuePart::Color(
                ColorValue {
                    red: r, green: g, blue: b,
                    original: Borrowed(&self.value_str[start..self.offset]),
                }
            ))
        } else {
            i = start;
            i += self.scan_while(&self.value_str[start..limit], isnt_space);
            self.offset = i;
            Some(ValuePart::String(Borrowed(&self.value_str[start..i])))
        };

        Ok(ret)
    }

    fn eat_color_u8(&mut self) -> u8 {
        let limit = self.value_str.len();
        let mut i = self.offset;
        let color_start = i;

        i += self.scan_while(&self.value_str[i..limit], is_number);
        self.offset = i;
        self.value_str[color_start..i].parse().unwrap_or(0)
    }

    fn eat(&mut self, expected: &str) -> bool {
        for c in expected.as_bytes().iter() {
            if !self.eatch(c) {
                return false
            }
        }
        return true
    }

    fn eatch(&mut self, expected_char: &u8) -> bool {
        if self.bytes[self.offset] == *expected_char {
            self.offset += 1;
            true
        } else {
            false
        }
    }

    fn scan_while<F>(&mut self, data: &str, f: F) -> usize
            where F: Fn(u8) -> bool {
        match data.as_bytes().iter().position(|&c| !f(c)) {
            Some(i) => i,
            None => data.len()
        }
    }

    fn skip_leading_whitespace(&mut self) {
       let mut i = self.offset;
       let limit = self.value_str.len();

       while i < limit {
           let c = self.bytes[i];
           if is_space(c) {
               i += self.scan_while(&self.value_str[i..limit], is_space);
           } else {
               self.offset = i;
               return
           }
       }
       self.offset = limit;
   }
}

impl<'a> Iterator for ValueTokenizer<'a> {
    type Item = Result<ValuePart<'a>>;

    fn next(&mut self) -> Option<Result<ValuePart<'a>>> {
        if self.offset < self.value_str.len() {
            return match self.parse() {
                Ok(Some(v)) => Some(Ok(v)),
                Ok(None) => None,
                Err(e) => Some(Err(e)),
            }
        }
        None
    }
}

fn is_space(c: u8) -> bool {
    c == b' '
}

fn isnt_space(c: u8) -> bool {
    !is_space(c)
}

fn valid_unit_char(c: u8) -> bool {
    c == b'%' || (!is_space(c) && !is_operator(c))
}

fn valid_hex_char(c: u8) -> bool {
    match c {
        b'0' ... b'9' | b'a' ... b'f' => true,
        _ => false,
    }
}

fn is_number(c: u8) -> bool {
    let result = match c {
        b'0' ... b'9' | b'.' => true,
        _ => false,
    };
    result
}

fn is_operator(c: u8) -> bool {
    match c {
        b'+' | b'-' | b'*' | b'/' | b'%' | b'(' | b')' | b',' => true,
        _ => false,
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use sass::color_value::ColorValue;
    use sass::value_part::ValuePart;
    use sass::number_value::NumberValue;
    use sass::op::Op;
    use std::borrow::Cow::Borrowed;

    #[test]
    fn it_returns_string_part() {
        let mut vt = ValueTokenizer::new("foo");
        assert_eq!(Some(Ok(ValuePart::String(Borrowed(&"foo")))), vt.next());
        assert_eq!(None, vt.next());
    }

    #[test]
    fn it_returns_space_separated_string_parts() {
        let mut vt = ValueTokenizer::new("foo bar");
        assert_eq!(Some(Ok(ValuePart::String(Borrowed(&"foo")))), vt.next());
        assert_eq!(Some(Ok(ValuePart::String(Borrowed(&"bar")))), vt.next());
        assert_eq!(None, vt.next());
    }

    #[test]
    fn it_returns_variable() {
        let mut vt = ValueTokenizer::new("$foo");
        assert_eq!(Some(Ok(ValuePart::Variable(Borrowed(&"$foo")))), vt.next());
        assert_eq!(None, vt.next());
    }

    #[test]
    fn it_returns_variables_and_string_parts() {
        let mut vt = ValueTokenizer::new("foo $bar baz $quux");
        assert_eq!(Some(Ok(ValuePart::String(Borrowed(&"foo")))), vt.next());
        assert_eq!(Some(Ok(ValuePart::Variable(Borrowed(&"$bar")))), vt.next());
        assert_eq!(Some(Ok(ValuePart::String(Borrowed(&"baz")))), vt.next());
        assert_eq!(Some(Ok(ValuePart::Variable(Borrowed(&"$quux")))), vt.next());
        assert_eq!(None, vt.next());
    }

    #[test]
    fn it_returns_number() {
        let mut vt = ValueTokenizer::new("3");
        assert_eq!(Some(Ok(ValuePart::Number(NumberValue::from_scalar(3.0)))), vt.next());
        assert_eq!(None, vt.next());
    }

    #[test]
    fn it_returns_two_numbers() {
        let mut vt = ValueTokenizer::new("3 8.9");
        assert_eq!(Some(Ok(ValuePart::Number(NumberValue::from_scalar(3.0)))), vt.next());
        assert_eq!(Some(Ok(ValuePart::Number(NumberValue::from_scalar(8.9)))), vt.next());
        assert_eq!(None, vt.next());
    }

    #[test]
    fn it_returns_numbers_with_units() {
        let mut vt = ValueTokenizer::new("3px");
        assert_eq!(
            Some(Ok(ValuePart::Number(NumberValue::with_units(3.0, Borrowed(&"px"))))),
            vt.next()
        );
        assert_eq!(None, vt.next());
    }

    #[test]
    fn it_returns_numbers_with_units_but_not_parens() {
        let mut vt = ValueTokenizer::new("(3px)");
        assert_eq!(Some(Ok(ValuePart::Operator(Op::LeftParen))), vt.next());
        assert_eq!(
            Some(Ok(ValuePart::Number(NumberValue::with_units(3.0, Borrowed(&"px"))))),
            vt.next()
        );
        assert_eq!(Some(Ok(ValuePart::Operator(Op::RightParen))), vt.next());
        assert_eq!(None, vt.next());
    }

    #[test]
    fn it_returns_numbers_with_percents_as_units() {
        let mut vt = ValueTokenizer::new("10px 8%");
        assert_eq!(
            Some(Ok(ValuePart::Number(NumberValue::with_units(10.0, Borrowed(&"px"))))),
            vt.next()
        );
        assert_eq!(
            Some(Ok(ValuePart::Number(NumberValue::with_units(8.0, Borrowed(&"%"))))),
            vt.next()
        );
        assert_eq!(None, vt.next());
    }

    #[test]
    fn it_returns_operator() {
        let mut vt = ValueTokenizer::new("+");
        assert_eq!(Some(Ok(ValuePart::Operator(Op::Plus))), vt.next());
        assert_eq!(None, vt.next());
    }

    #[test]
    fn it_returns_numbers_and_operators() {
        let mut vt = ValueTokenizer::new("6 + 75.2");
        assert_eq!(Some(Ok(ValuePart::Number(NumberValue::from_scalar(6.0)))), vt.next());
        assert_eq!(Some(Ok(ValuePart::Operator(Op::Plus))), vt.next());
        assert_eq!(Some(Ok(ValuePart::Number(NumberValue::from_scalar(75.2)))), vt.next());
        assert_eq!(None, vt.next());
    }

    #[test]
    fn it_returns_numbers_and_operators_without_spaces() {
        let mut vt = ValueTokenizer::new("6+75.2");
        assert_eq!(Some(Ok(ValuePart::Number(NumberValue::from_scalar(6.0)))), vt.next());
        assert_eq!(Some(Ok(ValuePart::Operator(Op::Plus))), vt.next());
        assert_eq!(Some(Ok(ValuePart::Number(NumberValue::from_scalar(75.2)))), vt.next());
        assert_eq!(None, vt.next());
    }

    #[test]
    fn it_does_stuff_with_parens() {
        let mut vt = ValueTokenizer::new("2+(3 4)");
        assert_eq!(Some(Ok(ValuePart::Number(NumberValue::from_scalar(2.0)))), vt.next());
        assert_eq!(Some(Ok(ValuePart::Operator(Op::Plus))), vt.next());
        assert_eq!(Some(Ok(ValuePart::Operator(Op::LeftParen))), vt.next());
        assert_eq!(Some(Ok(ValuePart::Number(NumberValue::from_scalar(3.0)))), vt.next());
        assert_eq!(Some(Ok(ValuePart::Number(NumberValue::from_scalar(4.0)))), vt.next());
        assert_eq!(Some(Ok(ValuePart::Operator(Op::RightParen))), vt.next());
        assert_eq!(None, vt.next());
    }

    #[test]
    fn it_does_stuff_with_slash_separators() {
        let mut vt = ValueTokenizer::new("15 / 3 / 5");
        assert_eq!(Some(Ok(ValuePart::Number(NumberValue::from_scalar(15.0)))), vt.next());
        assert_eq!(Some(Ok(ValuePart::Operator(Op::Slash))), vt.next());
        assert_eq!(Some(Ok(ValuePart::Number(NumberValue::from_scalar(3.0)))), vt.next());
        assert_eq!(Some(Ok(ValuePart::Operator(Op::Slash))), vt.next());
        assert_eq!(Some(Ok(ValuePart::Number(NumberValue::from_scalar(5.0)))), vt.next());
        assert_eq!(None, vt.next());
    }

    #[test]
    fn it_recognizes_hex() {
        let mut vt = ValueTokenizer::new("#aabbcc");
        assert_eq!(
            Some(Ok(ValuePart::Color(ColorValue {
                red: 170, green: 187, blue: 204, original: Borrowed("#aabbcc"),
            }))),
            vt.next()
        );
        assert_eq!(None, vt.next());
    }

    #[test]
    fn it_recognizes_short_hex() {
        let mut vt = ValueTokenizer::new("#cba");
        assert_eq!(
            Some(Ok(ValuePart::Color(ColorValue {
                red: 204, green: 187, blue: 170, original: Borrowed("#cba"),
            }))),
            vt.next()
        );
        assert_eq!(None, vt.next());
    }

    #[test]
    fn it_recognizes_hex_is_separate_from_parens() {
        let mut vt = ValueTokenizer::new("#cba)");
        assert_eq!(
            Some(Ok(ValuePart::Color(ColorValue {
                red: 204, green: 187, blue: 170, original: Borrowed("#cba"),
            }))),
            vt.next()
        );
        assert_eq!(Some(Ok(ValuePart::Operator(Op::RightParen))), vt.next());
        assert_eq!(None, vt.next());
    }

    #[test]
    fn it_recognizes_rgb() {
        let mut vt = ValueTokenizer::new("rgb(10,100,73)");
        assert_eq!(
            Some(Ok(ValuePart::Color(ColorValue {
                red: 10, green: 100, blue: 73, original: Borrowed("rgb(10,100,73)"),
            }))),
            vt.next()
        );
        assert_eq!(None, vt.next());
    }
}
<commit_msg>Tolerate spaces after commas in rgb colors<commit_after>use sass::color_value::ColorValue;
use sass::number_value::NumberValue;
use sass::value_part::ValuePart;
use sass::op::Op;

use error::Result;

use std::borrow::Cow::Borrowed;

#[derive(Debug)]
pub struct ValueTokenizer<'a> {
    value_str: &'a str,
    bytes: &'a [u8],
    offset: usize,
}

impl<'a> ValueTokenizer<'a> {
    pub fn new(value_str: &'a str) -> ValueTokenizer<'a> {
        ValueTokenizer {
            value_str: &value_str,
            bytes: &value_str.as_bytes(),
            offset: 0,
        }
    }

    pub fn parse(&mut self) -> Result<Option<ValuePart<'a>>> {
        self.skip_leading_whitespace();

        let start = self.offset;
        let mut i = self.offset;
        let limit = self.value_str.len();

        let ret = if start == limit {
            None
        } else if is_operator(self.bytes[start]) {
            self.offset = start + 1;
            Some(ValuePart::Operator(self.value_str[start..start + 1].parse().unwrap_or(Op::Plus)))
        } else if is_number(self.bytes[start]) {
            i += self.scan_while(&self.value_str[i..limit], is_number);
            self.offset = i;
            if i < limit && valid_unit_char(self.bytes[i]) {
                let unit_start = i;
                i += self.scan_while(&self.value_str[i..limit], valid_unit_char);
                self.offset = i;
                Some(ValuePart::Number(NumberValue::with_units(
                    self.value_str[start..unit_start].parse().unwrap_or(0.0),
                    Borrowed(&self.value_str[unit_start..i]),
                )))
            }
            else {
                Some(ValuePart::Number(NumberValue::from_scalar(
                    self.value_str[start..i].parse().unwrap_or(0.0)
                )))
            }
        } else if self.bytes[start] == b'$' {
            i += self.scan_while(&self.value_str[i..limit], isnt_space);
            self.offset = i;
            Some(ValuePart::Variable(Borrowed(&self.value_str[start..i])))
        } else if self.bytes[start] == b'#' {
            i += 1;
            i += self.scan_while(&self.value_str[i..limit], valid_hex_char);
            self.offset = i;
            match ColorValue::from_hex(Borrowed(&self.value_str[start..i])) {
                Ok(v) => Some(ValuePart::Color(v)),
                Err(e) => return Err(e),
            }
        } else if self.eat("rgb(") {
            let r = self.eat_color_u8();
            self.eat(",");
            self.skip_leading_whitespace();
            let g = self.eat_color_u8();
            self.eat(",");
            self.skip_leading_whitespace();
            let b = self.eat_color_u8();
            self.eat(")");

            Some(ValuePart::Color(
                ColorValue {
                    red: r, green: g, blue: b,
                    original: Borrowed(&self.value_str[start..self.offset]),
                }
            ))
        } else {
            i = start;
            i += self.scan_while(&self.value_str[start..limit], isnt_space);
            self.offset = i;
            Some(ValuePart::String(Borrowed(&self.value_str[start..i])))
        };

        Ok(ret)
    }

    fn eat_color_u8(&mut self) -> u8 {
        let limit = self.value_str.len();
        let mut i = self.offset;
        let color_start = i;

        i += self.scan_while(&self.value_str[i..limit], is_number);
        self.offset = i;
        self.value_str[color_start..i].parse().unwrap_or(0)
    }

    fn eat(&mut self, expected: &str) -> bool {
        for c in expected.as_bytes().iter() {
            if !self.eatch(c) {
                return false
            }
        }
        return true
    }

    fn eatch(&mut self, expected_char: &u8) -> bool {
        if self.bytes[self.offset] == *expected_char {
            self.offset += 1;
            true
        } else {
            false
        }
    }

    fn scan_while<F>(&mut self, data: &str, f: F) -> usize
            where F: Fn(u8) -> bool {
        match data.as_bytes().iter().position(|&c| !f(c)) {
            Some(i) => i,
            None => data.len()
        }
    }

    fn skip_leading_whitespace(&mut self) {
       let mut i = self.offset;
       let limit = self.value_str.len();

       while i < limit {
           let c = self.bytes[i];
           if is_space(c) {
               i += self.scan_while(&self.value_str[i..limit], is_space);
           } else {
               self.offset = i;
               return
           }
       }
       self.offset = limit;
   }
}

impl<'a> Iterator for ValueTokenizer<'a> {
    type Item = Result<ValuePart<'a>>;

    fn next(&mut self) -> Option<Result<ValuePart<'a>>> {
        if self.offset < self.value_str.len() {
            return match self.parse() {
                Ok(Some(v)) => Some(Ok(v)),
                Ok(None) => None,
                Err(e) => Some(Err(e)),
            }
        }
        None
    }
}

fn is_space(c: u8) -> bool {
    c == b' '
}

fn isnt_space(c: u8) -> bool {
    !is_space(c)
}

fn valid_unit_char(c: u8) -> bool {
    c == b'%' || (!is_space(c) && !is_operator(c))
}

fn valid_hex_char(c: u8) -> bool {
    match c {
        b'0' ... b'9' | b'a' ... b'f' => true,
        _ => false,
    }
}

fn is_number(c: u8) -> bool {
    let result = match c {
        b'0' ... b'9' | b'.' => true,
        _ => false,
    };
    result
}

fn is_operator(c: u8) -> bool {
    match c {
        b'+' | b'-' | b'*' | b'/' | b'%' | b'(' | b')' | b',' => true,
        _ => false,
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use sass::color_value::ColorValue;
    use sass::value_part::ValuePart;
    use sass::number_value::NumberValue;
    use sass::op::Op;
    use std::borrow::Cow::Borrowed;

    #[test]
    fn it_returns_string_part() {
        let mut vt = ValueTokenizer::new("foo");
        assert_eq!(Some(Ok(ValuePart::String(Borrowed(&"foo")))), vt.next());
        assert_eq!(None, vt.next());
    }

    #[test]
    fn it_returns_space_separated_string_parts() {
        let mut vt = ValueTokenizer::new("foo bar");
        assert_eq!(Some(Ok(ValuePart::String(Borrowed(&"foo")))), vt.next());
        assert_eq!(Some(Ok(ValuePart::String(Borrowed(&"bar")))), vt.next());
        assert_eq!(None, vt.next());
    }

    #[test]
    fn it_returns_variable() {
        let mut vt = ValueTokenizer::new("$foo");
        assert_eq!(Some(Ok(ValuePart::Variable(Borrowed(&"$foo")))), vt.next());
        assert_eq!(None, vt.next());
    }

    #[test]
    fn it_returns_variables_and_string_parts() {
        let mut vt = ValueTokenizer::new("foo $bar baz $quux");
        assert_eq!(Some(Ok(ValuePart::String(Borrowed(&"foo")))), vt.next());
        assert_eq!(Some(Ok(ValuePart::Variable(Borrowed(&"$bar")))), vt.next());
        assert_eq!(Some(Ok(ValuePart::String(Borrowed(&"baz")))), vt.next());
        assert_eq!(Some(Ok(ValuePart::Variable(Borrowed(&"$quux")))), vt.next());
        assert_eq!(None, vt.next());
    }

    #[test]
    fn it_returns_number() {
        let mut vt = ValueTokenizer::new("3");
        assert_eq!(Some(Ok(ValuePart::Number(NumberValue::from_scalar(3.0)))), vt.next());
        assert_eq!(None, vt.next());
    }

    #[test]
    fn it_returns_two_numbers() {
        let mut vt = ValueTokenizer::new("3 8.9");
        assert_eq!(Some(Ok(ValuePart::Number(NumberValue::from_scalar(3.0)))), vt.next());
        assert_eq!(Some(Ok(ValuePart::Number(NumberValue::from_scalar(8.9)))), vt.next());
        assert_eq!(None, vt.next());
    }

    #[test]
    fn it_returns_numbers_with_units() {
        let mut vt = ValueTokenizer::new("3px");
        assert_eq!(
            Some(Ok(ValuePart::Number(NumberValue::with_units(3.0, Borrowed(&"px"))))),
            vt.next()
        );
        assert_eq!(None, vt.next());
    }

    #[test]
    fn it_returns_numbers_with_units_but_not_parens() {
        let mut vt = ValueTokenizer::new("(3px)");
        assert_eq!(Some(Ok(ValuePart::Operator(Op::LeftParen))), vt.next());
        assert_eq!(
            Some(Ok(ValuePart::Number(NumberValue::with_units(3.0, Borrowed(&"px"))))),
            vt.next()
        );
        assert_eq!(Some(Ok(ValuePart::Operator(Op::RightParen))), vt.next());
        assert_eq!(None, vt.next());
    }

    #[test]
    fn it_returns_numbers_with_percents_as_units() {
        let mut vt = ValueTokenizer::new("10px 8%");
        assert_eq!(
            Some(Ok(ValuePart::Number(NumberValue::with_units(10.0, Borrowed(&"px"))))),
            vt.next()
        );
        assert_eq!(
            Some(Ok(ValuePart::Number(NumberValue::with_units(8.0, Borrowed(&"%"))))),
            vt.next()
        );
        assert_eq!(None, vt.next());
    }

    #[test]
    fn it_returns_operator() {
        let mut vt = ValueTokenizer::new("+");
        assert_eq!(Some(Ok(ValuePart::Operator(Op::Plus))), vt.next());
        assert_eq!(None, vt.next());
    }

    #[test]
    fn it_returns_numbers_and_operators() {
        let mut vt = ValueTokenizer::new("6 + 75.2");
        assert_eq!(Some(Ok(ValuePart::Number(NumberValue::from_scalar(6.0)))), vt.next());
        assert_eq!(Some(Ok(ValuePart::Operator(Op::Plus))), vt.next());
        assert_eq!(Some(Ok(ValuePart::Number(NumberValue::from_scalar(75.2)))), vt.next());
        assert_eq!(None, vt.next());
    }

    #[test]
    fn it_returns_numbers_and_operators_without_spaces() {
        let mut vt = ValueTokenizer::new("6+75.2");
        assert_eq!(Some(Ok(ValuePart::Number(NumberValue::from_scalar(6.0)))), vt.next());
        assert_eq!(Some(Ok(ValuePart::Operator(Op::Plus))), vt.next());
        assert_eq!(Some(Ok(ValuePart::Number(NumberValue::from_scalar(75.2)))), vt.next());
        assert_eq!(None, vt.next());
    }

    #[test]
    fn it_does_stuff_with_parens() {
        let mut vt = ValueTokenizer::new("2+(3 4)");
        assert_eq!(Some(Ok(ValuePart::Number(NumberValue::from_scalar(2.0)))), vt.next());
        assert_eq!(Some(Ok(ValuePart::Operator(Op::Plus))), vt.next());
        assert_eq!(Some(Ok(ValuePart::Operator(Op::LeftParen))), vt.next());
        assert_eq!(Some(Ok(ValuePart::Number(NumberValue::from_scalar(3.0)))), vt.next());
        assert_eq!(Some(Ok(ValuePart::Number(NumberValue::from_scalar(4.0)))), vt.next());
        assert_eq!(Some(Ok(ValuePart::Operator(Op::RightParen))), vt.next());
        assert_eq!(None, vt.next());
    }

    #[test]
    fn it_does_stuff_with_slash_separators() {
        let mut vt = ValueTokenizer::new("15 / 3 / 5");
        assert_eq!(Some(Ok(ValuePart::Number(NumberValue::from_scalar(15.0)))), vt.next());
        assert_eq!(Some(Ok(ValuePart::Operator(Op::Slash))), vt.next());
        assert_eq!(Some(Ok(ValuePart::Number(NumberValue::from_scalar(3.0)))), vt.next());
        assert_eq!(Some(Ok(ValuePart::Operator(Op::Slash))), vt.next());
        assert_eq!(Some(Ok(ValuePart::Number(NumberValue::from_scalar(5.0)))), vt.next());
        assert_eq!(None, vt.next());
    }

    #[test]
    fn it_recognizes_hex() {
        let mut vt = ValueTokenizer::new("#aabbcc");
        assert_eq!(
            Some(Ok(ValuePart::Color(ColorValue {
                red: 170, green: 187, blue: 204, original: Borrowed("#aabbcc"),
            }))),
            vt.next()
        );
        assert_eq!(None, vt.next());
    }

    #[test]
    fn it_recognizes_short_hex() {
        let mut vt = ValueTokenizer::new("#cba");
        assert_eq!(
            Some(Ok(ValuePart::Color(ColorValue {
                red: 204, green: 187, blue: 170, original: Borrowed("#cba"),
            }))),
            vt.next()
        );
        assert_eq!(None, vt.next());
    }

    #[test]
    fn it_recognizes_hex_is_separate_from_parens() {
        let mut vt = ValueTokenizer::new("#cba)");
        assert_eq!(
            Some(Ok(ValuePart::Color(ColorValue {
                red: 204, green: 187, blue: 170, original: Borrowed("#cba"),
            }))),
            vt.next()
        );
        assert_eq!(Some(Ok(ValuePart::Operator(Op::RightParen))), vt.next());
        assert_eq!(None, vt.next());
    }

    #[test]
    fn it_recognizes_rgb() {
        let mut vt = ValueTokenizer::new("rgb(10,100,73)");
        assert_eq!(
            Some(Ok(ValuePart::Color(ColorValue {
                red: 10, green: 100, blue: 73, original: Borrowed("rgb(10,100,73)"),
            }))),
            vt.next()
        );
        assert_eq!(None, vt.next());
    }

    #[test]
    fn it_recognizes_rgb_with_spaces() {
        let mut vt = ValueTokenizer::new("rgb(10, 100, 73)");
        assert_eq!(
            Some(Ok(ValuePart::Color(ColorValue {
                red: 10, green: 100, blue: 73, original: Borrowed("rgb(10, 100, 73)"),
            }))),
            vt.next()
        );
        assert_eq!(None, vt.next());
    }
}
<|endoftext|>


<commit_before>//! # The Rust Core Library
//!
//! The Rust Core Library is the dependency-free[^free] foundation of [The
//! Rust Standard Library](../std/index.html). It is the portable glue
//! between the language and its libraries, defining the intrinsic and
//! primitive building blocks of all Rust code. It links to no
//! upstream libraries, no system libraries, and no libc.
//!
//! [^free]: Strictly speaking, there are some symbols which are needed but
//!          they aren't always necessary.
//!
//! The core library is *minimal*: it isn't even aware of heap allocation,
//! nor does it provide concurrency or I/O. These things require
//! platform integration, and this library is platform-agnostic.
//!
//! # How to use the core library
//!
//! Please note that all of these details are currently not considered stable.
//!
// FIXME: Fill me in with more detail when the interface settles
//! This library is built on the assumption of a few existing symbols:
//!
//! * `memcpy`, `memcmp`, `memset` - These are core memory routines which are
//!   often generated by LLVM. Additionally, this library can make explicit
//!   calls to these functions. Their signatures are the same as found in C.
//!   These functions are often provided by the system libc, but can also be
//!   provided by the [compiler-builtins crate](https://crates.io/crates/compiler_builtins).
//!
//! * `rust_begin_panic` - This function takes four arguments, a
//!   `fmt::Arguments`, a `&'static str`, and two `u32`'s. These four arguments
//!   dictate the panic message, the file at which panic was invoked, and the
//!   line and column inside the file. It is up to consumers of this core
//!   library to define this panic function; it is only required to never
//!   return. This requires a `lang` attribute named `panic_impl`.
//!
//! * `rust_eh_personality` - is used by the failure mechanisms of the
//!    compiler. This is often mapped to GCC's personality function, but crates
//!    which do not trigger a panic can be assured that this function is never
//!    called. The `lang` attribute is called `eh_personality`.

// Since libcore defines many fundamental lang items, all tests live in a
// separate crate, libcoretest, to avoid bizarre issues.
//
// Here we explicitly #[cfg]-out this whole crate when testing. If we don't do
// this, both the generated test artifact and the linked libtest (which
// transitively includes libcore) will both define the same set of lang items,
// and this will cause the E0152 "duplicate lang item found" error. See
// discussion in #50466 for details.
//
// This cfg won't affect doc tests.
#![cfg(not(test))]

#![stable(feature = "core", since = "1.6.0")]
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/",
       html_playground_url = "https://play.rust-lang.org/",
       issue_tracker_base_url = "https://github.com/rust-lang/rust/issues/",
       test(no_crate_inject, attr(deny(warnings))),
       test(attr(allow(dead_code, deprecated, unused_variables, unused_mut))))]
#![no_core]

#![warn(deprecated_in_future)]
#![warn(missing_docs)]
#![warn(missing_debug_implementations)]
#![deny(intra_doc_link_resolution_failure)] // rustdoc is run without -D warnings
#![allow(explicit_outlives_requirements)]
#![allow(incomplete_features)]

#![feature(allow_internal_unstable)]
#![feature(arbitrary_self_types)]
#![feature(asm)]
#![feature(bound_cloned)]
#![feature(cfg_target_has_atomic)]
#![feature(concat_idents)]
#![feature(const_fn)]
#![feature(const_fn_union)]
#![feature(const_generics)]
#![feature(custom_inner_attributes)]
#![feature(decl_macro)]
#![feature(doc_cfg)]
#![feature(doc_spotlight)]
#![feature(extern_types)]
#![feature(fundamental)]
#![feature(intrinsics)]
#![feature(is_sorted)]
#![feature(iter_once_with)]
#![feature(lang_items)]
#![feature(link_llvm_intrinsics)]
#![feature(never_type)]
#![feature(nll)]
#![feature(exhaustive_patterns)]
#![feature(no_core)]
#![feature(on_unimplemented)]
#![feature(optin_builtin_traits)]
#![feature(prelude_import)]
#![feature(repr_simd, platform_intrinsics)]
#![feature(rustc_attrs)]
#![feature(rustc_const_unstable)]
#![feature(simd_ffi)]
#![feature(specialization)]
#![feature(staged_api)]
#![feature(std_internals)]
#![feature(stmt_expr_attributes)]
#![feature(transparent_unions)]
#![feature(unboxed_closures)]
#![feature(unsized_locals)]
#![feature(untagged_unions)]
#![feature(unwind_attributes)]
#![feature(doc_alias)]
#![feature(mmx_target_feature)]
#![feature(tbm_target_feature)]
#![feature(sse4a_target_feature)]
#![feature(arm_target_feature)]
#![feature(powerpc_target_feature)]
#![feature(mips_target_feature)]
#![feature(aarch64_target_feature)]
#![feature(wasm_target_feature)]
#![feature(avx512_target_feature)]
#![feature(cmpxchg16b_target_feature)]
#![feature(rtm_target_feature)]
#![feature(f16c_target_feature)]
#![feature(hexagon_target_feature)]
#![feature(const_int_conversion)]
#![feature(const_transmute)]
#![cfg_attr(bootstrap, feature(non_exhaustive))]
#![feature(structural_match)]
#![feature(abi_unadjusted)]
#![feature(adx_target_feature)]
#![feature(maybe_uninit_slice)]
#![feature(external_doc)]
#![feature(associated_type_bounds)]

#[prelude_import]
#[allow(unused)]
use prelude::v1::*;

#[macro_use]
mod macros;

#[macro_use]
mod internal_macros;

#[path = "num/int_macros.rs"]
#[macro_use]
mod int_macros;

#[path = "num/uint_macros.rs"]
#[macro_use]
mod uint_macros;

#[path = "num/isize.rs"] pub mod isize;
#[path = "num/i8.rs"]    pub mod i8;
#[path = "num/i16.rs"]   pub mod i16;
#[path = "num/i32.rs"]   pub mod i32;
#[path = "num/i64.rs"]   pub mod i64;
#[path = "num/i128.rs"]  pub mod i128;

#[path = "num/usize.rs"] pub mod usize;
#[path = "num/u8.rs"]    pub mod u8;
#[path = "num/u16.rs"]   pub mod u16;
#[path = "num/u32.rs"]   pub mod u32;
#[path = "num/u64.rs"]   pub mod u64;
#[path = "num/u128.rs"]  pub mod u128;

#[path = "num/f32.rs"]   pub mod f32;
#[path = "num/f64.rs"]   pub mod f64;

#[macro_use]
pub mod num;

/* The libcore prelude, not as all-encompassing as the libstd prelude */

pub mod prelude;

/* Core modules for ownership management */

pub mod intrinsics;
pub mod mem;
pub mod ptr;
pub mod hint;

/* Core language traits */

pub mod marker;
pub mod ops;
pub mod cmp;
pub mod clone;
pub mod default;
pub mod convert;
pub mod borrow;

/* Core types and methods on primitives */

pub mod any;
pub mod array;
pub mod ascii;
pub mod sync;
pub mod cell;
pub mod char;
pub mod panic;
pub mod panicking;
pub mod pin;
pub mod iter;
pub mod option;
pub mod raw;
pub mod result;
pub mod ffi;

pub mod slice;
pub mod str;
pub mod hash;
pub mod fmt;
pub mod time;

pub mod unicode;

/* Async */
pub mod future;
pub mod task;

/* Heap memory allocator trait */
#[allow(missing_docs)]
pub mod alloc;

// note: does not need to be public
mod bool;
mod tuple;
mod unit;

// Pull in the `core_arch` crate directly into libcore. The contents of
// `core_arch` are in a different repository: rust-lang/stdarch.
//
// `core_arch` depends on libcore, but the contents of this module are
// set up in such a way that directly pulling it here works such that the
// crate uses the this crate as its libcore.
#[path = "../stdarch/crates/core_arch/src/mod.rs"]
#[allow(missing_docs, missing_debug_implementations, dead_code, unused_imports)]
#[unstable(feature = "stdsimd", issue = "48556")]
mod core_arch;

#[stable(feature = "simd_arch", since = "1.27.0")]
pub use core_arch::arch;
<commit_msg>work around aggressive syntax feature gating<commit_after>//! # The Rust Core Library
//!
//! The Rust Core Library is the dependency-free[^free] foundation of [The
//! Rust Standard Library](../std/index.html). It is the portable glue
//! between the language and its libraries, defining the intrinsic and
//! primitive building blocks of all Rust code. It links to no
//! upstream libraries, no system libraries, and no libc.
//!
//! [^free]: Strictly speaking, there are some symbols which are needed but
//!          they aren't always necessary.
//!
//! The core library is *minimal*: it isn't even aware of heap allocation,
//! nor does it provide concurrency or I/O. These things require
//! platform integration, and this library is platform-agnostic.
//!
//! # How to use the core library
//!
//! Please note that all of these details are currently not considered stable.
//!
// FIXME: Fill me in with more detail when the interface settles
//! This library is built on the assumption of a few existing symbols:
//!
//! * `memcpy`, `memcmp`, `memset` - These are core memory routines which are
//!   often generated by LLVM. Additionally, this library can make explicit
//!   calls to these functions. Their signatures are the same as found in C.
//!   These functions are often provided by the system libc, but can also be
//!   provided by the [compiler-builtins crate](https://crates.io/crates/compiler_builtins).
//!
//! * `rust_begin_panic` - This function takes four arguments, a
//!   `fmt::Arguments`, a `&'static str`, and two `u32`'s. These four arguments
//!   dictate the panic message, the file at which panic was invoked, and the
//!   line and column inside the file. It is up to consumers of this core
//!   library to define this panic function; it is only required to never
//!   return. This requires a `lang` attribute named `panic_impl`.
//!
//! * `rust_eh_personality` - is used by the failure mechanisms of the
//!    compiler. This is often mapped to GCC's personality function, but crates
//!    which do not trigger a panic can be assured that this function is never
//!    called. The `lang` attribute is called `eh_personality`.

// Since libcore defines many fundamental lang items, all tests live in a
// separate crate, libcoretest, to avoid bizarre issues.
//
// Here we explicitly #[cfg]-out this whole crate when testing. If we don't do
// this, both the generated test artifact and the linked libtest (which
// transitively includes libcore) will both define the same set of lang items,
// and this will cause the E0152 "duplicate lang item found" error. See
// discussion in #50466 for details.
//
// This cfg won't affect doc tests.
#![cfg(not(test))]

#![stable(feature = "core", since = "1.6.0")]
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/",
       html_playground_url = "https://play.rust-lang.org/",
       issue_tracker_base_url = "https://github.com/rust-lang/rust/issues/",
       test(no_crate_inject, attr(deny(warnings))),
       test(attr(allow(dead_code, deprecated, unused_variables, unused_mut))))]
#![no_core]

#![warn(deprecated_in_future)]
#![warn(missing_docs)]
#![warn(missing_debug_implementations)]
#![deny(intra_doc_link_resolution_failure)] // rustdoc is run without -D warnings
#![allow(explicit_outlives_requirements)]
#![allow(incomplete_features)]

#![feature(allow_internal_unstable)]
#![feature(arbitrary_self_types)]
#![feature(asm)]
#![feature(bound_cloned)]
#![feature(cfg_target_has_atomic)]
#![feature(concat_idents)]
#![feature(const_fn)]
#![feature(const_fn_union)]
#![feature(const_generics)]
#![feature(custom_inner_attributes)]
#![feature(decl_macro)]
#![feature(doc_cfg)]
#![feature(doc_spotlight)]
#![feature(extern_types)]
#![feature(fundamental)]
#![feature(intrinsics)]
#![feature(is_sorted)]
#![feature(iter_once_with)]
#![feature(lang_items)]
#![feature(link_llvm_intrinsics)]
#![feature(never_type)]
#![feature(nll)]
#![feature(exhaustive_patterns)]
#![feature(no_core)]
#![feature(on_unimplemented)]
#![feature(optin_builtin_traits)]
#![feature(prelude_import)]
#![feature(repr_simd, platform_intrinsics)]
#![feature(rustc_attrs)]
#![feature(rustc_const_unstable)]
#![feature(simd_ffi)]
#![feature(specialization)]
#![feature(staged_api)]
#![feature(std_internals)]
#![feature(stmt_expr_attributes)]
#![feature(transparent_unions)]
#![feature(unboxed_closures)]
#![feature(unsized_locals)]
#![feature(untagged_unions)]
#![feature(unwind_attributes)]
#![feature(doc_alias)]
#![feature(mmx_target_feature)]
#![feature(tbm_target_feature)]
#![feature(sse4a_target_feature)]
#![feature(arm_target_feature)]
#![feature(powerpc_target_feature)]
#![feature(mips_target_feature)]
#![feature(aarch64_target_feature)]
#![feature(wasm_target_feature)]
#![feature(avx512_target_feature)]
#![feature(cmpxchg16b_target_feature)]
#![feature(rtm_target_feature)]
#![feature(f16c_target_feature)]
#![feature(hexagon_target_feature)]
#![feature(const_int_conversion)]
#![feature(const_transmute)]
#![cfg_attr(bootstrap, feature(non_exhaustive))]
#![feature(structural_match)]
#![feature(abi_unadjusted)]
#![feature(adx_target_feature)]
#![feature(maybe_uninit_slice)]
#![feature(external_doc)]
#![feature(associated_type_bounds)]

#[prelude_import]
#[allow(unused)]
use prelude::v1::*;

#[cfg(not(test))] // See #65860
#[macro_use]
mod macros;

#[macro_use]
mod internal_macros;

#[path = "num/int_macros.rs"]
#[macro_use]
mod int_macros;

#[path = "num/uint_macros.rs"]
#[macro_use]
mod uint_macros;

#[path = "num/isize.rs"] pub mod isize;
#[path = "num/i8.rs"]    pub mod i8;
#[path = "num/i16.rs"]   pub mod i16;
#[path = "num/i32.rs"]   pub mod i32;
#[path = "num/i64.rs"]   pub mod i64;
#[path = "num/i128.rs"]  pub mod i128;

#[path = "num/usize.rs"] pub mod usize;
#[path = "num/u8.rs"]    pub mod u8;
#[path = "num/u16.rs"]   pub mod u16;
#[path = "num/u32.rs"]   pub mod u32;
#[path = "num/u64.rs"]   pub mod u64;
#[path = "num/u128.rs"]  pub mod u128;

#[path = "num/f32.rs"]   pub mod f32;
#[path = "num/f64.rs"]   pub mod f64;

#[macro_use]
pub mod num;

/* The libcore prelude, not as all-encompassing as the libstd prelude */

pub mod prelude;

/* Core modules for ownership management */

pub mod intrinsics;
pub mod mem;
pub mod ptr;
pub mod hint;

/* Core language traits */

#[cfg(not(test))] // See #65860
pub mod marker;
pub mod ops;
#[cfg(not(test))] // See #65860
pub mod cmp;
#[cfg(not(test))] // See #65860
pub mod clone;
#[cfg(not(test))] // See #65860
pub mod default;
pub mod convert;
pub mod borrow;

/* Core types and methods on primitives */

pub mod any;
#[cfg(not(test))] // See #65860
pub mod array;
pub mod ascii;
pub mod sync;
pub mod cell;
pub mod char;
pub mod panic;
pub mod panicking;
#[cfg(not(test))] // See #65860
pub mod pin;
#[cfg(not(test))] // See #65860
pub mod iter;
pub mod option;
pub mod raw;
pub mod result;
pub mod ffi;

pub mod slice;
#[cfg(not(test))] // See #65860
pub mod str;
#[cfg(not(test))] // See #65860
pub mod hash;
#[cfg(not(test))] // See #65860
pub mod fmt;
pub mod time;

pub mod unicode;

/* Async */
#[cfg(not(test))] // See #65860
pub mod future;
pub mod task;

/* Heap memory allocator trait */
#[allow(missing_docs)]
pub mod alloc;

// note: does not need to be public
mod bool;
mod tuple;
mod unit;

// Pull in the `core_arch` crate directly into libcore. The contents of
// `core_arch` are in a different repository: rust-lang/stdarch.
//
// `core_arch` depends on libcore, but the contents of this module are
// set up in such a way that directly pulling it here works such that the
// crate uses the this crate as its libcore.
#[path = "../stdarch/crates/core_arch/src/mod.rs"]
#[allow(missing_docs, missing_debug_implementations, dead_code, unused_imports)]
#[unstable(feature = "stdsimd", issue = "48556")]
mod core_arch;

#[stable(feature = "simd_arch", since = "1.27.0")]
pub use core_arch::arch;
<|endoftext|>


<commit_before>use chrono::NaiveTime;

const STEFAN_BOLTZMANN_CONSTANT: f64 = 5.670367 / 100_000_000.0;

pub fn kelvin_to_celcius(k: f64) -> f64 {
    k - 273.15
}

pub fn kelvin_temperature(albedo: f64,
                          emissivity: f64,
                          solar_radiation_watt_per_square_meter: f64)
                          -> f64 {
    assert!(0.0 <= albedo && albedo <= 1.0);
    assert!(0.0 <= emissivity && emissivity <= 1.0);

    (((1.0 - albedo) * solar_radiation_watt_per_square_meter) /
     (4.0 * emissivity * STEFAN_BOLTZMANN_CONSTANT))
        .powf(1.0 / 4.0)
}

// WIP

// need day_of_year()
// -> .ordinal() (1-indexed)

// l'ensoleillement (insolation, english) est une mesure d'énergie
// l'irradiance (irradiance, english) est une mesure de puissance

/// Irradiance d'un point, en Watts par mètre carré, en fonction de la masse d'air
/// devant être traversée par les rayons du Soleil.
pub fn irradiance(air_mass: f64) -> f64 {
    1.353 * 0.7f64.powf(air_mass.powf(0.678))
}

pub fn air_mass(zenith_angle: f64) -> f64 {
    1.0 / zenith_angle.cos()
}

/// Angle zénithal en fonction de l'angle d'élévation.
pub fn zenith_angle(elevation_angle: f64) -> f64 {
    90.0 - elevation_angle
}

/// Angle d'élévation en fonction de l'angle de déclinaison, de la latitude et de l'angle horaire.
pub fn elevation_angle(declination_angle: f64, latitude: f64, hour_angle: f64) -> f64 {
    (declination_angle.sin() * latitude.sin() +
     declination_angle.cos() * latitude.cos() * hour_angle.cos())
        .asin()
}

/// Angle de déclinaison en fonction du jour de l'année.
pub fn declination_angle(day_of_year: u32) -> f64 {
    assert!(1 <= day_of_year && day_of_year <= 366); // leap years

    (23.45f64.sin() * ((360.0 / 365.0) * (day_of_year - 81) as f64).sin()).asin()
}

/// Angle horaire en fonction de l'heure solaire.
pub fn hour_angle(solar_time: f64) -> f64 {
    15.0 * (solar_time - 12.0)
}

/// Heure solaire en fonction de l'heure locale et du facteur de correction de l'heure.
pub fn solar_time(local_time: f64, time_correction_factor: f64) -> f64 {
    local_time + time_correction_factor / 60.0
}

/// Facteur de correction de l'heure en fonction de la longitude du point étudié,
/// de la longitude du méridien standard local et de l'équation du temps.
pub fn time_correction_factor(longitude: f64,
                              local_standard_meridian_longitude: f64,
                              equation_of_time: f64)
                              -> f64 {
    4.0 * (longitude - local_standard_meridian_longitude) + equation_of_time
}

/// Équation du temps en fonction du jour de l'année.
pub fn equation_of_time(day_of_year: u32) -> f64 {
    let b = (360.0 / 365.0) * (day_of_year - 81) as f64;
    9.87 * (2.0 * b).sin() - 7.53 * b.cos() - 1.5 * b.sin()
}
<commit_msg>update kelvin_temperature()<commit_after>use chrono::NaiveTime;

const STEFAN_BOLTZMANN_CONSTANT: f64 = 5.670367 / 100_000_000.0;

pub fn kelvin_to_celcius(k: f64) -> f64 {
    k - 273.15
}

/// Température, en kelvins, d'un objet, en fonction de son albedo, de son émissivité
/// et de son irradiance par le Soleil.
pub fn kelvin_temperature(albedo: f64, emissivity: f64, irradiance: f64) -> f64 {
    assert!(0.0 <= albedo && albedo <= 1.0);
    assert!(0.0 <= emissivity && emissivity <= 1.0);

    (((1.0 - albedo) * irradiance) / (4.0 * emissivity * STEFAN_BOLTZMANN_CONSTANT)).powf(1.0 / 4.0)
}

// WIP

// need day_of_year()
// -> .ordinal() (1-indexed)

// l'ensoleillement (insolation, english) est une mesure d'énergie
// l'irradiance (irradiance, english) est une mesure de puissance

/// Irradiance d'un point, en Watts par mètre carré, en fonction de la masse d'air
/// devant être traversée par les rayons du Soleil.
pub fn irradiance(air_mass: f64) -> f64 {
    1.353 * 0.7f64.powf(air_mass.powf(0.678))
}

pub fn air_mass(zenith_angle: f64) -> f64 {
    1.0 / zenith_angle.cos()
}

/// Angle zénithal en fonction de l'angle d'élévation.
pub fn zenith_angle(elevation_angle: f64) -> f64 {
    90.0 - elevation_angle
}

/// Angle d'élévation en fonction de l'angle de déclinaison, de la latitude et de l'angle horaire.
pub fn elevation_angle(declination_angle: f64, latitude: f64, hour_angle: f64) -> f64 {
    (declination_angle.sin() * latitude.sin() +
     declination_angle.cos() * latitude.cos() * hour_angle.cos())
        .asin()
}

/// Angle de déclinaison en fonction du jour de l'année.
pub fn declination_angle(day_of_year: u32) -> f64 {
    assert!(1 <= day_of_year && day_of_year <= 366); // leap years

    (23.45f64.sin() * ((360.0 / 365.0) * (day_of_year - 81) as f64).sin()).asin()
}

/// Angle horaire en fonction de l'heure solaire.
pub fn hour_angle(solar_time: f64) -> f64 {
    15.0 * (solar_time - 12.0)
}

/// Heure solaire en fonction de l'heure locale et du facteur de correction de l'heure.
pub fn solar_time(local_time: f64, time_correction_factor: f64) -> f64 {
    local_time + time_correction_factor / 60.0
}

/// Facteur de correction de l'heure en fonction de la longitude du point étudié,
/// de la longitude du méridien standard local et de l'équation du temps.
pub fn time_correction_factor(longitude: f64,
                              local_standard_meridian_longitude: f64,
                              equation_of_time: f64)
                              -> f64 {
    4.0 * (longitude - local_standard_meridian_longitude) + equation_of_time
}

/// Équation du temps en fonction du jour de l'année.
pub fn equation_of_time(day_of_year: u32) -> f64 {
    let b = (360.0 / 365.0) * (day_of_year - 81) as f64;
    9.87 * (2.0 * b).sin() - 7.53 * b.cos() - 1.5 * b.sin()
}
<|endoftext|>


<commit_before>use crate::config::EnvConfig;
use crate::error::ErrorKind;
use std::env;

#[test]
fn invalid_env_value() {
    let vars = vec![("GIT_BRWS_GHE_SSH_PORT".to_string(), "hello".to_string())];
    match EnvConfig::from_iter(vars.into_iter()).unwrap_err().kind() {
        ErrorKind::EnvLoadError(e) => {
            let msg = format!("{}", e);
            assert!(msg.contains("invalid digit found in string"), "{}", msg);
        }
        err => assert!(false, "Unexpected error: {}", err),
    }
}

#[test]
fn with_global_env() {
    let iter = [
        ("GIT_BRWS_GHE_TOKEN", "token for ghe"),
        ("GIT_BRWS_GITHUB_TOKEN", "token for github"),
        ("GIT_BRWS_SHORT_COMMIT_HASH", "true"),
    ]
    .iter()
    .map(|(k, v)| (k.to_string(), v.to_string()));
    let env = EnvConfig::from_iter(iter).unwrap().with_global_env();

    assert_eq!(env.git_command, "git");
    assert_eq!(env.gitlab_ssh_port, None);
    assert_eq!(env.ghe_token.unwrap(), "token for ghe");
    assert!(env.short_commit_hash);

    // $GITHUB_TOKEN is never used since $GIT_BRWS_GITHUB_TOKEN is prioritized
    //
    // XXX: This test is risky since when it does not work the token is exposed though the token
    // does not have any permission except for boosting API rate limit.
    assert_eq!(env.github_token.unwrap(), "token for github");

    let https_proxy = env::var("GIT_BRWS_HTTPS_PROXY")
        .or_else(|_| env::var("https_proxy"))
        .or_else(|_| env::var("HTTPS_PROXY"))
        .ok();
    assert_eq!(env.https_proxy, https_proxy);
}
<commit_msg>add tests for updating config variables from environment variables<commit_after>use crate::config::EnvConfig;
use crate::error::ErrorKind;
use crate::test::helper::empty_env;
use std::env;

#[test]
fn invalid_env_value() {
    let vars = vec![("GIT_BRWS_GHE_SSH_PORT".to_string(), "hello".to_string())];
    match EnvConfig::from_iter(vars.into_iter()).unwrap_err().kind() {
        ErrorKind::EnvLoadError(e) => {
            let msg = format!("{}", e);
            assert!(msg.contains("invalid digit found in string"), "{}", msg);
        }
        err => assert!(false, "Unexpected error: {}", err),
    }
}

#[test]
fn with_global_env() {
    let iter = [
        ("GIT_BRWS_GHE_TOKEN", "token for ghe"),
        ("GIT_BRWS_GITHUB_TOKEN", "token for github"),
        ("GIT_BRWS_SHORT_COMMIT_HASH", "true"),
    ]
    .iter()
    .map(|(k, v)| (k.to_string(), v.to_string()));
    let env = EnvConfig::from_iter(iter).unwrap().with_global_env();

    assert_eq!(env.git_command, "git");
    assert_eq!(env.gitlab_ssh_port, None);
    assert_eq!(env.ghe_token.unwrap(), "token for ghe");
    assert!(env.short_commit_hash);

    // $GITHUB_TOKEN is never used since $GIT_BRWS_GITHUB_TOKEN is prioritized
    //
    // XXX: This test is risky since when it does not work the token is exposed though the token
    // does not have any permission except for boosting API rate limit.
    assert_eq!(env.github_token.unwrap(), "token for github");

    let https_proxy = env::var("GIT_BRWS_HTTPS_PROXY")
        .or_else(|_| env::var("https_proxy"))
        .or_else(|_| env::var("HTTPS_PROXY"))
        .ok();
    assert_eq!(env.https_proxy, https_proxy);
}

#[test]
fn with_global_env_updates_none_values() {
    let env = empty_env().with_global_env();
    let https_proxy = env::var("https_proxy")
        .or_else(|_| env::var("HTTPS_PROXY"))
        .ok();
    let github_token = env::var("GITHUB_TOKEN").ok();
    assert_eq!(env.https_proxy, https_proxy);
    assert_eq!(env.github_token, github_token);
}
<|endoftext|>