<commit_before>use std::collections::BinaryHeap;

// https://leetcode.com/problems/jump-game-vi/
pub fn max_result(nums: Vec<i32>, k: i32) -> i32 {
    // fn f(nums: &Vec<i32>, k: i32, index: i32, memo: &mut Vec<i32>) -> i32 {
    //     if index == nums.len() as i32 - 1 {
    //         return nums[index as usize];
    //     }
    //     if memo[index as usize] != i32::MIN {
    //         return memo[index as usize];
    //     }
    //     let mut max = i32::MIN;
    //     for i in (index + 1)..=(nums.len() as i32 - 1).min(index + k) {
    //         let mut x = f(nums, k, i, memo);
    //         if x != i32::MIN {
    //             x += nums[index as usize];
    //         }
    //         max = max.max(x);
    //     }
    //     memo[index as usize] = max;
    //     max
    // }
    //
    // f(&nums, k, 0, &mut vec![i32::MIN; nums.len()])

    let mut dp = vec![i32::MIN; nums.len()];
    dp[0] = nums[0];
    let mut heap: BinaryHeap<(i32, i32)> = BinaryHeap::new();
    heap.push((dp[0], 0));
    for i in 1..nums.len() {
        while !heap.is_empty() && i as i32 - (*heap.peek().unwrap()).1 > k {
            heap.pop();
        }
        let max = heap.peek().unwrap();
        dp[i] = dp[i].max(nums[i] + dp[max.1 as usize]);
        heap.push((dp[i], i as i32));
    }
    dp[dp.len() - 1]
}

fn main() {
    println!("{}", max_result(vec![1, -1, -2, 4, -7, 3], 2)); // 7
    println!("{}", max_result(vec![10, -5, -2, 4, 0, 3], 3)); // 17
    println!("{}", max_result(vec![1, -5, -20, 4, -1, 3, -6, -3], 2)); // 0
    println!("{}", max_result(vec![3, -6, -3], 2)); // 0
}
<commit_msg>Solve problem 1696<commit_after>use std::collections::BinaryHeap;

// https://leetcode.com/problems/jump-game-vi/
pub fn max_result(nums: Vec<i32>, k: i32) -> i32 {
    let mut dp = vec![i32::MIN; nums.len()];
    dp[0] = nums[0];
    let mut heap: BinaryHeap<(i32, i32)> = BinaryHeap::new();
    heap.push((dp[0], 0));
    for i in 1..nums.len() {
        while !heap.is_empty() && i as i32 - (*heap.peek().unwrap()).1 > k {
            heap.pop();
        }
        let max = heap.peek().unwrap();
        dp[i] = dp[i].max(nums[i] + dp[max.1 as usize]);
        heap.push((dp[i], i as i32));
    }
    dp[dp.len() - 1]
}

fn main() {
    println!("{}", max_result(vec![1, -1, -2, 4, -7, 3], 2)); // 7
    println!("{}", max_result(vec![10, -5, -2, 4, 0, 3], 3)); // 17
    println!("{}", max_result(vec![1, -5, -20, 4, -1, 3, -6, -3], 2)); // 0
    println!("{}", max_result(vec![3, -6, -3], 2)); // 0
}
<|endoftext|>


<commit_before>// https://leetcode.com/problems/minimum-number-of-operations-to-sort-a-binary-tree-by-level/
use std::cell::RefCell;
use std::collections::VecDeque;
use std::rc::Rc;

#[derive(Debug, PartialEq, Eq)]
pub struct TreeNode {
    pub val: i32,
    pub left: Option<Rc<RefCell<TreeNode>>>,
    pub right: Option<Rc<RefCell<TreeNode>>>,
}

impl TreeNode {
    #[inline]
    pub fn new(val: i32) -> Self {
        TreeNode {
            val,
            left: None,
            right: None,
        }
    }
}

pub fn minimum_operations(root: Option<Rc<RefCell<TreeNode>>>) -> i32 {
    todo!()
}

fn main() {
    fn create_node(value: i32) -> Option<Rc<RefCell<TreeNode>>> {
        Some(Rc::new(RefCell::new(TreeNode::new(value))))
    }

    fn add_left(
        parent: &Option<Rc<RefCell<TreeNode>>>,
        value: i32,
    ) -> Option<Rc<RefCell<TreeNode>>> {
        parent.as_ref().unwrap().as_ref().borrow_mut().left = create_node(value);
        parent.as_ref().unwrap().as_ref().borrow().left.clone()
    }

    fn add_right(
        parent: &Option<Rc<RefCell<TreeNode>>>,
        value: i32,
    ) -> Option<Rc<RefCell<TreeNode>>> {
        parent.as_ref().unwrap().as_ref().borrow_mut().right = create_node(value);
        parent.as_ref().unwrap().as_ref().borrow().right.clone()
    }

    fn to_tree(nodes: Vec<Option<i32>>) -> Option<Rc<RefCell<TreeNode>>> {
        let mut deque: VecDeque<Option<Rc<RefCell<TreeNode>>>> = VecDeque::new();
        let root = create_node(nodes[0].unwrap());
        deque.push_back(root.clone());
        let mut i = 1;
        while i < nodes.len() {
            let parent = deque.pop_front().unwrap();
            let mut has_left = false;
            if let Some(left) = nodes[i] {
                deque.push_back(add_left(&parent, left));
                has_left = true;
            }
            let mut has_right = false;
            if i + 1 < nodes.len() {
                if let Some(right) = nodes[i + 1] {
                    deque.push_back(add_right(&parent, right));
                    has_right = true;
                }
            }
            if !has_left && !has_right {
                deque.push_back(parent);
            }
            i += 2;
        }
        root
    }

    println!(
        "{}",
        minimum_operations(to_tree(vec![
            Some(1),
            Some(4),
            Some(3),
            Some(7),
            Some(6),
            Some(8),
            Some(5),
            None,
            None,
            None,
            None,
            Some(9),
            None,
            Some(10)
        ]))
    ); // 3
    println!(
        "{}",
        minimum_operations(to_tree(vec![
            Some(1),
            Some(3),
            Some(2),
            Some(7),
            Some(6),
            Some(5),
            Some(4)
        ]))
    ); // 3
    println!(
        "{}",
        minimum_operations(to_tree(vec![
            Some(1),
            Some(2),
            Some(3),
            Some(4),
            Some(5),
            Some(6)
        ]))
    ); // 0
}
<commit_msg>Update problem 2471<commit_after>// https://leetcode.com/problems/minimum-number-of-operations-to-sort-a-binary-tree-by-level/
use std::cell::RefCell;
use std::collections::VecDeque;
use std::rc::Rc;

#[derive(Debug, PartialEq, Eq)]
pub struct TreeNode {
    pub val: i32,
    pub left: Option<Rc<RefCell<TreeNode>>>,
    pub right: Option<Rc<RefCell<TreeNode>>>,
}

impl TreeNode {
    #[inline]
    pub fn new(val: i32) -> Self {
        TreeNode {
            val,
            left: None,
            right: None,
        }
    }
}

pub fn minimum_operations(root: Option<Rc<RefCell<TreeNode>>>) -> i32 {
    todo!()
}

fn main() {
    fn create_node(value: i32) -> Option<Rc<RefCell<TreeNode>>> {
        Some(Rc::new(RefCell::new(TreeNode::new(value))))
    }

    fn add_left(
        parent: &Option<Rc<RefCell<TreeNode>>>,
        value: i32,
    ) -> Option<Rc<RefCell<TreeNode>>> {
        parent.as_ref().unwrap().as_ref().borrow_mut().left = create_node(value);
        parent.as_ref().unwrap().as_ref().borrow().left.clone()
    }

    fn add_right(
        parent: &Option<Rc<RefCell<TreeNode>>>,
        value: i32,
    ) -> Option<Rc<RefCell<TreeNode>>> {
        parent.as_ref().unwrap().as_ref().borrow_mut().right = create_node(value);
        parent.as_ref().unwrap().as_ref().borrow().right.clone()
    }

    fn to_tree(nodes: Vec<Option<i32>>) -> Option<Rc<RefCell<TreeNode>>> {
        let mut deque: VecDeque<Option<Rc<RefCell<TreeNode>>>> = VecDeque::new();
        let root = create_node(nodes[0].unwrap());
        deque.push_back(root.clone());
        let mut i = 1;
        while i < nodes.len() {
            let parent = deque.pop_front().unwrap();
            let mut has_left = false;
            if let Some(left) = nodes[i] {
                deque.push_back(add_left(&parent, left));
                has_left = true;
            }
            let mut has_right = false;
            if i + 1 < nodes.len() {
                if let Some(right) = nodes[i + 1] {
                    deque.push_back(add_right(&parent, right));
                    has_right = true;
                }
            }
            if !has_left && !has_right {
                deque.push_back(parent);
            }
            i += 2;
        }
        root
    }

    println!(
        "{}",
        minimum_operations(to_tree(vec![
            Some(1),
            Some(4),
            Some(3),
            Some(7),
            Some(6),
            Some(8),
            Some(5),
            None,
            None,
            None,
            None,
            Some(9),
            None,
            Some(10)
        ]))
    ); // 3
    println!(
        "{}",
        minimum_operations(to_tree(vec![
            Some(1),
            Some(3),
            Some(2),
            Some(7),
            Some(6),
            Some(5),
            Some(4)
        ]))
    ); // 3
    println!(
        "{}",
        minimum_operations(to_tree(vec![
            Some(1),
            Some(2),
            Some(3),
            Some(4),
            Some(5),
            Some(6)
        ]))
    ); // 0
    println!(
        "{}",
        minimum_operations(to_tree(vec![
            Some(9),
            Some(4),
            Some(5),
            Some(3),
            Some(7),
            Some(8)
        ]))
    ); // 0
}
<|endoftext|>


<commit_before>use config::action::ActionType;
use config::Context;
use serde::de::{Deserialize, Deserializer, MapVisitor, Error, Visitor};

use handlebars::Template;
use uuid::Uuid;

const FIELDS: &'static [&'static str] = &["name", "uuid", "conditions", "actions"];

impl Deserialize for Context {
    fn deserialize<D>(deserializer: &mut D) -> Result<Context, D::Error>
        where D: Deserializer
    {
        deserializer.visit_struct("Context", FIELDS, ContextVisitor)
    }
}

enum Field {
    Name,
    Uuid,
    Conditions,
    ContextId,
    Actions,
}

impl Deserialize for Field {
    fn deserialize<D>(deserializer: &mut D) -> Result<Field, D::Error>
        where D: Deserializer
    {
        struct FieldVisitor;

        impl Visitor for FieldVisitor {
            type Value = Field;

            fn visit_str<E>(&mut self, value: &str) -> Result<Field, E>
                where E: Error
            {
                match value {
                    "name" => Ok(Field::Name),
                    "uuid" => Ok(Field::Uuid),
                    "conditions" => Ok(Field::Conditions),
                    "context_id" => Ok(Field::ContextId),
                    "actions" => Ok(Field::Actions),
                    _ => Err(Error::syntax(&format!("Unexpected field: {}", value))),
                }
            }
        }

        deserializer.visit(FieldVisitor)
    }
}

struct ContextVisitor;

impl ContextVisitor {
    fn parse_uuid<V>(uuid: Option<String>) -> Result<Uuid, V::Error>
        where V: MapVisitor
    {
        match uuid {
            Some(value) => {
                match Uuid::parse_str(&value) {
                    Ok(uuid) => Ok(uuid),
                    Err(err) => {
                        return Err(Error::syntax(&format!("Failed to parse field 'uuid': \
                                                           uuid={} error={}",
                                                          value,
                                                          err)));
                    }
                }
            }
            None => {
                return Err(Error::missing_field("uuid"));
            }
        }
    }

    fn deser_context_id<V>(context_id: Option<String>,
                           uuid: &Uuid)
                           -> Result<Option<Template>, V::Error>
        where V: MapVisitor
    {
        if let Some(context_id) = context_id {
            ContextVisitor::parse_context_id::<V>(context_id, uuid)
        } else {
            Ok(None)
        }
    }

    fn parse_context_id<V>(context_id: String, uuid: &Uuid) -> Result<Option<Template>, V::Error>
        where V: MapVisitor
    {
        match Template::compile(context_id) {
            Ok(context_id) => Ok(Some(context_id)),
            Err(err) => {
                let errmsg = format!("Invalid handlebars template in 'context_id' field: uuid={} \
                                      error={}",
                                     uuid,
                                     err);
                return Err(Error::syntax(&errmsg));
            }
        }
    }

    fn parse_actions<V>(actions: Option<Vec<ActionType>>) -> Result<Vec<ActionType>, V::Error>
        where V: MapVisitor
    {
        match actions {
            Some(actions) => Ok(actions),
            None => Ok(Vec::new()),
        }
    }
}

impl Visitor for ContextVisitor {
    type Value = Context;

    fn visit_map<V>(&mut self, mut visitor: V) -> Result<Context, V::Error>
        where V: MapVisitor
    {
        let mut name = None;
        let mut uuid: Option<String> = None;
        let mut conditions = None;
        let mut context_id: Option<String> = None;
        let mut actions = None;

        loop {
            match try!(visitor.visit_key()) {
                Some(Field::Name) => {
                    name = Some(try!(visitor.visit_value()));
                }
                Some(Field::Uuid) => {
                    uuid = Some(try!(visitor.visit_value()));
                }
                Some(Field::Conditions) => {
                    conditions = Some(try!(visitor.visit_value()));
                }
                Some(Field::ContextId) => {
                    context_id = Some(try!(visitor.visit_value()));
                }
                Some(Field::Actions) => {
                    actions = Some(try!(visitor.visit_value()));
                }
                None => break,
            }
        }

        let uuid = try!(ContextVisitor::parse_uuid::<V>(uuid));
        let context_id = try!(ContextVisitor::deser_context_id::<V>(context_id, &uuid));
        let actions = try!(ContextVisitor::parse_actions::<V>(actions));

        try!(visitor.end());

        Ok(Context {
            name: name,
            uuid: uuid,
            conditions: conditions.unwrap(),
            context_id: context_id,
            actions: actions,
        })
    }
}

#[cfg(test)]
mod test {
    use config::action::{ActionType, ExecCondition};
    use config::action::message::MessageActionBuilder;
    use conditions::ConditionsBuilder;
    use config::Context;
    use handlebars::Template;
    use serde_json::from_str;
    use uuid::Uuid;

    #[test]
    fn test_given_config_context_when_it_is_deserialized_then_we_get_the_right_results() {
        let text = r#"
        {
            "name": "TEST_NAME",
            "uuid": "86ca9f93-84fb-4813-b037-6526f7a585a3",
            "conditions": {
                "timeout": 100,
                "first_opens": true,
                "patterns": [
                    "PATTERN_NAME1",
                    "PATTERN_NAME2",
                    "f13dafee-cd14-4dda-995c-6ed476a21de3"
                ]
            },
            "actions": [
                {
                    "message": {
                        "uuid": "uuid1",
                        "when": {
                            "on_closed": true,
                            "on_opened": false
                        },
                        "message": "message"
                    }
                }
            ]
        }
        "#;

        let result = from_str::<Context>(text);
        println!("{:?}", &result);
        let expected_name = "TEST_NAME".to_string();
        let expected_uuid = Uuid::parse_str("86ca9f93-84fb-4813-b037-6526f7a585a3").ok().unwrap();
        let expected_conditions = ConditionsBuilder::new(100)
                                      .first_opens(true)
                                      .patterns(vec!["PATTERN_NAME1".to_string(),
                                                     "PATTERN_NAME2".to_string(),
                                                     "f13dafee-cd14-4dda-995c-6ed476a21de3"
                                                         .to_string()])
                                      .build();
        let message = Template::compile("message".to_string())
                          .ok()
                          .expect("Failed to compile a handlebars template");
        let expected_exec_cond = ExecCondition {on_opened: false, on_closed: true};
        let expected_actions = vec![ActionType::Message(MessageActionBuilder::new("uuid1", message).when(expected_exec_cond).build())];
        let context = result.ok().expect("Failed to deserialize a valid Context");
        assert_eq!(&Some(expected_name), &context.name);
        assert_eq!(&expected_uuid, &context.uuid);
        assert_eq!(&expected_conditions, &context.conditions);
        assert_eq!(&expected_actions, &context.actions);
    }

    #[test]
    fn test_given_config_context_when_it_is_deserialized_and_only_the_required_fields_are_present_then_we_can_deserialize_it_successfully
        () {
        let text = r#"
        {
            "uuid": "86ca9f93-84fb-4813-b037-6526f7a585a3",
            "conditions": {
                "timeout": 100
            }
        }
        "#;

        let result = from_str::<Context>(text);
        println!("{:?}", &result);
        let expected_uuid = Uuid::parse_str("86ca9f93-84fb-4813-b037-6526f7a585a3").ok().unwrap();
        let expected_conditions = ConditionsBuilder::new(100).build();
        let context = result.ok().expect("Failed to deserialize a valid Context");
        assert_eq!(&expected_uuid, &context.uuid);
        assert_eq!(&expected_conditions, &context.conditions);
    }

    #[test]
    fn test_given_config_context_when_it_is_deserialized_and_the_uuid_is_invalid_then_we_report_an_error
        () {
        let text = r#"
        {
            "uuid": "this is an invalid uuid",
            "conditions": {
                "timeout": 100
            }
        }
        "#;

        let result = from_str::<Context>(text);
        println!("{:?}", &result);
        let _ = result.err()
                      .expect("Successfully deserialized an invalid Context (UUID is invalid)");
    }

    #[test]
    fn test_given_config_context_when_it_contains_context_id_then_can_be_deserialized() {
        let text = r#"
        {
            "uuid": "86ca9f93-84fb-4813-b037-6526f7a585a3",
            "context_id": "{{HOST}}{{PROGRAM}}",
            "conditions": {
                "timeout": 100
            }
        }
        "#;
        let expected_context_id = "{{HOST}}{{PROGRAM}}".to_string();
        let result = from_str::<Context>(text);
        println!("{:?}", &result);
        let context = result.ok().expect("Failed to deserialize a valid Context");
        assert_eq!(&expected_context_id,
                   &context.context_id.as_ref().unwrap().to_string());
    }
}
<commit_msg>ContextVisitor: simplify deser loop<commit_after>use config::action::ActionType;
use config::Context;
use serde::de::{Deserialize, Deserializer, MapVisitor, Error, Visitor};

use handlebars::Template;
use uuid::Uuid;

const FIELDS: &'static [&'static str] = &["name", "uuid", "conditions", "actions"];

impl Deserialize for Context {
    fn deserialize<D>(deserializer: &mut D) -> Result<Context, D::Error>
        where D: Deserializer
    {
        deserializer.visit_struct("Context", FIELDS, ContextVisitor)
    }
}

enum Field {
    Name,
    Uuid,
    Conditions,
    ContextId,
    Actions,
}

impl Deserialize for Field {
    fn deserialize<D>(deserializer: &mut D) -> Result<Field, D::Error>
        where D: Deserializer
    {
        struct FieldVisitor;

        impl Visitor for FieldVisitor {
            type Value = Field;

            fn visit_str<E>(&mut self, value: &str) -> Result<Field, E>
                where E: Error
            {
                match value {
                    "name" => Ok(Field::Name),
                    "uuid" => Ok(Field::Uuid),
                    "conditions" => Ok(Field::Conditions),
                    "context_id" => Ok(Field::ContextId),
                    "actions" => Ok(Field::Actions),
                    _ => Err(Error::syntax(&format!("Unexpected field: {}", value))),
                }
            }
        }

        deserializer.visit(FieldVisitor)
    }
}

struct ContextVisitor;

impl ContextVisitor {
    fn parse_uuid<V>(uuid: Option<String>) -> Result<Uuid, V::Error>
        where V: MapVisitor
    {
        match uuid {
            Some(value) => {
                match Uuid::parse_str(&value) {
                    Ok(uuid) => Ok(uuid),
                    Err(err) => {
                        return Err(Error::syntax(&format!("Failed to parse field 'uuid': \
                                                           uuid={} error={}",
                                                          value,
                                                          err)));
                    }
                }
            }
            None => {
                return Err(Error::missing_field("uuid"));
            }
        }
    }

    fn deser_context_id<V>(context_id: Option<String>,
                           uuid: &Uuid)
                           -> Result<Option<Template>, V::Error>
        where V: MapVisitor
    {
        if let Some(context_id) = context_id {
            ContextVisitor::parse_context_id::<V>(context_id, uuid)
        } else {
            Ok(None)
        }
    }

    fn parse_context_id<V>(context_id: String, uuid: &Uuid) -> Result<Option<Template>, V::Error>
        where V: MapVisitor
    {
        match Template::compile(context_id) {
            Ok(context_id) => Ok(Some(context_id)),
            Err(err) => {
                let errmsg = format!("Invalid handlebars template in 'context_id' field: uuid={} \
                                      error={}",
                                     uuid,
                                     err);
                return Err(Error::syntax(&errmsg));
            }
        }
    }

    fn parse_actions<V>(actions: Option<Vec<ActionType>>) -> Result<Vec<ActionType>, V::Error>
        where V: MapVisitor
    {
        match actions {
            Some(actions) => Ok(actions),
            None => Ok(Vec::new()),
        }
    }
}

impl Visitor for ContextVisitor {
    type Value = Context;

    fn visit_map<V>(&mut self, mut visitor: V) -> Result<Context, V::Error>
        where V: MapVisitor
    {
        let mut name = None;
        let mut uuid: Option<String> = None;
        let mut conditions = None;
        let mut context_id: Option<String> = None;
        let mut actions = None;

        while let Some(field) = try!(visitor.visit_key()) {
            match field {
                Field::Name => name = Some(try!(visitor.visit_value())),
                Field::Uuid => uuid = Some(try!(visitor.visit_value())),
                Field::Conditions => conditions = Some(try!(visitor.visit_value())),
                Field::ContextId => context_id = Some(try!(visitor.visit_value())),
                Field::Actions => actions = Some(try!(visitor.visit_value())),
            }
        }

        let uuid = try!(ContextVisitor::parse_uuid::<V>(uuid));
        let context_id = try!(ContextVisitor::deser_context_id::<V>(context_id, &uuid));
        let actions = try!(ContextVisitor::parse_actions::<V>(actions));

        try!(visitor.end());

        Ok(Context {
            name: name,
            uuid: uuid,
            conditions: conditions.unwrap(),
            context_id: context_id,
            actions: actions,
        })
    }
}

#[cfg(test)]
mod test {
    use config::action::{ActionType, ExecCondition};
    use config::action::message::MessageActionBuilder;
    use conditions::ConditionsBuilder;
    use config::Context;
    use handlebars::Template;
    use serde_json::from_str;
    use uuid::Uuid;

    #[test]
    fn test_given_config_context_when_it_is_deserialized_then_we_get_the_right_results() {
        let text = r#"
        {
            "name": "TEST_NAME",
            "uuid": "86ca9f93-84fb-4813-b037-6526f7a585a3",
            "conditions": {
                "timeout": 100,
                "first_opens": true,
                "patterns": [
                    "PATTERN_NAME1",
                    "PATTERN_NAME2",
                    "f13dafee-cd14-4dda-995c-6ed476a21de3"
                ]
            },
            "actions": [
                {
                    "message": {
                        "uuid": "uuid1",
                        "when": {
                            "on_closed": true,
                            "on_opened": false
                        },
                        "message": "message"
                    }
                }
            ]
        }
        "#;

        let result = from_str::<Context>(text);
        println!("{:?}", &result);
        let expected_name = "TEST_NAME".to_string();
        let expected_uuid = Uuid::parse_str("86ca9f93-84fb-4813-b037-6526f7a585a3").ok().unwrap();
        let expected_conditions = ConditionsBuilder::new(100)
                                      .first_opens(true)
                                      .patterns(vec!["PATTERN_NAME1".to_string(),
                                                     "PATTERN_NAME2".to_string(),
                                                     "f13dafee-cd14-4dda-995c-6ed476a21de3"
                                                         .to_string()])
                                      .build();
        let message = Template::compile("message".to_string())
                          .ok()
                          .expect("Failed to compile a handlebars template");
        let expected_exec_cond = ExecCondition {on_opened: false, on_closed: true};
        let expected_actions = vec![ActionType::Message(MessageActionBuilder::new("uuid1", message).when(expected_exec_cond).build())];
        let context = result.ok().expect("Failed to deserialize a valid Context");
        assert_eq!(&Some(expected_name), &context.name);
        assert_eq!(&expected_uuid, &context.uuid);
        assert_eq!(&expected_conditions, &context.conditions);
        assert_eq!(&expected_actions, &context.actions);
    }

    #[test]
    fn test_given_config_context_when_it_is_deserialized_and_only_the_required_fields_are_present_then_we_can_deserialize_it_successfully
        () {
        let text = r#"
        {
            "uuid": "86ca9f93-84fb-4813-b037-6526f7a585a3",
            "conditions": {
                "timeout": 100
            }
        }
        "#;

        let result = from_str::<Context>(text);
        println!("{:?}", &result);
        let expected_uuid = Uuid::parse_str("86ca9f93-84fb-4813-b037-6526f7a585a3").ok().unwrap();
        let expected_conditions = ConditionsBuilder::new(100).build();
        let context = result.ok().expect("Failed to deserialize a valid Context");
        assert_eq!(&expected_uuid, &context.uuid);
        assert_eq!(&expected_conditions, &context.conditions);
    }

    #[test]
    fn test_given_config_context_when_it_is_deserialized_and_the_uuid_is_invalid_then_we_report_an_error
        () {
        let text = r#"
        {
            "uuid": "this is an invalid uuid",
            "conditions": {
                "timeout": 100
            }
        }
        "#;

        let result = from_str::<Context>(text);
        println!("{:?}", &result);
        let _ = result.err()
                      .expect("Successfully deserialized an invalid Context (UUID is invalid)");
    }

    #[test]
    fn test_given_config_context_when_it_contains_context_id_then_can_be_deserialized() {
        let text = r#"
        {
            "uuid": "86ca9f93-84fb-4813-b037-6526f7a585a3",
            "context_id": "{{HOST}}{{PROGRAM}}",
            "conditions": {
                "timeout": 100
            }
        }
        "#;
        let expected_context_id = "{{HOST}}{{PROGRAM}}".to_string();
        let result = from_str::<Context>(text);
        println!("{:?}", &result);
        let context = result.ok().expect("Failed to deserialize a valid Context");
        assert_eq!(&expected_context_id,
                   &context.context_id.as_ref().unwrap().to_string());
    }
}
<|endoftext|>


<commit_before>//! Base trait and common functionality for all consumers.

use std::ptr;
use std::time::Duration;

use log::{error, trace};

use rdkafka_sys as rdsys;
use rdkafka_sys::types::*;

use crate::client::{ClientContext, NativeClient};
use crate::error::KafkaResult;
use crate::groups::GroupList;
use crate::message::BorrowedMessage;
use crate::metadata::Metadata;
use crate::topic_partition_list::{Offset, TopicPartitionList};
use crate::util::{cstr_to_owned, Timeout};

pub mod base_consumer;
pub mod stream_consumer;

// Re-exports.
pub use self::base_consumer::BaseConsumer;
pub use self::stream_consumer::{MessageStream, StreamConsumer};

/// Rebalance information.
#[derive(Clone, Debug)]
pub enum Rebalance<'a> {
    /// A new partition assignment is received.
    Assign(&'a TopicPartitionList),
    /// All partitions are revoked.
    Revoke,
    /// Unexpected error from Kafka.
    Error(String),
}

/// Consumer specific Context. This user-defined object can be used to provide custom callbacks to
/// consumer events. Refer to the list of methods to check which callbacks can be specified.
pub trait ConsumerContext: ClientContext {
    /// Implements the default rebalancing strategy and calls the `pre_rebalance` and
    /// `post_rebalance` methods. If this method is overridden, it will be responsibility
    /// of the user to call them if needed.
    fn rebalance(
        &self,
        native_client: &NativeClient,
        err: RDKafkaRespErr,
        tpl: &mut TopicPartitionList,
    ) {
        let rebalance = match err {
            RDKafkaRespErr::RD_KAFKA_RESP_ERR__ASSIGN_PARTITIONS => Rebalance::Assign(tpl),
            RDKafkaRespErr::RD_KAFKA_RESP_ERR__REVOKE_PARTITIONS => Rebalance::Revoke,
            _ => {
                let error = unsafe { cstr_to_owned(rdsys::rd_kafka_err2str(err)) };
                error!("Error rebalancing: {}", error);
                Rebalance::Error(error)
            }
        };

        trace!("Running pre-rebalance with {:?}", rebalance);
        self.pre_rebalance(&rebalance);

        trace!("Running rebalance with {:?}", rebalance);
        // Execute rebalance
        unsafe {
            match err {
                RDKafkaRespErr::RD_KAFKA_RESP_ERR__ASSIGN_PARTITIONS => {
                    rdsys::rd_kafka_assign(native_client.ptr(), tpl.ptr());
                }
                _ => {
                    // Also for RD_KAFKA_RESP_ERR__REVOKE_PARTITIONS
                    rdsys::rd_kafka_assign(native_client.ptr(), ptr::null());
                }
            }
        }
        trace!("Running post-rebalance with {:?}", rebalance);
        self.post_rebalance(&rebalance);
    }

    /// Pre-rebalance callback. This method will run before the rebalance and should
    /// terminate its execution quickly.
    #[allow(unused_variables)]
    fn pre_rebalance<'a>(&self, rebalance: &Rebalance<'a>) {}

    /// Post-rebalance callback. This method will run after the rebalance and should
    /// terminate its execution quickly.
    #[allow(unused_variables)]
    fn post_rebalance<'a>(&self, rebalance: &Rebalance<'a>) {}

    // TODO: convert pointer to structure
    /// Post commit callback. This method will run after a group of offsets was committed to the
    /// offset store.
    #[allow(unused_variables)]
    fn commit_callback(&self, result: KafkaResult<()>, offsets: &TopicPartitionList) {}

    /// Returns the minimum interval at which to poll the main queue, which
    /// services the logging, stats, and error callbacks.
    ///
    /// The main queue is polled once whenever [`Consumer.poll`] is called. If
    /// `Consumer.poll` is called with a timeout that is larger than this
    /// interval, then the main queue will be polled at that interval while the
    /// consumer queue is blocked.
    ///
    /// For example, if the main queue's minimum poll interval is 200ms and
    /// `Consumer.poll` is called with a timeout of 1s, then `Consumer.poll` may
    /// block for up to 1s waiting for a message, but it will poll the main
    /// queue every 200ms while it is waiting.
    ///
    /// By default, the minimum poll interval for the main queue is 1s.
    fn main_queue_min_poll_interval(&self) -> Timeout {
        Timeout::After(Duration::from_secs(1))
    }

    /// Message queue nonempty callback. This method will run when the
    /// consumer's message queue switches from empty to nonempty.
    fn message_queue_nonempty_callback(&self) {}
}

/// An empty consumer context that can be user when no context is needed.
#[derive(Clone)]
pub struct DefaultConsumerContext;

impl ClientContext for DefaultConsumerContext {}
impl ConsumerContext for DefaultConsumerContext {}

/// Specifies if the commit should be performed synchronously
/// or asynchronously.
pub enum CommitMode {
    /// Synchronous commit.
    Sync = 0,
    /// Asynchronous commit.
    Async = 1,
}

/// Common trait for all consumers.
///
/// # Note about object safety
///
/// Doing type erasure on consumers is expected to be rare (eg. `Box<Consumer>`). Therefore, the
/// API is optimised for the case where a concrete type is available. As a result, some methods are
/// not available on trait objects, since they are generic.
///
/// If there's still the need to erase the type, the generic methods can still be reached through
/// the [`get_base_consumer`](#method.get_base_consumer) method.
pub trait Consumer<C: ConsumerContext = DefaultConsumerContext> {
    /// Returns a reference to the BaseConsumer.
    fn get_base_consumer(&self) -> &BaseConsumer<C>;

    // Default implementations

    /// Subscribe the consumer to a list of topics.
    fn subscribe(&self, topics: &[&str]) -> KafkaResult<()> {
        self.get_base_consumer().subscribe(topics)
    }

    /// Unsubscribe the current subscription list.
    fn unsubscribe(&self) {
        self.get_base_consumer().unsubscribe();
    }

    /// Manually assign topics and partitions to the consumer. If used, automatic consumer
    /// rebalance won't be activated.
    fn assign(&self, assignment: &TopicPartitionList) -> KafkaResult<()> {
        self.get_base_consumer().assign(assignment)
    }

    /// Seek to `offset` for the specified `topic` and `partition`. After a
    /// successful call to `seek`, the next poll of the consumer will return the
    /// message with `offset`.
    fn seek<T: Into<Timeout>>(
        &self,
        topic: &str,
        partition: i32,
        offset: Offset,
        timeout: T,
    ) -> KafkaResult<()> {
        self.get_base_consumer()
            .seek(topic, partition, offset, timeout)
    }

    /// Commits the offset of the specified message. The commit can be sync (blocking), or async.
    /// Notice that when a specific offset is committed, all the previous offsets are considered
    /// committed as well. Use this method only if you are processing messages in order.
    fn commit(
        &self,
        topic_partition_list: &TopicPartitionList,
        mode: CommitMode,
    ) -> KafkaResult<()> {
        self.get_base_consumer().commit(topic_partition_list, mode)
    }

    /// Commit the current consumer state. Notice that if the consumer fails after a message
    /// has been received, but before the message has been processed by the user code,
    /// this might lead to data loss. Check the "at-least-once delivery" section in the readme
    /// for more information.
    fn commit_consumer_state(&self, mode: CommitMode) -> KafkaResult<()> {
        self.get_base_consumer().commit_consumer_state(mode)
    }

    /// Commit the provided message. Note that this will also automatically commit every
    /// message with lower offset within the same partition.
    fn commit_message(&self, message: &BorrowedMessage, mode: CommitMode) -> KafkaResult<()> {
        self.get_base_consumer().commit_message(message, mode)
    }

    /// Store offset for this message to be used on the next (auto)commit.
    /// When using this `enable.auto.offset.store` should be set to `false` in the config.
    fn store_offset(&self, message: &BorrowedMessage) -> KafkaResult<()> {
        self.get_base_consumer().store_offset(message)
    }

    /// Store offsets to be used on the next (auto)commit.
    /// When using this `enable.auto.offset.store` should be set to `false` in the config.
    fn store_offsets(&self, tpl: &TopicPartitionList) -> KafkaResult<()> {
        self.get_base_consumer().store_offsets(tpl)
    }

    /// Returns the current topic subscription.
    fn subscription(&self) -> KafkaResult<TopicPartitionList> {
        self.get_base_consumer().subscription()
    }

    /// Returns the current partition assignment.
    fn assignment(&self) -> KafkaResult<TopicPartitionList> {
        self.get_base_consumer().assignment()
    }

    /// Retrieve committed offsets for topics and partitions.
    fn committed<T>(&self, timeout: T) -> KafkaResult<TopicPartitionList>
    where
        T: Into<Timeout>,
        Self: Sized,
    {
        self.get_base_consumer().committed(timeout)
    }

    /// Retrieve committed offsets for specified topics and partitions.
    fn committed_offsets<T>(
        &self,
        tpl: TopicPartitionList,
        timeout: T,
    ) -> KafkaResult<TopicPartitionList>
    where
        T: Into<Timeout>,
    {
        self.get_base_consumer().committed_offsets(tpl, timeout)
    }

    /// Lookup the offsets for this consumer's partitions by timestamp.
    fn offsets_for_timestamp<T>(
        &self,
        timestamp: i64,
        timeout: T,
    ) -> KafkaResult<TopicPartitionList>
    where
        T: Into<Timeout>,
        Self: Sized,
    {
        self.get_base_consumer()
            .offsets_for_timestamp(timestamp, timeout)
    }

    /// Look up the offsets for the specified partitions by timestamp.
    fn offsets_for_times<T>(
        &self,
        timestamps: TopicPartitionList,
        timeout: T,
    ) -> KafkaResult<TopicPartitionList>
    where
        T: Into<Timeout>,
        Self: Sized,
    {
        self.get_base_consumer()
            .offsets_for_times(timestamps, timeout)
    }

    /// Retrieve current positions (offsets) for topics and partitions.
    fn position(&self) -> KafkaResult<TopicPartitionList> {
        self.get_base_consumer().position()
    }

    /// Returns the metadata information for the specified topic, or for all topics in the cluster
    /// if no topic is specified.
    fn fetch_metadata<T>(&self, topic: Option<&str>, timeout: T) -> KafkaResult<Metadata>
    where
        T: Into<Timeout>,
        Self: Sized,
    {
        self.get_base_consumer().fetch_metadata(topic, timeout)
    }

    /// Returns the metadata information for all the topics in the cluster.
    fn fetch_watermarks<T>(
        &self,
        topic: &str,
        partition: i32,
        timeout: T,
    ) -> KafkaResult<(i64, i64)>
    where
        T: Into<Timeout>,
        Self: Sized,
    {
        self.get_base_consumer()
            .fetch_watermarks(topic, partition, timeout)
    }

    /// Returns the group membership information for the given group. If no group is
    /// specified, all groups will be returned.
    fn fetch_group_list<T>(&self, group: Option<&str>, timeout: T) -> KafkaResult<GroupList>
    where
        T: Into<Timeout>,
        Self: Sized,
    {
        self.get_base_consumer().fetch_group_list(group, timeout)
    }

    /// Pause consumption for the provided list of partitions.
    fn pause(&self, partitions: &TopicPartitionList) -> KafkaResult<()> {
        self.get_base_consumer().pause(partitions)
    }

    /// Resume consumption for the provided list of partitions.
    fn resume(&self, partitions: &TopicPartitionList) -> KafkaResult<()> {
        self.get_base_consumer().resume(partitions)
    }
}
<commit_msg>Implement Default for DefaultConsumerContext<commit_after>//! Base trait and common functionality for all consumers.

use std::ptr;
use std::time::Duration;

use log::{error, trace};

use rdkafka_sys as rdsys;
use rdkafka_sys::types::*;

use crate::client::{ClientContext, NativeClient};
use crate::error::KafkaResult;
use crate::groups::GroupList;
use crate::message::BorrowedMessage;
use crate::metadata::Metadata;
use crate::topic_partition_list::{Offset, TopicPartitionList};
use crate::util::{cstr_to_owned, Timeout};

pub mod base_consumer;
pub mod stream_consumer;

// Re-exports.
pub use self::base_consumer::BaseConsumer;
pub use self::stream_consumer::{MessageStream, StreamConsumer};

/// Rebalance information.
#[derive(Clone, Debug)]
pub enum Rebalance<'a> {
    /// A new partition assignment is received.
    Assign(&'a TopicPartitionList),
    /// All partitions are revoked.
    Revoke,
    /// Unexpected error from Kafka.
    Error(String),
}

/// Consumer specific Context. This user-defined object can be used to provide custom callbacks to
/// consumer events. Refer to the list of methods to check which callbacks can be specified.
pub trait ConsumerContext: ClientContext {
    /// Implements the default rebalancing strategy and calls the `pre_rebalance` and
    /// `post_rebalance` methods. If this method is overridden, it will be responsibility
    /// of the user to call them if needed.
    fn rebalance(
        &self,
        native_client: &NativeClient,
        err: RDKafkaRespErr,
        tpl: &mut TopicPartitionList,
    ) {
        let rebalance = match err {
            RDKafkaRespErr::RD_KAFKA_RESP_ERR__ASSIGN_PARTITIONS => Rebalance::Assign(tpl),
            RDKafkaRespErr::RD_KAFKA_RESP_ERR__REVOKE_PARTITIONS => Rebalance::Revoke,
            _ => {
                let error = unsafe { cstr_to_owned(rdsys::rd_kafka_err2str(err)) };
                error!("Error rebalancing: {}", error);
                Rebalance::Error(error)
            }
        };

        trace!("Running pre-rebalance with {:?}", rebalance);
        self.pre_rebalance(&rebalance);

        trace!("Running rebalance with {:?}", rebalance);
        // Execute rebalance
        unsafe {
            match err {
                RDKafkaRespErr::RD_KAFKA_RESP_ERR__ASSIGN_PARTITIONS => {
                    rdsys::rd_kafka_assign(native_client.ptr(), tpl.ptr());
                }
                _ => {
                    // Also for RD_KAFKA_RESP_ERR__REVOKE_PARTITIONS
                    rdsys::rd_kafka_assign(native_client.ptr(), ptr::null());
                }
            }
        }
        trace!("Running post-rebalance with {:?}", rebalance);
        self.post_rebalance(&rebalance);
    }

    /// Pre-rebalance callback. This method will run before the rebalance and should
    /// terminate its execution quickly.
    #[allow(unused_variables)]
    fn pre_rebalance<'a>(&self, rebalance: &Rebalance<'a>) {}

    /// Post-rebalance callback. This method will run after the rebalance and should
    /// terminate its execution quickly.
    #[allow(unused_variables)]
    fn post_rebalance<'a>(&self, rebalance: &Rebalance<'a>) {}

    // TODO: convert pointer to structure
    /// Post commit callback. This method will run after a group of offsets was committed to the
    /// offset store.
    #[allow(unused_variables)]
    fn commit_callback(&self, result: KafkaResult<()>, offsets: &TopicPartitionList) {}

    /// Returns the minimum interval at which to poll the main queue, which
    /// services the logging, stats, and error callbacks.
    ///
    /// The main queue is polled once whenever [`Consumer.poll`] is called. If
    /// `Consumer.poll` is called with a timeout that is larger than this
    /// interval, then the main queue will be polled at that interval while the
    /// consumer queue is blocked.
    ///
    /// For example, if the main queue's minimum poll interval is 200ms and
    /// `Consumer.poll` is called with a timeout of 1s, then `Consumer.poll` may
    /// block for up to 1s waiting for a message, but it will poll the main
    /// queue every 200ms while it is waiting.
    ///
    /// By default, the minimum poll interval for the main queue is 1s.
    fn main_queue_min_poll_interval(&self) -> Timeout {
        Timeout::After(Duration::from_secs(1))
    }

    /// Message queue nonempty callback. This method will run when the
    /// consumer's message queue switches from empty to nonempty.
    fn message_queue_nonempty_callback(&self) {}
}

/// An empty consumer context that can be user when no context is needed.
#[derive(Clone, Default)]
pub struct DefaultConsumerContext;

impl ClientContext for DefaultConsumerContext {}
impl ConsumerContext for DefaultConsumerContext {}

/// Specifies if the commit should be performed synchronously
/// or asynchronously.
pub enum CommitMode {
    /// Synchronous commit.
    Sync = 0,
    /// Asynchronous commit.
    Async = 1,
}

/// Common trait for all consumers.
///
/// # Note about object safety
///
/// Doing type erasure on consumers is expected to be rare (eg. `Box<Consumer>`). Therefore, the
/// API is optimised for the case where a concrete type is available. As a result, some methods are
/// not available on trait objects, since they are generic.
///
/// If there's still the need to erase the type, the generic methods can still be reached through
/// the [`get_base_consumer`](#method.get_base_consumer) method.
pub trait Consumer<C: ConsumerContext = DefaultConsumerContext> {
    /// Returns a reference to the BaseConsumer.
    fn get_base_consumer(&self) -> &BaseConsumer<C>;

    // Default implementations

    /// Subscribe the consumer to a list of topics.
    fn subscribe(&self, topics: &[&str]) -> KafkaResult<()> {
        self.get_base_consumer().subscribe(topics)
    }

    /// Unsubscribe the current subscription list.
    fn unsubscribe(&self) {
        self.get_base_consumer().unsubscribe();
    }

    /// Manually assign topics and partitions to the consumer. If used, automatic consumer
    /// rebalance won't be activated.
    fn assign(&self, assignment: &TopicPartitionList) -> KafkaResult<()> {
        self.get_base_consumer().assign(assignment)
    }

    /// Seek to `offset` for the specified `topic` and `partition`. After a
    /// successful call to `seek`, the next poll of the consumer will return the
    /// message with `offset`.
    fn seek<T: Into<Timeout>>(
        &self,
        topic: &str,
        partition: i32,
        offset: Offset,
        timeout: T,
    ) -> KafkaResult<()> {
        self.get_base_consumer()
            .seek(topic, partition, offset, timeout)
    }

    /// Commits the offset of the specified message. The commit can be sync (blocking), or async.
    /// Notice that when a specific offset is committed, all the previous offsets are considered
    /// committed as well. Use this method only if you are processing messages in order.
    fn commit(
        &self,
        topic_partition_list: &TopicPartitionList,
        mode: CommitMode,
    ) -> KafkaResult<()> {
        self.get_base_consumer().commit(topic_partition_list, mode)
    }

    /// Commit the current consumer state. Notice that if the consumer fails after a message
    /// has been received, but before the message has been processed by the user code,
    /// this might lead to data loss. Check the "at-least-once delivery" section in the readme
    /// for more information.
    fn commit_consumer_state(&self, mode: CommitMode) -> KafkaResult<()> {
        self.get_base_consumer().commit_consumer_state(mode)
    }

    /// Commit the provided message. Note that this will also automatically commit every
    /// message with lower offset within the same partition.
    fn commit_message(&self, message: &BorrowedMessage, mode: CommitMode) -> KafkaResult<()> {
        self.get_base_consumer().commit_message(message, mode)
    }

    /// Store offset for this message to be used on the next (auto)commit.
    /// When using this `enable.auto.offset.store` should be set to `false` in the config.
    fn store_offset(&self, message: &BorrowedMessage) -> KafkaResult<()> {
        self.get_base_consumer().store_offset(message)
    }

    /// Store offsets to be used on the next (auto)commit.
    /// When using this `enable.auto.offset.store` should be set to `false` in the config.
    fn store_offsets(&self, tpl: &TopicPartitionList) -> KafkaResult<()> {
        self.get_base_consumer().store_offsets(tpl)
    }

    /// Returns the current topic subscription.
    fn subscription(&self) -> KafkaResult<TopicPartitionList> {
        self.get_base_consumer().subscription()
    }

    /// Returns the current partition assignment.
    fn assignment(&self) -> KafkaResult<TopicPartitionList> {
        self.get_base_consumer().assignment()
    }

    /// Retrieve committed offsets for topics and partitions.
    fn committed<T>(&self, timeout: T) -> KafkaResult<TopicPartitionList>
    where
        T: Into<Timeout>,
        Self: Sized,
    {
        self.get_base_consumer().committed(timeout)
    }

    /// Retrieve committed offsets for specified topics and partitions.
    fn committed_offsets<T>(
        &self,
        tpl: TopicPartitionList,
        timeout: T,
    ) -> KafkaResult<TopicPartitionList>
    where
        T: Into<Timeout>,
    {
        self.get_base_consumer().committed_offsets(tpl, timeout)
    }

    /// Lookup the offsets for this consumer's partitions by timestamp.
    fn offsets_for_timestamp<T>(
        &self,
        timestamp: i64,
        timeout: T,
    ) -> KafkaResult<TopicPartitionList>
    where
        T: Into<Timeout>,
        Self: Sized,
    {
        self.get_base_consumer()
            .offsets_for_timestamp(timestamp, timeout)
    }

    /// Look up the offsets for the specified partitions by timestamp.
    fn offsets_for_times<T>(
        &self,
        timestamps: TopicPartitionList,
        timeout: T,
    ) -> KafkaResult<TopicPartitionList>
    where
        T: Into<Timeout>,
        Self: Sized,
    {
        self.get_base_consumer()
            .offsets_for_times(timestamps, timeout)
    }

    /// Retrieve current positions (offsets) for topics and partitions.
    fn position(&self) -> KafkaResult<TopicPartitionList> {
        self.get_base_consumer().position()
    }

    /// Returns the metadata information for the specified topic, or for all topics in the cluster
    /// if no topic is specified.
    fn fetch_metadata<T>(&self, topic: Option<&str>, timeout: T) -> KafkaResult<Metadata>
    where
        T: Into<Timeout>,
        Self: Sized,
    {
        self.get_base_consumer().fetch_metadata(topic, timeout)
    }

    /// Returns the metadata information for all the topics in the cluster.
    fn fetch_watermarks<T>(
        &self,
        topic: &str,
        partition: i32,
        timeout: T,
    ) -> KafkaResult<(i64, i64)>
    where
        T: Into<Timeout>,
        Self: Sized,
    {
        self.get_base_consumer()
            .fetch_watermarks(topic, partition, timeout)
    }

    /// Returns the group membership information for the given group. If no group is
    /// specified, all groups will be returned.
    fn fetch_group_list<T>(&self, group: Option<&str>, timeout: T) -> KafkaResult<GroupList>
    where
        T: Into<Timeout>,
        Self: Sized,
    {
        self.get_base_consumer().fetch_group_list(group, timeout)
    }

    /// Pause consumption for the provided list of partitions.
    fn pause(&self, partitions: &TopicPartitionList) -> KafkaResult<()> {
        self.get_base_consumer().pause(partitions)
    }

    /// Resume consumption for the provided list of partitions.
    fn resume(&self, partitions: &TopicPartitionList) -> KafkaResult<()> {
        self.get_base_consumer().resume(partitions)
    }
}
<|endoftext|>


<commit_before>#![feature(test)]
extern crate combine as pc;
extern crate test;

use std::collections::HashMap;
use std::io::Read;
use std::fs::File;
use std::path::Path;

use pc::primitives::{Consumed, Parser, ParseError, ParseResult, State, Stream, BufferedStream};
use pc::combinator::{any, between, choice, many, many1, optional, parser, satisfy, sep_by, Expected,
                     FnParser, Skip};
use pc::char::{char, digit, spaces, Spaces, string};
use pc::from_iter;

#[derive(PartialEq, Debug)]
enum Value {
    Number(f64),
    String(String),
    Bool(bool),
    Null,
    Object(HashMap<String, Value>),
    Array(Vec<Value>),
}

fn lex<P>(p: P) -> Skip<P, Spaces<P::Input>>
    where P: Parser,
          P::Input: Stream<Item = char>
{
    p.skip(spaces())
}
struct Json<I>(::std::marker::PhantomData<fn(I) -> I>);

type FnPtrParser<O, I> = FnParser<I, fn(I) -> ParseResult<O, I>>;
type JsonParser<O, I> = Expected<FnPtrParser<O, I>>;

fn fn_parser<O, I>(f: fn(I) -> ParseResult<O, I>, err: &'static str) -> JsonParser<O, I>
    where I: Stream<Item = char>
{
    parser(f).expected(err)
}

impl<I> Json<I>
    where I: Stream<Item = char>
{
    fn integer() -> JsonParser<i64, I> {
        fn_parser(Json::<I>::integer_, "integer")
    }
    fn integer_(input: I) -> ParseResult<i64, I> {
        let (s, input) = try!(lex(many1::<String, _>(digit())).parse_lazy(input).into());
        let mut n = 0;
        for c in s.chars() {
            n = n * 10 + (c as i64 - '0' as i64);
        }
        Ok((n, input))
    }

    fn number() -> JsonParser<f64, I> {
        fn_parser(Json::<I>::number_, "number")
    }
    fn number_(input: I) -> ParseResult<f64, I> {
        let i = char('0')
            .map(|_| 0.0)
            .or(Json::<I>::integer().map(|x| x as f64));
        let fractional = many(digit()).map(|digits: String| {
            let mut magnitude = 1.0;
            digits.chars().fold(0.0, |acc, d| {
                magnitude /= 10.0;
                match d.to_digit(10) {
                    Some(d) => acc + (d as f64) * magnitude,
                    None => panic!("Not a digit"),
                }
            })
        });

        let exp = satisfy(|c| c == 'e' || c == 'E')
            .with(optional(char('-')).and(Json::<I>::integer()));
        lex(optional(char('-'))
                .and(i)
                .map(|(sign, n)| if sign.is_some() { -n } else { n })
                .and(optional(char('.')).with(fractional))
                .map(|(x, y)| if x > 0.0 { x + y } else { x - y })
                .and(optional(exp))
                .map(|(n, exp_option)| match exp_option {
                    Some((sign, e)) => {
                        let e = if sign.is_some() { -e } else { e };
                        n * 10.0f64.powi(e as i32)
                    }
                    None => n,
                }))
            .parse_lazy(input)
            .into()
    }

    fn char() -> JsonParser<char, I> {
        fn_parser(Json::<I>::char_, "char")
    }
    fn char_(input: I) -> ParseResult<char, I> {
        let (c, input) = try!(any().parse_lazy(input).into());
        let mut back_slash_char = satisfy(|c| "\"\\/bfnrt".chars().any(|x| x == c)).map(|c| {
            match c {
                '"' => '"',
                '\\' => '\\',
                '/' => '/',
                'b' => '\u{0008}',
                'f' => '\u{000c}',
                'n' => '\n',
                'r' => '\r',
                't' => '\t',
                c => c,//Should never happen
            }
        });
        match c {
            '\\' => input.combine(|input| back_slash_char.parse_stream(input)),
            '"' => {
                Err(Consumed::Empty(ParseError::from_errors(input.into_inner().position(),
                                                            Vec::new())))
            }
            _ => Ok((c, input)),
        }
    }
    fn string() -> JsonParser<String, I> {
        fn_parser(Json::<I>::string_, "string")
    }
    fn string_(input: I) -> ParseResult<String, I> {
        between(char('"'), lex(char('"')), many(Json::<I>::char())).parse_lazy(input).into()
    }

    fn object() -> JsonParser<Value, I> {
        fn_parser(Json::<I>::object_, "object")
    }
    fn object_(input: I) -> ParseResult<Value, I> {
        let field = (Json::<I>::string(), lex(char(':')), Json::<I>::value()).map(|t| (t.0, t.2));
        let fields = sep_by(field, lex(char(',')));
        between(lex(char('{')), lex(char('}')), fields)
            .map(Value::Object)
            .parse_lazy(input)
            .into()
    }

    fn value() -> FnPtrParser<Value, I> {
        parser(Json::<I>::value_ as fn(_) -> _)
    }
    #[allow(unconditional_recursion)]
    fn value_(input: I) -> ParseResult<Value, I> {
        let mut array = between(lex(char('[')),
                                lex(char(']')),
                                sep_by(Json::<I>::value(), lex(char(','))))
            .map(Value::Array);

        choice::<[&mut Parser<Input = I, Output = Value>; 7],
                 _>([&mut Json::<I>::string().map(Value::String),
                     &mut Json::<I>::object(),
                     &mut array,
                     &mut Json::<I>::number().map(Value::Number),
                     &mut lex(string("false").map(|_| Value::Bool(false))),
                     &mut lex(string("true").map(|_| Value::Bool(true))),
                     &mut lex(string("null").map(|_| Value::Null))])
            .parse_lazy(input)
            .into()
    }
}

#[test]
fn json_test() {
    use self::Value::*;
    let input = r#"
{
    "array": [1, ""],
    "object": {},
    "number": 3.14,
    "int": -100,
    "exp": -1e2,
    "exp_neg": 23e-2,
    "true": true,
    "false"  : false,
    "null" : null
}"#;
    let result = Json::value().parse(input);
    let expected = Object(vec![("array", Array(vec![Number(1.0), String("".to_string())])),
                               ("object", Object(HashMap::new())),
                               ("number", Number(3.14)),
                               ("int", Number(-100.)),
                               ("exp", Number(-1e2)),
                               ("exp_neg", Number(23E-2)),
                               ("true", Bool(true)),
                               ("false", Bool(false)),
                               ("null", Null)]
        .into_iter()
        .map(|(k, v)| (k.to_string(), v))
        .collect());
    match result {
        Ok(result) => assert_eq!(result, (expected, "")),
        Err(e) => {
            println!("{}", e);
            assert!(false);
        }
    }
}

#[bench]
fn bench_json(bencher: &mut ::test::Bencher) {
    let mut data = String::new();
    File::open(&Path::new(&"benches/data.json"))
        .and_then(|mut file| file.read_to_string(&mut data))
        .unwrap();
    let mut parser = Json::value();
    match parser.parse(State::new(&data[..])) {
        Ok((Value::Array(_), _)) => (),
        Ok(_) => assert!(false),
        Err(err) => {
            println!("{}", err);
            assert!(false);
        }
    }
    bencher.iter(|| {
        let result = parser.parse(State::new(&data[..]));
        ::test::black_box(result)
    });
}

#[bench]
fn bench_buffered_json(bencher: &mut ::test::Bencher) {
    let mut data = String::new();
    File::open(&Path::new(&"benches/data.json"))
        .and_then(|mut file| file.read_to_string(&mut data))
        .unwrap();
    bencher.iter(|| {
        let buffer = BufferedStream::new(from_iter(data.chars()), 1);
        let mut parser = Json::value();
        match parser.parse(State::new(buffer.as_stream())) {
            Ok((Value::Array(v), _)) => {
                ::test::black_box(v);
            }
            Ok(_) => assert!(false),
            Err(err) => {
                println!("{}", err);
                assert!(false);
            }
        }
    });
}
<commit_msg>Remove a leading new line causes parse error<commit_after>#![feature(test)]
extern crate combine as pc;
extern crate test;

use std::collections::HashMap;
use std::io::Read;
use std::fs::File;
use std::path::Path;

use pc::primitives::{Consumed, Parser, ParseError, ParseResult, State, Stream, BufferedStream};
use pc::combinator::{any, between, choice, many, many1, optional, parser, satisfy, sep_by, Expected,
                     FnParser, Skip};
use pc::char::{char, digit, spaces, Spaces, string};
use pc::from_iter;

#[derive(PartialEq, Debug)]
enum Value {
    Number(f64),
    String(String),
    Bool(bool),
    Null,
    Object(HashMap<String, Value>),
    Array(Vec<Value>),
}

fn lex<P>(p: P) -> Skip<P, Spaces<P::Input>>
    where P: Parser,
          P::Input: Stream<Item = char>
{
    p.skip(spaces())
}
struct Json<I>(::std::marker::PhantomData<fn(I) -> I>);

type FnPtrParser<O, I> = FnParser<I, fn(I) -> ParseResult<O, I>>;
type JsonParser<O, I> = Expected<FnPtrParser<O, I>>;

fn fn_parser<O, I>(f: fn(I) -> ParseResult<O, I>, err: &'static str) -> JsonParser<O, I>
    where I: Stream<Item = char>
{
    parser(f).expected(err)
}

impl<I> Json<I>
    where I: Stream<Item = char>
{
    fn integer() -> JsonParser<i64, I> {
        fn_parser(Json::<I>::integer_, "integer")
    }
    fn integer_(input: I) -> ParseResult<i64, I> {
        let (s, input) = try!(lex(many1::<String, _>(digit())).parse_lazy(input).into());
        let mut n = 0;
        for c in s.chars() {
            n = n * 10 + (c as i64 - '0' as i64);
        }
        Ok((n, input))
    }

    fn number() -> JsonParser<f64, I> {
        fn_parser(Json::<I>::number_, "number")
    }
    fn number_(input: I) -> ParseResult<f64, I> {
        let i = char('0')
            .map(|_| 0.0)
            .or(Json::<I>::integer().map(|x| x as f64));
        let fractional = many(digit()).map(|digits: String| {
            let mut magnitude = 1.0;
            digits.chars().fold(0.0, |acc, d| {
                magnitude /= 10.0;
                match d.to_digit(10) {
                    Some(d) => acc + (d as f64) * magnitude,
                    None => panic!("Not a digit"),
                }
            })
        });

        let exp = satisfy(|c| c == 'e' || c == 'E')
            .with(optional(char('-')).and(Json::<I>::integer()));
        lex(optional(char('-'))
                .and(i)
                .map(|(sign, n)| if sign.is_some() { -n } else { n })
                .and(optional(char('.')).with(fractional))
                .map(|(x, y)| if x > 0.0 { x + y } else { x - y })
                .and(optional(exp))
                .map(|(n, exp_option)| match exp_option {
                    Some((sign, e)) => {
                        let e = if sign.is_some() { -e } else { e };
                        n * 10.0f64.powi(e as i32)
                    }
                    None => n,
                }))
            .parse_lazy(input)
            .into()
    }

    fn char() -> JsonParser<char, I> {
        fn_parser(Json::<I>::char_, "char")
    }
    fn char_(input: I) -> ParseResult<char, I> {
        let (c, input) = try!(any().parse_lazy(input).into());
        let mut back_slash_char = satisfy(|c| "\"\\/bfnrt".chars().any(|x| x == c)).map(|c| {
            match c {
                '"' => '"',
                '\\' => '\\',
                '/' => '/',
                'b' => '\u{0008}',
                'f' => '\u{000c}',
                'n' => '\n',
                'r' => '\r',
                't' => '\t',
                c => c,//Should never happen
            }
        });
        match c {
            '\\' => input.combine(|input| back_slash_char.parse_stream(input)),
            '"' => {
                Err(Consumed::Empty(ParseError::from_errors(input.into_inner().position(),
                                                            Vec::new())))
            }
            _ => Ok((c, input)),
        }
    }
    fn string() -> JsonParser<String, I> {
        fn_parser(Json::<I>::string_, "string")
    }
    fn string_(input: I) -> ParseResult<String, I> {
        between(char('"'), lex(char('"')), many(Json::<I>::char())).parse_lazy(input).into()
    }

    fn object() -> JsonParser<Value, I> {
        fn_parser(Json::<I>::object_, "object")
    }
    fn object_(input: I) -> ParseResult<Value, I> {
        let field = (Json::<I>::string(), lex(char(':')), Json::<I>::value()).map(|t| (t.0, t.2));
        let fields = sep_by(field, lex(char(',')));
        between(lex(char('{')), lex(char('}')), fields)
            .map(Value::Object)
            .parse_lazy(input)
            .into()
    }

    fn value() -> FnPtrParser<Value, I> {
        parser(Json::<I>::value_ as fn(_) -> _)
    }
    #[allow(unconditional_recursion)]
    fn value_(input: I) -> ParseResult<Value, I> {
        let mut array = between(lex(char('[')),
                                lex(char(']')),
                                sep_by(Json::<I>::value(), lex(char(','))))
            .map(Value::Array);

        choice::<[&mut Parser<Input = I, Output = Value>; 7],
                 _>([&mut Json::<I>::string().map(Value::String),
                     &mut Json::<I>::object(),
                     &mut array,
                     &mut Json::<I>::number().map(Value::Number),
                     &mut lex(string("false").map(|_| Value::Bool(false))),
                     &mut lex(string("true").map(|_| Value::Bool(true))),
                     &mut lex(string("null").map(|_| Value::Null))])
            .parse_lazy(input)
            .into()
    }
}

#[test]
fn json_test() {
    use self::Value::*;
    let input = r#"{
    "array": [1, ""],
    "object": {},
    "number": 3.14,
    "int": -100,
    "exp": -1e2,
    "exp_neg": 23e-2,
    "true": true,
    "false"  : false,
    "null" : null
}"#;
    let result = Json::value().parse(input);
    let expected = Object(vec![("array", Array(vec![Number(1.0), String("".to_string())])),
                               ("object", Object(HashMap::new())),
                               ("number", Number(3.14)),
                               ("int", Number(-100.)),
                               ("exp", Number(-1e2)),
                               ("exp_neg", Number(23E-2)),
                               ("true", Bool(true)),
                               ("false", Bool(false)),
                               ("null", Null)]
        .into_iter()
        .map(|(k, v)| (k.to_string(), v))
        .collect());
    match result {
        Ok(result) => assert_eq!(result, (expected, "")),
        Err(e) => {
            println!("{}", e);
            assert!(false);
        }
    }
}

#[bench]
fn bench_json(bencher: &mut ::test::Bencher) {
    let mut data = String::new();
    File::open(&Path::new(&"benches/data.json"))
        .and_then(|mut file| file.read_to_string(&mut data))
        .unwrap();
    let mut parser = Json::value();
    match parser.parse(State::new(&data[..])) {
        Ok((Value::Array(_), _)) => (),
        Ok(_) => assert!(false),
        Err(err) => {
            println!("{}", err);
            assert!(false);
        }
    }
    bencher.iter(|| {
        let result = parser.parse(State::new(&data[..]));
        ::test::black_box(result)
    });
}

#[bench]
fn bench_buffered_json(bencher: &mut ::test::Bencher) {
    let mut data = String::new();
    File::open(&Path::new(&"benches/data.json"))
        .and_then(|mut file| file.read_to_string(&mut data))
        .unwrap();
    bencher.iter(|| {
        let buffer = BufferedStream::new(from_iter(data.chars()), 1);
        let mut parser = Json::value();
        match parser.parse(State::new(buffer.as_stream())) {
            Ok((Value::Array(v), _)) => {
                ::test::black_box(v);
            }
            Ok(_) => assert!(false),
            Err(err) => {
                println!("{}", err);
                assert!(false);
            }
        }
    });
}
<|endoftext|>


<commit_before>
use {
    BackEnd,
    Borrowed,
    Clear,
    Field,
    Fill,
    Image,
    Value,
};
use triangulation::{
    with_round_rectangle_tri_list_xy_f32_rgba_f32
};
use internal::{
    CanColor,
    CanRectangle,
    CanTransform,
    CanViewTransform,
    Color,
    HasColor,
    HasRectangle,
    HasTransform,
    HasViewTransform,
    Matrix2d,
    Radius,
    Rectangle,
};

/// A round rectangle color context.
pub struct RoundRectangleColorContext<'a> {
    /// View transformation.
    pub view: Field<'a, Matrix2d>,
    /// Current transformation.
    pub transform: Field<'a, Matrix2d>,
    /// Current rectangle.
    pub rect: Field<'a, Rectangle>,
    /// Current roundness radius.
    pub round_radius: Field<'a, Radius>,
    /// Current color.
    pub color: Field<'a, Color>,
}

impl<'a> Clone for RoundRectangleColorContext<'a> {
    #[inline(always)]
    fn clone(&self) -> RoundRectangleColorContext<'static> {
        RoundRectangleColorContext {
            view: Value(*self.view.get()),
            transform: Value(*self.transform.get()),
            rect: Value(*self.rect.get()),
            round_radius: Value(*self.round_radius.get()),
            color: Value(*self.color.get()),
        }
    }
}

impl<'a> HasTransform<'a, Matrix2d> for RoundRectangleColorContext<'a> {
    #[inline(always)]
    fn get_transform(&'a self) -> &'a Matrix2d {
        self.transform.get()
    }
}

impl<'a> CanTransform<'a, RoundRectangleColorContext<'a>, Matrix2d> for RoundRectangleColorContext<'a> {
    #[inline(always)]
    fn transform(&'a self, value: Matrix2d) -> RoundRectangleColorContext<'a> {
        RoundRectangleColorContext {
            view: Borrowed(self.view.get()),
            transform: Value(value),
            rect: Borrowed(self.rect.get()),
            round_radius: Borrowed(self.round_radius.get()),
            color: Borrowed(self.color.get()),
        }
    }
}

impl<'a> HasViewTransform<'a, Matrix2d> for RoundRectangleColorContext<'a> {
    #[inline(always)]
    fn get_view_transform(&'a self) -> &'a Matrix2d {
        self.view.get()
    }
}

impl<'a> CanViewTransform<'a, RoundRectangleColorContext<'a>, Matrix2d>
for RoundRectangleColorContext<'a> {
    #[inline(always)]
    fn view_transform(&'a self, value: Matrix2d) -> RoundRectangleColorContext<'a> {
        RoundRectangleColorContext {
            view: Value(value),
            transform: Borrowed(self.transform.get()),
            rect: Borrowed(self.rect.get()),
            round_radius: Borrowed(self.round_radius.get()),
            color: Borrowed(self.color.get()),
        }
    }
}

impl<'a> HasColor<'a, Color> for RoundRectangleColorContext<'a> {
    #[inline(always)]
    fn get_color(&'a self) -> &'a Color {
        self.color.get()
    }
}

impl<'a> CanColor<'a, RoundRectangleColorContext<'a>, Color> for RoundRectangleColorContext<'a> {
    #[inline(always)]
    fn color(&'a self, value: Color) -> RoundRectangleColorContext<'a> {
        RoundRectangleColorContext {
            view: Borrowed(self.view.get()),
            transform: Borrowed(self.transform.get()),
            color: Value(value),
            rect: Borrowed(self.rect.get()),
            round_radius: Borrowed(self.round_radius.get()),
        }
    }
}

impl<'a> HasRectangle<'a, Rectangle> for RoundRectangleColorContext<'a> {
    #[inline(always)]
    fn get_rectangle(&'a self) -> &'a Rectangle {
        self.rect.get()
    }
}

impl<'a> CanRectangle<'a, RoundRectangleColorContext<'a>, Rectangle> for RoundRectangleColorContext<'a> {
    #[inline(always)]
    fn rectangle(&'a self, rect: Rectangle) -> RoundRectangleColorContext<'a> {
        RoundRectangleColorContext {
            view: Borrowed(self.view.get()),
            transform: Borrowed(self.transform.get()),
            rect: Value(rect),
            round_radius: Borrowed(self.round_radius.get()),
            color: Borrowed(self.color.get()),
        }
    }
}

impl<'a, B: BackEnd<I>, I: Image> Clear<B, I> for RoundRectangleColorContext<'a> {
    fn clear(&self, back_end: &mut B) {
        if back_end.supports_clear_rgba() {
            let color = self.color.get();
            back_end.clear_rgba(color[0], color[1], color[2], color[3]);
        } else {
            unimplemented!();
        }
    }
}

impl<'a> Fill<'a> for RoundRectangleColorContext<'a> {
    #[inline(always)]
    fn fill<B: BackEnd<I>, I: Image>(&'a self, back_end: &mut B) {
        if back_end.supports_tri_list_xy_f32_rgba_f32() {
            let rect = self.rect.get();
            let round_radius = self.round_radius.get();
            let color = self.color.get();
            // Complete transparency does not need to be rendered.
            if color[3] == 0.0 { return; }
            // Turn on alpha blending if not completely opaque.
            let needs_alpha = color[3] != 1.0;
            if needs_alpha { back_end.enable_alpha_blend(); }
            with_round_rectangle_tri_list_xy_f32_rgba_f32(
                32,
                *self.transform.get(),
                *rect,
                *round_radius,
                *color,
                |vertices, colors| {
                    back_end.tri_list_xy_f32_rgba_f32(vertices, colors)
                }
            );
            if needs_alpha { back_end.disable_alpha_blend(); }
        } else {
            unimplemented!();
        }
    }
}

<commit_msg>Implemented `AddBorder` for `RoundRectangleColorContext`<commit_after>
use {
    AddBorder,
    BackEnd,
    Borrowed,
    Clear,
    Field,
    Fill,
    Image,
    RoundRectangleBorderColorContext,
    Value,
};
use triangulation::{
    with_round_rectangle_tri_list_xy_f32_rgba_f32
};
use internal::{
    CanColor,
    CanRectangle,
    CanTransform,
    CanViewTransform,
    Color,
    HasColor,
    HasRectangle,
    HasTransform,
    HasViewTransform,
    Matrix2d,
    Radius,
    Rectangle,
};

/// A round rectangle color context.
pub struct RoundRectangleColorContext<'a> {
    /// View transformation.
    pub view: Field<'a, Matrix2d>,
    /// Current transformation.
    pub transform: Field<'a, Matrix2d>,
    /// Current rectangle.
    pub rect: Field<'a, Rectangle>,
    /// Current roundness radius.
    pub round_radius: Field<'a, Radius>,
    /// Current color.
    pub color: Field<'a, Color>,
}

impl<'a> Clone for RoundRectangleColorContext<'a> {
    #[inline(always)]
    fn clone(&self) -> RoundRectangleColorContext<'static> {
        RoundRectangleColorContext {
            view: Value(*self.view.get()),
            transform: Value(*self.transform.get()),
            rect: Value(*self.rect.get()),
            round_radius: Value(*self.round_radius.get()),
            color: Value(*self.color.get()),
        }
    }
}

impl<'a> HasTransform<'a, Matrix2d> for RoundRectangleColorContext<'a> {
    #[inline(always)]
    fn get_transform(&'a self) -> &'a Matrix2d {
        self.transform.get()
    }
}

impl<'a> CanTransform<'a, RoundRectangleColorContext<'a>, Matrix2d> for RoundRectangleColorContext<'a> {
    #[inline(always)]
    fn transform(&'a self, value: Matrix2d) -> RoundRectangleColorContext<'a> {
        RoundRectangleColorContext {
            view: Borrowed(self.view.get()),
            transform: Value(value),
            rect: Borrowed(self.rect.get()),
            round_radius: Borrowed(self.round_radius.get()),
            color: Borrowed(self.color.get()),
        }
    }
}

impl<'a> HasViewTransform<'a, Matrix2d> for RoundRectangleColorContext<'a> {
    #[inline(always)]
    fn get_view_transform(&'a self) -> &'a Matrix2d {
        self.view.get()
    }
}

impl<'a> CanViewTransform<'a, RoundRectangleColorContext<'a>, Matrix2d>
for RoundRectangleColorContext<'a> {
    #[inline(always)]
    fn view_transform(&'a self, value: Matrix2d) -> RoundRectangleColorContext<'a> {
        RoundRectangleColorContext {
            view: Value(value),
            transform: Borrowed(self.transform.get()),
            rect: Borrowed(self.rect.get()),
            round_radius: Borrowed(self.round_radius.get()),
            color: Borrowed(self.color.get()),
        }
    }
}

impl<'a> HasColor<'a, Color> for RoundRectangleColorContext<'a> {
    #[inline(always)]
    fn get_color(&'a self) -> &'a Color {
        self.color.get()
    }
}

impl<'a> CanColor<'a, RoundRectangleColorContext<'a>, Color> for RoundRectangleColorContext<'a> {
    #[inline(always)]
    fn color(&'a self, value: Color) -> RoundRectangleColorContext<'a> {
        RoundRectangleColorContext {
            view: Borrowed(self.view.get()),
            transform: Borrowed(self.transform.get()),
            color: Value(value),
            rect: Borrowed(self.rect.get()),
            round_radius: Borrowed(self.round_radius.get()),
        }
    }
}

impl<'a> HasRectangle<'a, Rectangle> for RoundRectangleColorContext<'a> {
    #[inline(always)]
    fn get_rectangle(&'a self) -> &'a Rectangle {
        self.rect.get()
    }
}

impl<'a> CanRectangle<'a, RoundRectangleColorContext<'a>, Rectangle> for RoundRectangleColorContext<'a> {
    #[inline(always)]
    fn rectangle(&'a self, rect: Rectangle) -> RoundRectangleColorContext<'a> {
        RoundRectangleColorContext {
            view: Borrowed(self.view.get()),
            transform: Borrowed(self.transform.get()),
            rect: Value(rect),
            round_radius: Borrowed(self.round_radius.get()),
            color: Borrowed(self.color.get()),
        }
    }
}

impl<'a, B: BackEnd<I>, I: Image> Clear<B, I> for RoundRectangleColorContext<'a> {
    fn clear(&self, back_end: &mut B) {
        if back_end.supports_clear_rgba() {
            let color = self.color.get();
            back_end.clear_rgba(color[0], color[1], color[2], color[3]);
        } else {
            unimplemented!();
        }
    }
}

impl<'a> Fill<'a> for RoundRectangleColorContext<'a> {
    #[inline(always)]
    fn fill<B: BackEnd<I>, I: Image>(&'a self, back_end: &mut B) {
        if back_end.supports_tri_list_xy_f32_rgba_f32() {
            let rect = self.rect.get();
            let round_radius = self.round_radius.get();
            let color = self.color.get();
            // Complete transparency does not need to be rendered.
            if color[3] == 0.0 { return; }
            // Turn on alpha blending if not completely opaque.
            let needs_alpha = color[3] != 1.0;
            if needs_alpha { back_end.enable_alpha_blend(); }
            with_round_rectangle_tri_list_xy_f32_rgba_f32(
                32,
                *self.transform.get(),
                *rect,
                *round_radius,
                *color,
                |vertices, colors| {
                    back_end.tri_list_xy_f32_rgba_f32(vertices, colors)
                }
            );
            if needs_alpha { back_end.disable_alpha_blend(); }
        } else {
            unimplemented!();
        }
    }
}

impl<'a> AddBorder<'a, RoundRectangleBorderColorContext<'a>>
for RoundRectangleColorContext<'a> {
    #[inline(always)]
    fn border_radius(&'a self, radius: f64) -> RoundRectangleBorderColorContext<'a> {
        RoundRectangleBorderColorContext {
            view: Borrowed(self.view.get()),
            transform: Borrowed(self.transform.get()),
            rect: Borrowed(self.rect.get()),
            round_radius: Borrowed(self.round_radius.get()),
            color: Borrowed(self.color.get()),
            border: Value(radius),
        }
    }
}

<|endoftext|>


<commit_before>#![crate_id = "seax-svm"]
#![crate_type="lib"]
#![feature(box_syntax)]
#![allow(dead_code)]

/// Contains the Seax Virtual Machine (SVM) and miscellaneous
/// support code.
pub mod svm {

    use svm::slist::List;
    use svm::slist::Stack;

    /// Singly-linked list and stack implementations.
    pub mod slist {

        use svm::slist::List::{Cons,Nil};
        use std::fmt::Show;

        /// A stack implementation wrapping a List<T>
        pub struct Stack<T> {
            /// The head item of the list.
            head: Box<List<T>>
        }

        impl<T> Stack<T> {
            /// Push an item to the top of the stack, returning a new stack
            pub fn push(self, it: T) -> Stack<T> {
                Stack { head: Box::new(self.head.prepend(it)) }
            }

            /// Peak at the top item of the stack.
            ///
            /// Returns Some<T> if there is an item on top of the stack,
            /// and None if the stack is empty.
            pub fn peek(&self) -> Option<&T> {
                match *self.head {
                    Nil => None,
                    Cons(ref it,_) => Some(it)
                }
            }

            /// Returns an empty stack.
            pub fn empty() -> Stack<T> {
                Stack { head: box Nil }
            }

            /// Wraps a list into a stack.
            pub fn new(l: List<T>) -> Stack<T> {
                Stack { head: box l }
            }
        }

        /// Singly-linked cons list.
        ///
        /// This is used internally to represent list primitives in the machine.
        pub enum List<T> {
            Cons(T, Box<List<T>>),
            Nil,
        }

        /// Public implementation for List.
        impl<T> List<T> {

            /// Creates a new empty list
            pub fn new() -> List<T> {
                Nil
            }

            /// Prepends the given item to the list
            pub fn prepend(self, it: T) -> List<T> {
                Cons(it, box self)
            }

            /// Returns the length of the list
            pub fn length (&self) -> i32 {
                match *self {
                    Cons(_, ref tail) => 1 + tail.length(),
                    Nil => 0
                }
            }
        }

        impl<T> List<T> where T: Show {
            /// Return a string representation of the list
            fn to_string(&self) -> String {
                match *self {
                    Cons(ref head, ref tail) => format!("({:?}, {})", head, tail.to_string()),
                    Nil => format!("nil")
                }
            }

        }

       macro_rules! list(
            ( $e:expr, $($rest:expr),+ ) => ( Cons($e, Box::new(list!( $( $rest ),+ )) ));
            ( $e:expr ) => ( Cons($e, Box::new(Nil)) );
            () => ( @Empty )
        );

        #[cfg(test)]
        mod tests {
            use super::{List, Stack};
            use super::List::{Cons,Nil};

            #[test]
            fn test_list_length() {
                let l: List<i32> = Cons(1, Box::new(Cons(2, Box::new(Cons(3, Box::new(Nil))))));
                assert_eq!(l.length(), 3);
            }

            #[test]
            fn test_list_to_string() {
                let l: List<i32> = Cons(1, Box::new(Cons(2, Box::new(Cons(3, Box::new(Nil))))));
                assert_eq!(l.to_string(), "(1i32, (2i32, (3i32, nil)))");
            }

            #[test]
            fn test_stack_peek() {
                let s: Stack<i32> = Stack::new(Cons(1, Box::new(Cons(2, Box::new(Nil)))));
                assert_eq!(s.peek(), Some(&1));
            }

            #[test]
            fn test_stack_push() {
                let mut s: Stack<i32> = Stack::empty();
                assert_eq!(s.peek(), None);
                s = s.push(1);
                assert_eq!(s.peek(), Some(&1));
                s = s.push(6);
                assert_eq!(s.peek(), Some(&6));
            }

            #[test]
            fn test_stack_pop() {
                let mut s: Stack<i32> = Stack::empty();
                assert_eq!(s.peek(), None);
                s = s.push(1);
                assert_eq!(s.peek(), Some(&1));
                s = s.push(6);
                assert_eq!(s.peek(), Some(&6));
            }

            #[test]
            fn test_list_macro() {
                let l: List<i32> = list!(1i32, 2i32, 3i32);
                assert_eq!(l.to_string(), "(1i32, (2i32, (3i32, nil)))")
            }
        }
    }

    /// SVM item types
    pub enum SVMCell {
        Atom,
        ListCell(Box<List<SVMCell>>)
    }

    pub enum Atom {
        AtomUInt(usize),
        AtomSInt(isize),
        AtomFloat(f64),
        AtomStr(String)
    }

    /// SVM instruction types
    pub enum SVMInstruction {
        /// `nil`
        ///
        /// Pushes an empty list (nil) onto the stack
        InstNIL,
        /// `ldc`: `L`oa`d` `C`onstant. Loads a constant (atom)
        InstLDC(Atom),
        /// `ld`: `L`oa`d`. Pushes a variable onto the stack.
        ///
        /// The variable is indicated by the argument, a pair.
        /// The pair's `car` specifies the level, the `cdr` the position.
        /// So `(1 . 3)` gives the current function's (level 1) third parameter.
        InstLD,
        /// `ldf`: `L`oa`d` `F`unction.
        ///
        ///  Takes one list argument representing a function and constructs
        ///  a closure (a pair containing the function and the current
        ///  environment) and pushes that onto the stack.
        InstLDF,
        /// `join`
        ///
        /// Pops a list reference from the dump and makes this the new value
        /// of `C`. This instruction occurs at the end of both alternatives of
        ///  a `sel`.
        InstJOIN,
        /// `ap`: `Ap`ply.
        ///
        /// Pops a closure and a list of parameter values from the stack.
        /// The closure is applied to the parameters by installing its
        /// environment as the current one, pushing the parameter list
        /// in front of that, clearing the stack, and setting `C` to the
        /// closure's function pointer. The previous values of `S`, `E`,
        ///  and the next value of `C` are saved on the dump.
        InstAP,
        /// `ret`: `Ret`urn.
        ///
        /// Pops one return value from the stack, restores
        /// `S`, `E`, and `C` from the dump, and pushes
        /// the return value onto the now-current stack.
        InstRET,
        /// `dum`: `Dum`my.
        ///
        /// Pops a dummy environment (an empty list) onto the `E` stack.
        InstDUM,
        /// `rap`: `R`ecursive `Ap`ply.
        /// Works like `ap`, only that it replaces an occurrence of a
        /// dummy environment with the current one, thus making recursive
        ///  functions possible.
        InstRAP,
        /// `sel`: `Sel`ect
        ///
        /// Expects two list arguments, and pops a value from the stack.
        /// The first list is executed if the popped value was non-nil,
        /// the second list otherwise. Before one of these list pointers
        ///  is made the new `C`, a pointer to the instruction following
        ///  `sel` is saved on the dump.
        InstSEL
        // TODO:
    }

    /// Represents a SVM machine state
    pub struct State {
        stack: Stack<SVMCell>,
        env: Stack<SVMCell>,
        control: Stack<SVMCell>,
        dump: Stack<SVMCell>
    }

    impl State {

        /// Creates a new empty state
        fn new() -> State {
            State {
                stack: Stack::empty(),
                env: Stack::empty(),
                control: Stack::empty(),
                dump: Stack::empty()
            }
        }

        pub fn eval(self, inst: SVMInstruction) -> State {
            match inst {
                SVMInstruction::InstNIL => State {
                    stack: self.stack.push(SVMCell::ListCell(box List::new())),
                    env: self.env,
                    control: self.control,
                    dump: self.dump
                },
                _ => { unimplemented!() }
            }
        }

    }
}
<commit_msg>Add math instructions to SVMInstruction<commit_after>#![crate_id = "seax-svm"]
#![crate_type="lib"]
#![feature(box_syntax)]
#![allow(dead_code)]

/// Contains the Seax Virtual Machine (SVM) and miscellaneous
/// support code.
pub mod svm {
    use svm::slist::List;
    use svm::slist::Stack;
    use std::iter::IteratorExt;

    /// Singly-linked list and stack implementations.
    pub mod slist {

        use svm::slist::List::{Cons,Nil};
        use std::fmt::Show;

        /// A stack implementation wrapping a List<T>
        pub struct Stack<T> {
            /// The head item of the list.
            head: Box<List<T>>
        }

        impl<T> Stack<T> {
            /// Push an item to the top of the stack, returning a new stack
            pub fn push(self, it: T) -> Stack<T> {
                Stack { head: Box::new(self.head.prepend(it)) }
            }

            /// Peak at the top item of the stack.
            ///
            /// Returns Some<T> if there is an item on top of the stack,
            /// and None if the stack is empty.
            pub fn peek(&self) -> Option<&T> {
                match *self.head {
                    Nil => None,
                    Cons(ref it,_) => Some(it)
                }
            }

            /// Returns an empty stack.
            pub fn empty() -> Stack<T> {
                Stack { head: box Nil }
            }

            /// Wraps a list into a stack.
            pub fn new(l: List<T>) -> Stack<T> {
                Stack { head: box l }
            }
        }

        /// Singly-linked cons list.
        ///
        /// This is used internally to represent list primitives in the machine.
        pub enum List<T> {
            Cons(T, Box<List<T>>),
            Nil,
        }

        /// Public implementation for List.
        impl<T> List<T> {

            /// Creates a new empty list
            pub fn new() -> List<T> {
                Nil
            }

            /// Prepends the given item to the list
            pub fn prepend(self, it: T) -> List<T> {
                Cons(it, box self)
            }

            /// Returns the length of the list
            pub fn length (&self) -> i32 {
                match *self {
                    Cons(_, ref tail) => 1 + tail.length(),
                    Nil => 0
                }
            }
        }

        impl<T> List<T> where T: Show {
            /// Return a string representation of the list
            fn to_string(&self) -> String {
                match *self {
                    Cons(ref head, ref tail) => format!("({:?}, {})", head, tail.to_string()),
                    Nil => format!("nil")
                }
            }

        }

       macro_rules! list(
            ( $e:expr, $($rest:expr),+ ) => ( Cons($e, Box::new(list!( $( $rest ),+ )) ));
            ( $e:expr ) => ( Cons($e, Box::new(Nil)) );
            () => ( @Empty )
        );

        #[cfg(test)]
        mod tests {
            use super::{List, Stack};
            use super::List::{Cons,Nil};

            #[test]
            fn test_list_length() {
                let l: List<i32> = Cons(1, Box::new(Cons(2, Box::new(Cons(3, Box::new(Nil))))));
                assert_eq!(l.length(), 3);
            }

            #[test]
            fn test_list_to_string() {
                let l: List<i32> = Cons(1, Box::new(Cons(2, Box::new(Cons(3, Box::new(Nil))))));
                assert_eq!(l.to_string(), "(1i32, (2i32, (3i32, nil)))");
            }

            #[test]
            fn test_stack_peek() {
                let s: Stack<i32> = Stack::new(Cons(1, Box::new(Cons(2, Box::new(Nil)))));
                assert_eq!(s.peek(), Some(&1));
            }

            #[test]
            fn test_stack_push() {
                let mut s: Stack<i32> = Stack::empty();
                assert_eq!(s.peek(), None);
                s = s.push(1);
                assert_eq!(s.peek(), Some(&1));
                s = s.push(6);
                assert_eq!(s.peek(), Some(&6));
            }

            #[test]
            fn test_stack_pop() {
                let mut s: Stack<i32> = Stack::empty();
                assert_eq!(s.peek(), None);
                s = s.push(1);
                assert_eq!(s.peek(), Some(&1));
                s = s.push(6);
                assert_eq!(s.peek(), Some(&6));
            }

            #[test]
            fn test_list_macro() {
                let l: List<i32> = list!(1i32, 2i32, 3i32);
                assert_eq!(l.to_string(), "(1i32, (2i32, (3i32, nil)))")
            }
        }
    }

    /// SVM item types
    pub enum SVMCell {
        Atom,
        ListCell(Box<List<SVMCell>>)
    }

    pub enum Atom {
        AtomUInt(usize),
        AtomSInt(isize),
        AtomFloat(f64),
        AtomStr(String)
    }

    /// SVM instruction types
    pub enum SVMInstruction {
        /// `nil`
        ///
        /// Pushes an empty list (nil) onto the stack
        InstNIL,
        /// `ldc`: `L`oa`d` `C`onstant. Loads a constant (atom)
        InstLDC(Atom),
        /// `ld`: `L`oa`d`. Pushes a variable onto the stack.
        ///
        /// The variable is indicated by the argument, a pair.
        /// The pair's `car` specifies the level, the `cdr` the position.
        /// So `(1 . 3)` gives the current function's (level 1) third
        /// parameter.
        InstLD,
        /// `ldf`: `L`oa`d` `F`unction.
        ///
        ///  Takes one list argument representing a function and constructs
        ///  a closure (a pair containing the function and the current
        ///  environment) and pushes that onto the stack.
        InstLDF,
        /// `join`
        ///
        /// Pops a list reference from the dump and makes this the new value
        /// of `C`. This instruction occurs at the end of both alternatives of
        ///  a `sel`.
        InstJOIN,
        /// `ap`: `Ap`ply.
        ///
        /// Pops a closure and a list of parameter values from the stack.
        /// The closure is applied to the parameters by installing its
        /// environment as the current one, pushing the parameter list
        /// in front of that, clearing the stack, and setting `C` to the
        /// closure's function pointer. The previous values of `S`, `E`,
        ///  and the next value of `C` are saved on the dump.
        InstAP,
        /// `ret`: `Ret`urn.
        ///
        /// Pops one return value from the stack, restores
        /// `S`, `E`, and `C` from the dump, and pushes
        /// the return value onto the now-current stack.
        InstRET,
        /// `dum`: `Dum`my.
        ///
        /// Pops a dummy environment (an empty list) onto the `E` stack.
        InstDUM,
        /// `rap`: `R`ecursive `Ap`ply.
        /// Works like `ap`, only that it replaces an occurrence of a
        /// dummy environment with the current one, thus making recursive
        ///  functions possible.
        InstRAP,
        /// `sel`: `Sel`ect
        ///
        /// Expects two list arguments, and pops a value from the stack.
        /// The first list is executed if the popped value was non-nil,
        /// the second list otherwise. Before one of these list pointers
        ///  is made the new `C`, a pointer to the instruction following
        ///  `sel` is saved on the dump.
        InstSEL,
        /// `add`
        ///
        /// Pops two numbers off of the stack and adds them, pushing the
        /// result onto the stack. This will up-convert integers to floating
        /// point if necessary.
        ///
        /// TODO: figure out what happens when you try to add things that aren't
        /// numbers (maybe the compiler won't let this happen?).
        InstADD,
        /// `sub`: `Sub`tract
        ///
        /// Pops two numbers off of the stack and subtracts the first from the
        /// second, pushing the result onto the stack. This will up-convert
        /// integers to floating point if necessary.
        ///
        /// TODO: figure out what happens when you try to subtract things that
        /// aren't numbers (maybe the compiler won't let this happen?).
        InstSUB,
        /// `mul`: `Mul`tiply
        ///
        /// Pops two numbers off of the stack and multiplies them, pushing the
        /// result onto the stack. This will up-convert integers to floating
        /// point if necessary.
        ///
        /// TODO: figure out what happens when you try to multiply things that
        /// aren't numbers (maybe the compiler won't let this happen?).
        InstMUL,
        /// `div`: `Div`ide
        ///
        /// Pops two numbers off of the stack and divides the first by the second,
        /// pushing the result onto the stack. This performs integer division.
        ///
        /// TODO: figure out what happens when you try to divide things that
        /// aren't numbers (maybe the compiler won't let this happen?).
        InstDIV,
        /// `fdiv`: `F`loating-point `div`ide
        ///
        /// Pops two numbers off of the stack and divides the first by the second,
        /// pushing the result onto the stack. This performs float division.
        ///
        /// TODO: figure out what happens when you try to divide things that
        /// aren't numbers (maybe the compiler won't let this happen?).
        ///
        /// TODO: Not sure if there should be separate float and int divide words
        /// I guess the compiler can figure this out
        InstFDIV,
        /// `mod`: `Mod`ulo
        ///
        /// Pops two numbers off of the stack and divides the first by the second,
        /// pushing the remainder onto the stack.
        ///
        /// TODO: figure out what happens when you try to modulo things that
        /// aren't numbers (maybe the compiler won't let this happen?).
        InstMOD
        // TODO: add some hardcoded I/O instructions here so that you can
        //  do I/O without farming everything out to `stdio`
        // TODO: add `cons` and `cdr` words
    }

    /// Represents a SVM machine state
    pub struct State {
        stack: Stack<SVMCell>,
        env: Stack<SVMCell>,
        control: Stack<SVMCell>,
        dump: Stack<SVMCell>
    }

    impl State {

        /// Creates a new empty state
        fn new() -> State {
            State {
                stack: Stack::empty(),
                env: Stack::empty(),
                control: Stack::empty(),
                dump: Stack::empty()
            }
        }

        /// Evaluates an instruction.
        ///
        /// Evaluates an instruction against a state, returning a new state.
        pub fn eval(self, inst: SVMInstruction) -> State {
            match inst {
                SVMInstruction::InstNIL => State {
                    stack: self.stack.push(SVMCell::ListCell(box List::new())),
                    env: self.env,
                    control: self.control,
                    dump: self.dump
                },
                _ => { unimplemented!() }
            }
        }
    }

}
<|endoftext|>