<commit_before>//============================================================================
//
// A simple Mandelbrot image generator in Rust
//
// Main entry point for GUI
//
// Copyright (c) 2014 Gavin Baker <gavinb@antonym.org>
// Published under the MIT license
//
//============================================================================

#[macro_use]
extern crate glium;
extern crate glutin;

//----------------------------------------------------------------------------

fn main() {

    use glium::DisplayBuild;

    let window = glium::glutin::WindowBuilder::new()
        .with_dimensions(512, 512)
        .with_title("MandelRust".to_string())
        .build_glium()
        .unwrap();

    loop {
        for ev in window.poll_events() {
            match ev {
                glium::glutin::Event::Closed => return,
                _ => ()
            }
        }
    }
}
<commit_msg>Clear screen<commit_after>//============================================================================
//
// A simple Mandelbrot image generator in Rust
//
// Main entry point for GUI
//
// Copyright (c) 2014 Gavin Baker <gavinb@antonym.org>
// Published under the MIT license
//
//============================================================================

#[macro_use]
extern crate glium;
extern crate glutin;

//----------------------------------------------------------------------------

fn main() {

    use glium::{DisplayBuild,Surface};

    let window = glium::glutin::WindowBuilder::new()
        .with_dimensions(512, 512)
        .with_title("MandelRust".to_string())
        .build_glium()
        .unwrap();

    loop {
        let mut target = window.draw();
        target.clear_color(0.0, 0.0, 1.0, 1.0);
        target.finish().unwrap();

        for ev in window.poll_events() {
            match ev {
                glium::glutin::Event::Closed => return,
                _ => ()
            }
        }
    }
}
<|endoftext|>


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

#[cfg(feature = "gecko")]
#[macro_use]
extern crate lazy_static;
#[cfg(feature = "bindgen")]
extern crate bindgen;
#[cfg(feature = "bindgen")]
extern crate log;
#[cfg(feature = "bindgen")]
extern crate regex;
extern crate walkdir;

use std::env;
use std::path::Path;
use std::process::{Command, exit};
use walkdir::WalkDir;

#[cfg(feature = "gecko")]
mod build_gecko;

#[cfg(not(feature = "gecko"))]
mod build_gecko {
    pub fn generate() {}
}

#[cfg(windows)]
fn find_python() -> String {
    if Command::new("python2.7.exe").arg("--version").output().is_ok() {
        return "python2.7.exe".to_owned();
    }

    if Command::new("python27.exe").arg("--version").output().is_ok() {
        return "python27.exe".to_owned();
    }

    if Command::new("python.exe").arg("--version").output().is_ok() {
        return "python.exe".to_owned();
    }

    panic!(concat!("Can't find python (tried python2.7.exe, python27.exe, and python.exe)! ",
                   "Try fixing PATH or setting the PYTHON env var"));
}

#[cfg(not(windows))]
fn find_python() -> String {
    if Command::new("python2.7").arg("--version").output().unwrap().status.success() {
        "python2.7"
    } else {
        "python"
    }.to_owned()
}

fn generate_properties() {
    for entry in WalkDir::new("properties") {
        let entry = entry.unwrap();
        match entry.path().extension().and_then(|e| e.to_str()) {
            Some("mako") | Some("rs") | Some("py") | Some("zip") => {
                println!("cargo:rerun-if-changed={}", entry.path().display());
            }
            _ => {}
        }
    }

    let python = env::var("PYTHON").ok().unwrap_or_else(find_python);
    let script = Path::new(file!()).parent().unwrap().join("properties").join("build.py");
    let product = if cfg!(feature = "gecko") { "gecko" } else { "servo" };
    let status = Command::new(python)
        .arg(&script)
        .arg(product)
        .arg("style-crate")
        .arg(if cfg!(feature = "testing") { "testing" } else { "regular" })
        .status()
        .unwrap();
    if !status.success() {
        exit(1)
    }
}

fn main() {
    println!("cargo:rerun-if-changed=build.rs");
    generate_properties();
    build_gecko::generate();
}
<commit_msg>Move python path into a lazy static.<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#[macro_use]
extern crate lazy_static;
#[cfg(feature = "bindgen")]
extern crate bindgen;
#[cfg(feature = "bindgen")]
extern crate log;
#[cfg(feature = "bindgen")]
extern crate regex;
extern crate walkdir;

use std::env;
use std::path::Path;
use std::process::{Command, exit};
use walkdir::WalkDir;

#[cfg(feature = "gecko")]
mod build_gecko;

#[cfg(not(feature = "gecko"))]
mod build_gecko {
    pub fn generate() {}
}

#[cfg(windows)]
fn find_python() -> String {
    if Command::new("python2.7.exe").arg("--version").output().is_ok() {
        return "python2.7.exe".to_owned();
    }

    if Command::new("python27.exe").arg("--version").output().is_ok() {
        return "python27.exe".to_owned();
    }

    if Command::new("python.exe").arg("--version").output().is_ok() {
        return "python.exe".to_owned();
    }

    panic!(concat!("Can't find python (tried python2.7.exe, python27.exe, and python.exe)! ",
                   "Try fixing PATH or setting the PYTHON env var"));
}

#[cfg(not(windows))]
fn find_python() -> String {
    if Command::new("python2.7").arg("--version").output().unwrap().status.success() {
        "python2.7"
    } else {
        "python"
    }.to_owned()
}

lazy_static! {
    pub static ref PYTHON: String = env::var("PYTHON").ok().unwrap_or_else(find_python);
}

fn generate_properties() {
    for entry in WalkDir::new("properties") {
        let entry = entry.unwrap();
        match entry.path().extension().and_then(|e| e.to_str()) {
            Some("mako") | Some("rs") | Some("py") | Some("zip") => {
                println!("cargo:rerun-if-changed={}", entry.path().display());
            }
            _ => {}
        }
    }

    let script = Path::new(file!()).parent().unwrap().join("properties").join("build.py");
    let product = if cfg!(feature = "gecko") { "gecko" } else { "servo" };
    let status = Command::new(&*PYTHON)
        .arg(&script)
        .arg(product)
        .arg("style-crate")
        .arg(if cfg!(feature = "testing") { "testing" } else { "regular" })
        .status()
        .unwrap();
    if !status.success() {
        exit(1)
    }
}

fn main() {
    println!("cargo:rerun-if-changed=build.rs");
    generate_properties();
    build_gecko::generate();
}
<|endoftext|>


<commit_before>use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::in_macro;
use clippy_utils::source::snippet_opt;
use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir::{BinOpKind, Expr, ExprKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty;
use rustc_session::{declare_lint_pass, declare_tool_lint};

declare_clippy_lint! {
    /// **What it does:**
    /// Checks for uses of bitwise and/or operators between booleans, where performance may be improved by using
    /// a lazy and.
    ///
    /// **Why is this bad?**
    /// The bitwise operators do not support short-circuiting, so it may hinder code performance.
    /// Additionally, boolean logic "masked" as bitwise logic is not caught by lints like `unnecessary_fold`
    ///
    /// **Known problems:**
    /// This lint evaluates only when the right side is determined to have no side effects. At this time, that
    /// determination is quite conservative.
    ///
    /// **Example:**
    ///
    /// ```rust
    /// if x & !y {} // where both x and y are booleans
    /// ```
    /// Use instead:
    /// ```rust
    /// if x && !y {}
    /// ```
    pub NEEDLESS_BITWISE_BOOL,
    pedantic,
    "Boolean expressions that use bitwise rather than lazy operators"
}

declare_lint_pass!(NeedlessBitwiseBool => [NEEDLESS_BITWISE_BOOL]);

fn is_bitwise_operation(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
    let ty = cx.typeck_results().expr_ty(expr);
    if_chain! {
        if !in_macro(expr.span);
        if let (&ExprKind::Binary(ref op, _, right), &ty::Bool) = (&expr.kind, &ty.kind());
        if op.node == BinOpKind::BitAnd || op.node == BinOpKind::BitOr;
        if let ExprKind::Call(..) | ExprKind::MethodCall(..) | ExprKind::Binary(..) | ExprKind::Unary(..) = right.kind;
        if !right.can_have_side_effects();
        then {
            return true;
        }
    }
    false
}

fn suggession_snippet(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<String> {
    if let ExprKind::Binary(ref op, left, right) = expr.kind {
        if let (Some(l_snippet), Some(r_snippet)) = (snippet_opt(cx, left.span), snippet_opt(cx, right.span)) {
            let op_snippet = match op.node {
                BinOpKind::BitAnd => "&&",
                _ => "||",
            };
            return Some(format!("{} {} {}", l_snippet, op_snippet, r_snippet));
        }
    }
    None
}

impl LateLintPass<'_> for NeedlessBitwiseBool {
    fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
        if is_bitwise_operation(cx, expr) {
            span_lint_and_then(
                cx,
                NEEDLESS_BITWISE_BOOL,
                expr.span,
                "use of bitwise operator instead of lazy operator between booleans",
                |diag| {
                    if let Some(sugg) = suggession_snippet(cx, expr) {
                        diag.span_suggestion(expr.span, "try", sugg, Applicability::MachineApplicable);
                    }
                },
            );
        }
    }
}
<commit_msg>Fix missing variable init in lint example<commit_after>use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::in_macro;
use clippy_utils::source::snippet_opt;
use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir::{BinOpKind, Expr, ExprKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty;
use rustc_session::{declare_lint_pass, declare_tool_lint};

declare_clippy_lint! {
    /// **What it does:**
    /// Checks for uses of bitwise and/or operators between booleans, where performance may be improved by using
    /// a lazy and.
    ///
    /// **Why is this bad?**
    /// The bitwise operators do not support short-circuiting, so it may hinder code performance.
    /// Additionally, boolean logic "masked" as bitwise logic is not caught by lints like `unnecessary_fold`
    ///
    /// **Known problems:**
    /// This lint evaluates only when the right side is determined to have no side effects. At this time, that
    /// determination is quite conservative.
    ///
    /// **Example:**
    ///
    /// ```rust
    /// let (x,y) = (true, false);
    /// if x & !y {} // where both x and y are booleans
    /// ```
    /// Use instead:
    /// ```rust
    /// let (x,y) = (true, false);
    /// if x && !y {}
    /// ```
    pub NEEDLESS_BITWISE_BOOL,
    pedantic,
    "Boolean expressions that use bitwise rather than lazy operators"
}

declare_lint_pass!(NeedlessBitwiseBool => [NEEDLESS_BITWISE_BOOL]);

fn is_bitwise_operation(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
    let ty = cx.typeck_results().expr_ty(expr);
    if_chain! {
        if !in_macro(expr.span);
        if let (&ExprKind::Binary(ref op, _, right), &ty::Bool) = (&expr.kind, &ty.kind());
        if op.node == BinOpKind::BitAnd || op.node == BinOpKind::BitOr;
        if let ExprKind::Call(..) | ExprKind::MethodCall(..) | ExprKind::Binary(..) | ExprKind::Unary(..) = right.kind;
        if !right.can_have_side_effects();
        then {
            return true;
        }
    }
    false
}

fn suggession_snippet(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<String> {
    if let ExprKind::Binary(ref op, left, right) = expr.kind {
        if let (Some(l_snippet), Some(r_snippet)) = (snippet_opt(cx, left.span), snippet_opt(cx, right.span)) {
            let op_snippet = match op.node {
                BinOpKind::BitAnd => "&&",
                _ => "||",
            };
            return Some(format!("{} {} {}", l_snippet, op_snippet, r_snippet));
        }
    }
    None
}

impl LateLintPass<'_> for NeedlessBitwiseBool {
    fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
        if is_bitwise_operation(cx, expr) {
            span_lint_and_then(
                cx,
                NEEDLESS_BITWISE_BOOL,
                expr.span,
                "use of bitwise operator instead of lazy operator between booleans",
                |diag| {
                    if let Some(sugg) = suggession_snippet(cx, expr) {
                        diag.span_suggestion(expr.span, "try", sugg, Applicability::MachineApplicable);
                    }
                },
            );
        }
    }
}
<|endoftext|>


<commit_before>use std::rc::{Rc};
use std::cell::{RefCell};
use std::collections::HashMap;

//is same identity
fn is_same<T>(lhs: &T, rhs: &T) -> bool {
    lhs as *const T as i64 == rhs as *const T as i64
}

//the code below is horrible
//borrow doesn't return T, it returns Ref<T>
//we need to dereference it to get to the T inside
//is_same takes borrow so reapply the ampersand
fn is_same_subscriber<T: Subscriber>(lhs: Rc<RefCell<T>>, rhs: Rc<RefCell<T>>) -> bool {
    let lhs = lhs.clone();
    let rhs = rhs.clone();
    let res = is_same(&*lhs.borrow(), &*rhs.borrow()); //needed to live long enough
    res
}

pub trait Subscriber {
    fn new_message(&mut self, bytes: &[u8]);
}

pub struct Broker<T: Subscriber> {
    tree: Node<T>,
}

struct Node<T: Subscriber> {
    children: HashMap<String, Node<T>>,
    leaves: Vec<Subscription<T>>,
}

struct Subscription<T: Subscriber> {
    subscriber: Rc<RefCell<T>>,
    topic: String,
}

impl<T: Subscriber> Subscription<T> {
    fn new(subscriber: Rc<RefCell<T>>, topic: &str) -> Self {
        Subscription { subscriber: subscriber.clone(), topic: topic.to_string() }
    }
}

impl<T: Subscriber> Node<T> {
    fn new() -> Self {
        Node { children: HashMap::new(), leaves: vec![] }
    }

    fn add_subscription(&mut self, subscription: Subscription<T>) {
        self.leaves.push(subscription);
    }
}

impl<T: Subscriber> Broker<T> {
    pub fn new() -> Self {
        Broker { tree: Node::new() }
    }

    pub fn subscribe(&mut self, subscriber: Rc<RefCell<T>>, topics: &[&str]) {
        for topic in topics {
            let sub_parts : Vec<&str> = topic.split("/").collect();
            Self::ensure_node_exists(&sub_parts, &mut self.tree);
            Self::add_subscription_to_node(&mut self.tree, subscriber.clone(), &sub_parts, topic);
        }
    }

    pub fn unsubscribe_all(&mut self, subscriber: Rc<RefCell<T>>) {
        Self::unsubscribe_all_impl(&mut self.tree, subscriber.clone());
    }

    pub fn unsubscribe(&mut self, subscriber: Rc<RefCell<T>>, topics: &[&str]) {
        Self::unsubscribe_impl(&mut self.tree, subscriber.clone(), topics);
    }

    pub fn publish(&self, topic: &str, payload: &[u8]) {
        let pub_parts : Vec<&str> = topic.split("/").collect();
        Self::publish_impl(&self.tree, &pub_parts, &payload);
    }

    fn ensure_node_exists(sub_parts: &[&str], node: &mut Node<T>) {
        if sub_parts.len() == 0 {
            return;
        }

        let part = &sub_parts[0][..];
        if !node.children.contains_key(part) {
            node.children.insert(sub_parts[0].to_string(), Node::new());
        }

        Self::ensure_node_exists(&sub_parts[1..], node.children.get_mut(part).unwrap());
    }

    fn add_subscription_to_node(tree: &mut Node<T>, subscriber: Rc<RefCell<T>>, sub_parts: &[&str], topic: &str) {
        if sub_parts.len() < 1 {
            panic!("oops");
        }

        let part = &sub_parts[0][..];
        let node = tree.children.get_mut(part).unwrap();
        let sub_parts = &sub_parts[1..];

        if sub_parts.len() == 0 {
            node.add_subscription(Subscription::new(subscriber.clone(), topic));
        } else {
            Self::add_subscription_to_node(node, subscriber, sub_parts, topic);
        }
    }

    fn publish_impl(tree: &Node<T>, pub_parts: &[&str], payload: &[u8]) {
        if pub_parts.len() < 1 {
            return;
        }

        let part = &pub_parts[0][..];
        let pub_parts = &pub_parts[1..];

        for part in vec![part, "#", "+"] {

            let node = tree.children.get(part);

            match node {
                None => {
                    continue; //didn't find a subscriber
                },
                Some(node) => {
                    //so that "finance/#" matches "finance"
                    if pub_parts.len() == 0 && node.children.contains_key("#") {
                        Self::publish_node(node.children.get("#").unwrap(), payload);
                    }

                    if pub_parts.len() == 0 || part == "#" {
                        Self::publish_node(&node, payload);
                    }

                    Self::publish_impl(&node, pub_parts, payload);
                }
            }
        }
    }

    fn publish_node(node: &Node<T>, payload: &[u8]) {
        for subscription in &node.leaves {
            let subscriber = subscription.subscriber.clone();
            subscriber.borrow_mut().new_message(payload);
        }
    }

    fn unsubscribe_all_impl(tree: &mut Node<T>, subscriber: Rc<RefCell<T>>) {
        tree.leaves.retain(|s| !is_same_subscriber(s.subscriber.clone(), subscriber.clone()));

        if tree.children.len() == 0 {
            return;
        }

        for (_, node) in tree.children.iter_mut() {
            Self::unsubscribe_all_impl(node, subscriber.clone());
        }
    }

    fn unsubscribe_impl(tree: &mut Node<T>, subscriber: Rc<RefCell<T>>, topics: &[&str]) {
        tree.leaves.retain(|s| {
            let is_same_subscriber = is_same_subscriber(s.subscriber.clone(), subscriber.clone());
            //I have no idea why t below is &&&str, I added a tripe deref cos the compiler told me to
            let is_same_topic = topics.into_iter().find(|t| ***t == s.topic).is_some();
            !is_same_subscriber || !is_same_topic
        });

        if tree.children.len() == 0 {
            return;
        }

        for (_, node) in tree.children.iter_mut() {
            Self::unsubscribe_impl(node, subscriber.clone(), topics);
        }
    }
}

#[cfg(test)]
struct TestSubscriber {
    msgs: Vec<Vec<u8>>,
}

#[cfg(test)]
impl TestSubscriber {
    fn new() -> Self {
        TestSubscriber{msgs: vec![]}
    }
}

#[cfg(test)]
impl Subscriber for TestSubscriber {
    fn new_message(&mut self, bytes: &[u8]) {
        self.msgs.push(bytes.to_vec());
    }
}

#[test]
fn test_subscribe() {
    let mut broker = Broker::<TestSubscriber>::new();
    let sub_rc = Rc::new(RefCell::new(TestSubscriber::new()));
    let subscriber = sub_rc.clone();
    broker.publish("topics/foo", &[0, 1, 2]);
    assert_eq!(subscriber.borrow().msgs.len(), 0);

    broker.subscribe(subscriber.clone(), &["topics/foo"]);
    broker.publish("topics/foo", &[0, 1, 9]); //should get this
    broker.publish("topics/bar", &[2, 4, 6]); //shouldn't get this
    assert_eq!(subscriber.borrow().msgs.len(), 1);
    assert_eq!(subscriber.borrow().msgs[0], &[0, 1, 9]);

    broker.subscribe(subscriber.clone(), &["topics/bar"]);
    broker.publish("topics/foo", &[1, 3, 5, 7]);
    broker.publish("topics/bar", &[2, 4]);
    assert_eq!(subscriber.borrow().msgs.len(), 3);
    assert_eq!(subscriber.borrow().msgs[0], &[0, 1, 9]);
    assert_eq!(subscriber.borrow().msgs[1], &[1, 3, 5, 7]);
    assert_eq!(subscriber.borrow().msgs[2], &[2, 4]);
}

#[test]
fn test_unsubscribe_all() {
    let mut broker = Broker::<TestSubscriber>::new();
    let sub_rc = Rc::new(RefCell::new(TestSubscriber::new()));
    let subscriber = sub_rc.clone();

    broker.subscribe(subscriber.clone(), &["topics/foo"]);
    broker.publish("topics/foo", &[0, 1, 9]); //should get this
    broker.publish("topics/bar", &[2, 4, 6]); //shouldn't get this
    assert_eq!(subscriber.borrow().msgs.len(), 1);
    assert_eq!(subscriber.borrow().msgs[0], &[0, 1, 9]);

    broker.unsubscribe_all(subscriber.clone());
    broker.publish("topics/foo", &[0, 1, 9]);
    broker.publish("topics/bar", &[2, 4]);
    broker.publish("topics/baz", &[2, 4, 7, 11]);

    //shouldn't have changed
    assert_eq!(subscriber.borrow().msgs.len(), 1);
    assert_eq!(subscriber.borrow().msgs[0], &[0, 1, 9]);
}

#[test]
fn test_unsubscribe_one() {
    let mut broker = Broker::<TestSubscriber>::new();
    let sub_rc = Rc::new(RefCell::new(TestSubscriber::new()));
    let subscriber = sub_rc.clone();

    broker.subscribe(subscriber.clone(), &["topics/foo", "topics/bar"]);
    broker.publish("topics/foo", &[0, 1, 9]); //should get this
    broker.publish("topics/bar", &[2, 4]); //should get this
    broker.publish("topics/baz", &[2, 4, 7, 11]); //shouldn't get this
    assert_eq!(subscriber.borrow().msgs.len(), 2);
    assert_eq!(subscriber.borrow().msgs[0], &[0, 1, 9]);
    assert_eq!(subscriber.borrow().msgs[1], &[2, 4]);

    broker.unsubscribe(subscriber.clone(), &["topics/foo"]);
    broker.publish("topics/foo", &[0, 1, 9]); //shouldn't get this
    broker.publish("topics/bar", &[2, 4]); //should get this
    broker.publish("topics/baz", &[2, 4, 7, 11]); //shouldn't get this

    assert_eq!(subscriber.borrow().msgs.len(), 3);
    assert_eq!(subscriber.borrow().msgs[0], &[0, 1, 9]);
    assert_eq!(subscriber.borrow().msgs[1], &[2, 4]);
    assert_eq!(subscriber.borrow().msgs[2], &[2, 4]);
}

#[cfg(test)]
fn test_matches(pub_topic: &str, sub_topic: &str) -> bool {
    let mut broker = Broker::<TestSubscriber>::new();
    let sub_rc = Rc::new(RefCell::new(TestSubscriber::new()));
    let subscriber = sub_rc.clone();

    broker.subscribe(subscriber.clone(), &[sub_topic]);
    broker.publish(pub_topic, &[0, 1, 2]);
    let subscriber = subscriber.borrow();
    subscriber.msgs.len() == 1
}

#[test]
fn test_wildcards() {
    assert_eq!(test_matches("foo/bar/baz", "foo/bar/baz"), true);
    assert_eq!(test_matches("foo/bar", "foo/+"), true);
    assert_eq!(test_matches("foo/baz", "foo/+"), true);
    assert_eq!(test_matches("foo/bar/baz", "foo/+"), false);
    assert_eq!(test_matches("foo/bar", "foo/#"), true);
    assert_eq!(test_matches("foo/bar/baz", "foo/#"), true);
    assert_eq!(test_matches("foo/bar/baz/boo", "foo/#"), true);
    assert_eq!(test_matches("foo/bla/bar/baz/boo/bogadog", "foo/+/bar/baz/#"), true);
    assert_eq!(test_matches("finance", "finance/#"), true);
    assert_eq!(test_matches("finance", "finance#"), false);
    assert_eq!(test_matches("finance", "#"), true);
    assert_eq!(test_matches("finance/stock", "#"), true);
    assert_eq!(test_matches("finance/stock", "finance/stock/ibm"), false);
    assert_eq!(test_matches("topics/foo/bar", "topics/foo/#"), true);
    assert_eq!(test_matches("topics/bar/baz/boo", "topics/foo/#"), false);
}

#[test]
fn test_subscribe_wildcards() {
    let mut broker = Broker::<TestSubscriber>::new();
    let sub_rc1 = Rc::new(RefCell::new(TestSubscriber::new()));
    let sub_rc2 = Rc::new(RefCell::new(TestSubscriber::new()));
    let sub_rc3 = Rc::new(RefCell::new(TestSubscriber::new()));
    let sub_rc4 = Rc::new(RefCell::new(TestSubscriber::new()));

    let subscriber1 = sub_rc1.clone();
    let subscriber2 = sub_rc2.clone();
    let subscriber3 = sub_rc3.clone();
    let subscriber4 = sub_rc4.clone();

    broker.subscribe(subscriber1.clone(), &["topics/foo/+"]);
    broker.publish("topics/foo/bar", &[3]);
    broker.publish("topics/bar/baz/boo", &[4]); //shouldn't get this one
    assert_eq!(subscriber1.borrow().msgs, vec![&[3]]);

    broker.subscribe(subscriber2.clone(), &["topics/foo/#"]);
    broker.publish("topics/foo/bar", &[3]);
    broker.publish("topics/bar/baz/boo", &[4]); //shouldn't get this one
    assert_eq!(subscriber1.borrow().msgs, vec![&[3], &[3]]);
    assert_eq!(subscriber2.borrow().msgs, vec![&[3]]);

    broker.subscribe(subscriber3.clone(), &["topics/+/bar"]);
    broker.subscribe(subscriber4.clone(), &["topics/#"]);

    broker.publish("topics/foo/bar", &[3]);
    broker.publish("topics/bar/baz/boo", &[4]);
    broker.publish("topics/boo/bar/zoo", &[5]);
    broker.publish("topics/foo/bar/zoo", &[6]);
    broker.publish("topics/bbobobobo/bar", &[7]);

    assert_eq!(subscriber1.borrow().msgs, vec![&[3], &[3], &[3]]);
    assert_eq!(subscriber2.borrow().msgs, vec![&[3], &[3], &[6]]);
    assert_eq!(subscriber3.borrow().msgs, vec![&[3], &[7]]);
    assert_eq!(subscriber4.borrow().msgs, vec![&[3], &[4], &[5], &[6], &[7]]);
}
<commit_msg>Refactoring of the unsubscribe functions<commit_after>use std::rc::{Rc};
use std::cell::{RefCell};
use std::collections::HashMap;

//is same identity
fn is_same<T>(lhs: &T, rhs: &T) -> bool {
    lhs as *const T as i64 == rhs as *const T as i64
}

//the code below is horrible
//borrow doesn't return T, it returns Ref<T>
//we need to dereference it to get to the T inside
//is_same takes borrow so reapply the ampersand
fn is_same_subscriber<T: Subscriber>(lhs: Rc<RefCell<T>>, rhs: Rc<RefCell<T>>) -> bool {
    let lhs = lhs.clone();
    let rhs = rhs.clone();
    let res = is_same(&*lhs.borrow(), &*rhs.borrow()); //needed to live long enough
    res
}

pub trait Subscriber {
    fn new_message(&mut self, bytes: &[u8]);
}

pub struct Broker<T: Subscriber> {
    tree: Node<T>,
}

struct Node<T: Subscriber> {
    children: HashMap<String, Node<T>>,
    leaves: Vec<Subscription<T>>,
}

struct Subscription<T: Subscriber> {
    subscriber: Rc<RefCell<T>>,
    topic: String,
}

impl<T: Subscriber> Subscription<T> {
    fn new(subscriber: Rc<RefCell<T>>, topic: &str) -> Self {
        Subscription { subscriber: subscriber.clone(), topic: topic.to_string() }
    }
}

impl<T: Subscriber> Node<T> {
    fn new() -> Self {
        Node { children: HashMap::new(), leaves: vec![] }
    }

    fn add_subscription(&mut self, subscription: Subscription<T>) {
        self.leaves.push(subscription);
    }
}

impl<T: Subscriber> Broker<T> {
    pub fn new() -> Self {
        Broker { tree: Node::new() }
    }

    pub fn subscribe(&mut self, subscriber: Rc<RefCell<T>>, topics: &[&str]) {
        for topic in topics {
            let sub_parts : Vec<&str> = topic.split("/").collect();
            Self::ensure_node_exists(&sub_parts, &mut self.tree);
            Self::add_subscription_to_node(&mut self.tree, subscriber.clone(), &sub_parts, topic);
        }
    }

    pub fn unsubscribe_all(&mut self, subscriber: Rc<RefCell<T>>) {
        Self::unsubscribe_impl(&mut self.tree, subscriber.clone(), &[], false);
    }

    pub fn unsubscribe(&mut self, subscriber: Rc<RefCell<T>>, topics: &[&str]) {
        Self::unsubscribe_impl(&mut self.tree, subscriber.clone(), topics, true);
    }

    pub fn publish(&self, topic: &str, payload: &[u8]) {
        let pub_parts : Vec<&str> = topic.split("/").collect();
        Self::publish_impl(&self.tree, &pub_parts, &payload);
    }

    fn ensure_node_exists(sub_parts: &[&str], node: &mut Node<T>) {
        if sub_parts.len() == 0 {
            return;
        }

        let part = &sub_parts[0][..];
        if !node.children.contains_key(part) {
            node.children.insert(sub_parts[0].to_string(), Node::new());
        }

        Self::ensure_node_exists(&sub_parts[1..], node.children.get_mut(part).unwrap());
    }

    fn add_subscription_to_node(tree: &mut Node<T>, subscriber: Rc<RefCell<T>>, sub_parts: &[&str], topic: &str) {
        if sub_parts.len() < 1 {
            panic!("oops");
        }

        let part = &sub_parts[0][..];
        let node = tree.children.get_mut(part).unwrap();
        let sub_parts = &sub_parts[1..];

        if sub_parts.len() == 0 {
            node.add_subscription(Subscription::new(subscriber.clone(), topic));
        } else {
            Self::add_subscription_to_node(node, subscriber, sub_parts, topic);
        }
    }

    fn publish_impl(tree: &Node<T>, pub_parts: &[&str], payload: &[u8]) {
        if pub_parts.len() < 1 {
            return;
        }

        let part = &pub_parts[0][..];
        let pub_parts = &pub_parts[1..];

        for part in vec![part, "#", "+"] {

            let node = tree.children.get(part);

            match node {
                None => {
                    continue; //didn't find a subscriber
                },
                Some(node) => {
                    //so that "finance/#" matches "finance"
                    if pub_parts.len() == 0 && node.children.contains_key("#") {
                        Self::publish_node(node.children.get("#").unwrap(), payload);
                    }

                    if pub_parts.len() == 0 || part == "#" {
                        Self::publish_node(&node, payload);
                    }

                    Self::publish_impl(&node, pub_parts, payload);
                }
            }
        }
    }

    fn publish_node(node: &Node<T>, payload: &[u8]) {
        for subscription in &node.leaves {
            let subscriber = subscription.subscriber.clone();
            subscriber.borrow_mut().new_message(payload);
        }
    }

    fn unsubscribe_impl(tree: &mut Node<T>, subscriber: Rc<RefCell<T>>, topics: &[&str], check_topics: bool) {
        tree.leaves.retain(|s| {
            let is_same_subscriber = is_same_subscriber(s.subscriber.clone(), subscriber.clone());
            //I have no idea why t below is &&&str, I added a tripe deref cos the compiler told me to
            let is_same_topic = !check_topics || topics.into_iter().find(|t| ***t == s.topic).is_some();
            !is_same_subscriber || !is_same_topic
        });

        if tree.children.len() == 0 {
            return;
        }

        for (_, node) in tree.children.iter_mut() {
            Self::unsubscribe_impl(node, subscriber.clone(), topics, check_topics);
        }
    }

}

#[cfg(test)]
struct TestSubscriber {
    msgs: Vec<Vec<u8>>,
}

#[cfg(test)]
impl TestSubscriber {
    fn new() -> Self {
        TestSubscriber{msgs: vec![]}
    }
}

#[cfg(test)]
impl Subscriber for TestSubscriber {
    fn new_message(&mut self, bytes: &[u8]) {
        self.msgs.push(bytes.to_vec());
    }
}

#[test]
fn test_subscribe() {
    let mut broker = Broker::<TestSubscriber>::new();
    let sub_rc = Rc::new(RefCell::new(TestSubscriber::new()));
    let subscriber = sub_rc.clone();
    broker.publish("topics/foo", &[0, 1, 2]);
    assert_eq!(subscriber.borrow().msgs.len(), 0);

    broker.subscribe(subscriber.clone(), &["topics/foo"]);
    broker.publish("topics/foo", &[0, 1, 9]); //should get this
    broker.publish("topics/bar", &[2, 4, 6]); //shouldn't get this
    assert_eq!(subscriber.borrow().msgs.len(), 1);
    assert_eq!(subscriber.borrow().msgs[0], &[0, 1, 9]);

    broker.subscribe(subscriber.clone(), &["topics/bar"]);
    broker.publish("topics/foo", &[1, 3, 5, 7]);
    broker.publish("topics/bar", &[2, 4]);
    assert_eq!(subscriber.borrow().msgs.len(), 3);
    assert_eq!(subscriber.borrow().msgs[0], &[0, 1, 9]);
    assert_eq!(subscriber.borrow().msgs[1], &[1, 3, 5, 7]);
    assert_eq!(subscriber.borrow().msgs[2], &[2, 4]);
}

#[test]
fn test_unsubscribe_all() {
    let mut broker = Broker::<TestSubscriber>::new();
    let sub_rc = Rc::new(RefCell::new(TestSubscriber::new()));
    let subscriber = sub_rc.clone();

    broker.subscribe(subscriber.clone(), &["topics/foo"]);
    broker.publish("topics/foo", &[0, 1, 9]); //should get this
    broker.publish("topics/bar", &[2, 4, 6]); //shouldn't get this
    assert_eq!(subscriber.borrow().msgs.len(), 1);
    assert_eq!(subscriber.borrow().msgs[0], &[0, 1, 9]);

    broker.unsubscribe_all(subscriber.clone());
    broker.publish("topics/foo", &[0, 1, 9]);
    broker.publish("topics/bar", &[2, 4]);
    broker.publish("topics/baz", &[2, 4, 7, 11]);

    //shouldn't have changed
    assert_eq!(subscriber.borrow().msgs.len(), 1);
    assert_eq!(subscriber.borrow().msgs[0], &[0, 1, 9]);
}

#[test]
fn test_unsubscribe_one() {
    let mut broker = Broker::<TestSubscriber>::new();
    let sub_rc = Rc::new(RefCell::new(TestSubscriber::new()));
    let subscriber = sub_rc.clone();

    broker.subscribe(subscriber.clone(), &["topics/foo", "topics/bar"]);
    broker.publish("topics/foo", &[0, 1, 9]); //should get this
    broker.publish("topics/bar", &[2, 4]); //should get this
    broker.publish("topics/baz", &[2, 4, 7, 11]); //shouldn't get this
    assert_eq!(subscriber.borrow().msgs.len(), 2);
    assert_eq!(subscriber.borrow().msgs[0], &[0, 1, 9]);
    assert_eq!(subscriber.borrow().msgs[1], &[2, 4]);

    broker.unsubscribe(subscriber.clone(), &["topics/foo"]);
    broker.publish("topics/foo", &[0, 1, 9]); //shouldn't get this
    broker.publish("topics/bar", &[2, 4]); //should get this
    broker.publish("topics/baz", &[2, 4, 7, 11]); //shouldn't get this

    assert_eq!(subscriber.borrow().msgs.len(), 3);
    assert_eq!(subscriber.borrow().msgs[0], &[0, 1, 9]);
    assert_eq!(subscriber.borrow().msgs[1], &[2, 4]);
    assert_eq!(subscriber.borrow().msgs[2], &[2, 4]);
}

#[cfg(test)]
fn test_matches(pub_topic: &str, sub_topic: &str) -> bool {
    let mut broker = Broker::<TestSubscriber>::new();
    let sub_rc = Rc::new(RefCell::new(TestSubscriber::new()));
    let subscriber = sub_rc.clone();

    broker.subscribe(subscriber.clone(), &[sub_topic]);
    broker.publish(pub_topic, &[0, 1, 2]);
    let subscriber = subscriber.borrow();
    subscriber.msgs.len() == 1
}

#[test]
fn test_wildcards() {
    assert_eq!(test_matches("foo/bar/baz", "foo/bar/baz"), true);
    assert_eq!(test_matches("foo/bar", "foo/+"), true);
    assert_eq!(test_matches("foo/baz", "foo/+"), true);
    assert_eq!(test_matches("foo/bar/baz", "foo/+"), false);
    assert_eq!(test_matches("foo/bar", "foo/#"), true);
    assert_eq!(test_matches("foo/bar/baz", "foo/#"), true);
    assert_eq!(test_matches("foo/bar/baz/boo", "foo/#"), true);
    assert_eq!(test_matches("foo/bla/bar/baz/boo/bogadog", "foo/+/bar/baz/#"), true);
    assert_eq!(test_matches("finance", "finance/#"), true);
    assert_eq!(test_matches("finance", "finance#"), false);
    assert_eq!(test_matches("finance", "#"), true);
    assert_eq!(test_matches("finance/stock", "#"), true);
    assert_eq!(test_matches("finance/stock", "finance/stock/ibm"), false);
    assert_eq!(test_matches("topics/foo/bar", "topics/foo/#"), true);
    assert_eq!(test_matches("topics/bar/baz/boo", "topics/foo/#"), false);
}

#[test]
fn test_subscribe_wildcards() {
    let mut broker = Broker::<TestSubscriber>::new();
    let sub_rc1 = Rc::new(RefCell::new(TestSubscriber::new()));
    let sub_rc2 = Rc::new(RefCell::new(TestSubscriber::new()));
    let sub_rc3 = Rc::new(RefCell::new(TestSubscriber::new()));
    let sub_rc4 = Rc::new(RefCell::new(TestSubscriber::new()));

    let subscriber1 = sub_rc1.clone();
    let subscriber2 = sub_rc2.clone();
    let subscriber3 = sub_rc3.clone();
    let subscriber4 = sub_rc4.clone();

    broker.subscribe(subscriber1.clone(), &["topics/foo/+"]);
    broker.publish("topics/foo/bar", &[3]);
    broker.publish("topics/bar/baz/boo", &[4]); //shouldn't get this one
    assert_eq!(subscriber1.borrow().msgs, vec![&[3]]);

    broker.subscribe(subscriber2.clone(), &["topics/foo/#"]);
    broker.publish("topics/foo/bar", &[3]);
    broker.publish("topics/bar/baz/boo", &[4]); //shouldn't get this one
    assert_eq!(subscriber1.borrow().msgs, vec![&[3], &[3]]);
    assert_eq!(subscriber2.borrow().msgs, vec![&[3]]);

    broker.subscribe(subscriber3.clone(), &["topics/+/bar"]);
    broker.subscribe(subscriber4.clone(), &["topics/#"]);

    broker.publish("topics/foo/bar", &[3]);
    broker.publish("topics/bar/baz/boo", &[4]);
    broker.publish("topics/boo/bar/zoo", &[5]);
    broker.publish("topics/foo/bar/zoo", &[6]);
    broker.publish("topics/bbobobobo/bar", &[7]);

    assert_eq!(subscriber1.borrow().msgs, vec![&[3], &[3], &[3]]);
    assert_eq!(subscriber2.borrow().msgs, vec![&[3], &[3], &[6]]);
    assert_eq!(subscriber3.borrow().msgs, vec![&[3], &[7]]);
    assert_eq!(subscriber4.borrow().msgs, vec![&[3], &[4], &[5], &[6], &[7]]);
}
<|endoftext|>


<commit_before>#![allow(dead_code)]
use utils;
use std::ops::Index;

enum MemType
{
    RAM,
    BASIC,
    CHARGEN,
    IO,
    KERNAL,
}

// specific memory bank - RAM, ROM, IO
struct MemBank
{
    bank_type: MemType,
    read_only: bool,
    offset: u16,
    data: Vec<u8>,
}

impl MemBank
{
    pub fn new(mem_type: MemType) -> MemBank
    {
        let mut mem_bank = MemBank
        {
            bank_type: mem_type,
            read_only: true,
            offset: 0x0000,
            data: Vec::<u8>::new(),
        };

        match mem_bank.bank_type
        {
            MemType::BASIC   => {
                mem_bank.data = utils::open_file("rom/basic.rom", 0);
                mem_bank.offset = 0xA000;
            },
            MemType::CHARGEN => {
                mem_bank.data = utils::open_file("rom/chargen.rom", 0);
                mem_bank.offset = 0xD000;
            },
            MemType::KERNAL  => {
                mem_bank.data = utils::open_file("rom/kernal.rom", 0);
                mem_bank.offset = 0xE000;
            },
            MemType::RAM => {
                mem_bank.data = Vec::<u8>::with_capacity(0x10000);
                for _ in 0..0x10000
                {
                    mem_bank.data.push(0);
                }

                mem_bank.read_only = false;
            }
            MemType::IO => {
                mem_bank.data = Vec::<u8>::with_capacity(0x1000);
                for _ in 0..0x1000
                {
                    mem_bank.data.push(0);
                }

                mem_bank.offset = 0xD000;
                mem_bank.read_only = false;
            }
        }

        mem_bank
    }

    fn write(&mut self, addr: u16, val: u8)
    {
        match self.bank_type
        {
            MemType::RAM => self.data[(addr - self.offset) as usize] = val,
            MemType::IO => {
                // TODO: IO access has specific behavior depending on address
                self.data[(addr - self.offset) as usize] = val;
            },
            _ => panic!("Can't write to ROM!")
        }
    }

    fn read(&self, addr: u16) -> u8
    {
        match self.bank_type
        {
            MemType::IO => {
                // TODO: IO access has specific behavior depending on address
                self.data[(addr - self.offset) as usize]
            },
            _ => self.data[(addr - self.offset) as usize]
        }
    }
}

impl Index<u16> for MemBank
{
    type Output = u8;

    fn index<'a>(&'a self, _index: u16) -> &'a u8
    {
        &self.data[_index as usize]
    }
}

// collective memory storage with all the banks and bank switching support
pub struct Memory
{
    ram:     MemBank,
    basic:   MemBank,
    chargen: MemBank,
    io:      MemBank,
    kernal:  MemBank,

    // bank switching flags
    basic_on:   bool,
    chargen_on: bool,
    io_on:      bool,
    kernal_on:  bool,
    cart_lo_on: bool, // cart flag - unused for now
    cart_hi_on: bool  // cart flag - unused for now
}

impl Memory
{
    pub fn new() -> Memory
    {
        Memory
        {
            ram:     MemBank::new(MemType::RAM),     // 64k
            basic:   MemBank::new(MemType::BASIC),   // 8k
            chargen: MemBank::new(MemType::CHARGEN), // 4k
            io:      MemBank::new(MemType::IO),      // 4k (VIC, SID, CIA, Color RAM)
            kernal:  MemBank::new(MemType::KERNAL),  // 8k
            basic_on:   false,
            chargen_on: false,
            io_on:      false,
            kernal_on:  false,
            cart_lo_on: false, // unused for now
            cart_hi_on: false, // unused for now
        }
    }

    // returns memory bank for current latch setting and address
    pub fn get_bank(&mut self, addr: u16) -> (&mut MemBank)
    {
        match addr
        {
            0x0000...0x9FFF => &mut self.ram,
            0xA000...0xCFFF => if self.basic_on { &mut self.basic } else { &mut self.ram },
            0xD000...0xDFFF => {
                if self.chargen_on { return &mut self.chargen }
                if self.io_on      { return &mut self.io; }
                return &mut self.ram;
            },
            0xE000...0xFFFF => if self.kernal_on  { &mut self.kernal } else { &mut self.ram },
            _ => panic!("Address out of memory range")
        }
    }

    pub fn reset(&mut self)
    {
        self.write_byte(0x0000, 0xFF);
        self.write_byte(0x0001, 0x07); // enable kernal, chargen and basic ROMs
    }

    fn update_bank_flags(&mut self)
    {
        // latch state is determined by 3 least significant bits from this location
        let latch = self.ram[0x0001] & 0x07;

        self.chargen_on = ((latch & 0x04) == 0) && ((latch & 0x03) != 0); // %0xx except %000
        self.io_on      = ((latch & 0x04) != 0) && ((latch & 0x03) != 0); // %1xx except %100
        self.basic_on   = (latch & 0x03) == 0x03;
        self.kernal_on  = self.basic_on || ((latch & 0x03) == 0x02);
    }

    // Write a byte to memory - returns whether RAM was written (true) or RAM under ROM (false)
    pub fn write_byte(&mut self, addr: u16, value: u8) -> bool
    {
            // RAM under ROM written? Return false to let us know about it
            if self.get_bank(addr).read_only
            {
                self.ram.write(addr, value);
                return false;
            }
            else
            {
                self.get_bank(addr).write(addr, value);
            }

        // update the bank switching flags here, since they can only change on memory write
        // latch byte changed - update bank switching flags
        if addr == 0x0001 { self.update_bank_flags(); }

        return true;
    }

    // Read a byte from memory
    pub fn read_byte(&mut self, addr: u16) -> u8
    {
        self.get_bank(addr).read(addr)
    }

    // Read a word from memory (stored in little endian)
    pub fn read_word_le(&mut self, addr: u16) -> u16
    {
        let bank = self.get_bank(addr);
        let value_be: u16 = ((bank.read(addr) as u16) << 8 & 0xFF00) |
                            ((bank.read(addr + 0x0001) as u16) & 0x00FF);

        let value_le: u16 = ((value_be << 8) & 0xFF00) | ((value_be >> 8) & 0x00FF);
        value_le
    }

    // Read a word from memory (stored in big endian: swap low<->high)
    pub fn read_word_be(&mut self, addr: u16) -> u16
    {
        let bank = self.get_bank(addr);
        let value_le: u16 = ((bank.read(addr) as u16) << 8 & 0xFF00) |
                            ((bank.read(addr + 0x0001) as u16) & 0x00FF);
        value_le
    }

    // Write word in little endian format (low/high)
    pub fn write_word_le(&mut self, addr: u16, value: u16) -> bool
    {
        let value_le_lo: u8 = (((value << 8) & 0xFF00) >> 8 & 0xFF) as u8;
        let value_le_hi: u8 = ((value >> 8) & 0x00FF) as u8;

        let hi = self.write_byte(addr, value_le_lo);
        let lo = self.write_byte(addr + 0x0001, value_le_hi);

        return hi && lo;
    }

    // Write word in big endian format (high/low)
    pub fn write_word_be(&mut self, addr: u16, value: u16) -> bool
    {
        let value_le_lo: u8 = (((value << 8) & 0xFF00) >> 8 & 0xFF) as u8;
        let value_le_hi: u8 = ((value >> 8) & 0x00FF) as u8;

        let hi = self.write_byte(addr, value_le_hi);
        let lo = self.write_byte(addr + 0x0001, value_le_lo);

        return hi && lo;
    }
}

<commit_msg>temporarily comment out direct indexing + added Deref and DerefMut traits (commented out)<commit_after>#![allow(dead_code)]
use utils;
//use std::ops::{Index, Deref, DerefMut};

enum MemType
{
    RAM,
    BASIC,
    CHARGEN,
    IO,
    KERNAL,
}

// specific memory bank - RAM, ROM, IO
struct MemBank
{
    bank_type: MemType, // what am I?
    read_only: bool,    // RAM or ROM?
    offset: u16,        // offset from start of address space
    data: Vec<u8>,
}

impl MemBank
{
    pub fn new(mem_type: MemType) -> MemBank
    {
        let mut mem_bank = MemBank
        {
            bank_type: mem_type,
            read_only: true,
            offset: 0x0000,
            data: Vec::<u8>::new(),
        };

        match mem_bank.bank_type
        {
            MemType::BASIC   => {
                mem_bank.data = utils::open_file("rom/basic.rom", 0);
                mem_bank.offset = 0xA000;
            },
            MemType::CHARGEN => {
                mem_bank.data = utils::open_file("rom/chargen.rom", 0);
                mem_bank.offset = 0xD000;
            },
            MemType::KERNAL  => {
                mem_bank.data = utils::open_file("rom/kernal.rom", 0);
                mem_bank.offset = 0xE000;
            },
            MemType::RAM => {
                mem_bank.data = Vec::<u8>::with_capacity(0x10000);
                for _ in 0..0x10000
                {
                    mem_bank.data.push(0);
                }

                mem_bank.read_only = false;
            }
            MemType::IO => {
                mem_bank.data = Vec::<u8>::with_capacity(0x1000);
                for _ in 0..0x1000
                {
                    mem_bank.data.push(0);
                }

                mem_bank.offset = 0xD000;
                mem_bank.read_only = false;
            }
        }

        mem_bank
    }

    fn write(&mut self, addr: u16, val: u8)
    {
        match self.bank_type
        {
            MemType::RAM => self.data[(addr - self.offset) as usize] = val,
            MemType::IO => {
                // TODO: IO access has specific behavior depending on address
                self.data[(addr - self.offset) as usize] = val;
            },
            _ => panic!("Can't write to ROM!")
        }
    }

    fn read(&self, addr: u16) -> u8
    {
        match self.bank_type
        {
            MemType::IO => {
                // TODO: IO access has specific behavior depending on address
                self.data[(addr - self.offset) as usize]
            },
            _ => self.data[(addr - self.offset) as usize]
        }
    }
}

/*impl Index<u16> for MemBank
{
    type Output = u8;

    fn index<'a>(&'a self, _index: u16) -> &'a u8
    {
        &self.data[_index as usize]
    }
}

impl Deref for MemBank
{
    type Target = Vec<u8>;

    fn deref(&self) -> &Vec<u8>
    {
        &self.data
    }
}

impl DerefMut for MemBank
{
    fn deref_mut(&mut self) -> &mut Vec<u8>
    {
        &mut self.data
    }
}*/

// collective memory storage with all the banks and bank switching support
pub struct Memory
{
    ram:     MemBank,
    basic:   MemBank,
    chargen: MemBank,
    io:      MemBank,
    kernal:  MemBank,

    // bank switching flags
    basic_on:   bool,
    chargen_on: bool,
    io_on:      bool,
    kernal_on:  bool,
    cart_lo_on: bool, // cart flag - unused for now
    cart_hi_on: bool  // cart flag - unused for now
}

impl Memory
{
    pub fn new() -> Memory
    {
        Memory
        {
            ram:     MemBank::new(MemType::RAM),     // 64k
            basic:   MemBank::new(MemType::BASIC),   // 8k
            chargen: MemBank::new(MemType::CHARGEN), // 4k
            io:      MemBank::new(MemType::IO),      // 4k (VIC, SID, CIA, Color RAM)
            kernal:  MemBank::new(MemType::KERNAL),  // 8k
            basic_on:   false,
            chargen_on: false,
            io_on:      false,
            kernal_on:  false,
            cart_lo_on: false, // unused for now
            cart_hi_on: false, // unused for now
        }
    }

    // returns memory bank for current latch setting and address
    pub fn get_bank(&mut self, addr: u16) -> (&mut MemBank)
    {
        match addr
        {
            0x0000...0x9FFF => &mut self.ram,
            0xA000...0xCFFF => if self.basic_on { &mut self.basic } else { &mut self.ram },
            0xD000...0xDFFF => {
                if self.chargen_on { return &mut self.chargen }
                if self.io_on      { return &mut self.io; }
                return &mut self.ram;
            },
            0xE000...0xFFFF => if self.kernal_on  { &mut self.kernal } else { &mut self.ram },
            _ => panic!("Address out of memory range")
        }
    }

    pub fn reset(&mut self)
    {
        self.write_byte(0x0000, 0xFF);
        self.write_byte(0x0001, 0x07); // enable kernal, chargen and basic ROMs
    }

    fn update_bank_flags(&mut self)
    {
        // latch state is determined by 3 least significant bits from this location
        let latch = self.ram.read(0x0001) & 0x07;

        self.chargen_on = ((latch & 0x04) == 0) && ((latch & 0x03) != 0); // %0xx except %000
        self.io_on      = ((latch & 0x04) != 0) && ((latch & 0x03) != 0); // %1xx except %100
        self.basic_on   = (latch & 0x03) == 0x03;
        self.kernal_on  = self.basic_on || ((latch & 0x03) == 0x02);
    }

    // Write a byte to memory - returns whether RAM was written (true) or RAM under ROM (false)
    pub fn write_byte(&mut self, addr: u16, value: u8) -> bool
    {
            // RAM under ROM written? Return false to let us know about it
            if self.get_bank(addr).read_only
            {
                self.ram.write(addr, value);
                return false;
            }
            else
            {
                self.get_bank(addr).write(addr, value);
            }

        // update the bank switching flags here, since they can only change on memory write
        // latch byte changed - update bank switching flags
        if addr == 0x0001 { self.update_bank_flags(); }

        return true;
    }

    // Read a byte from memory
    pub fn read_byte(&mut self, addr: u16) -> u8
    {
        self.get_bank(addr).read(addr)
    }

    // Read a word from memory (stored in little endian)
    pub fn read_word_le(&mut self, addr: u16) -> u16
    {
        let bank = self.get_bank(addr);
        let value_be: u16 = ((bank.read(addr) as u16) << 8 & 0xFF00) |
                            ((bank.read(addr + 0x0001) as u16) & 0x00FF);

        let value_le: u16 = ((value_be << 8) & 0xFF00) | ((value_be >> 8) & 0x00FF);
        value_le
    }

    // Read a word from memory (stored in big endian: swap low<->high)
    pub fn read_word_be(&mut self, addr: u16) -> u16
    {
        let bank = self.get_bank(addr);
        let value_le: u16 = ((bank.read(addr) as u16) << 8 & 0xFF00) |
                            ((bank.read(addr + 0x0001) as u16) & 0x00FF);
        value_le
    }

    // Write word in little endian format (low/high)
    pub fn write_word_le(&mut self, addr: u16, value: u16) -> bool
    {
        let value_le_lo: u8 = (((value << 8) & 0xFF00) >> 8 & 0xFF) as u8;
        let value_le_hi: u8 = ((value >> 8) & 0x00FF) as u8;

        let hi = self.write_byte(addr, value_le_lo);
        let lo = self.write_byte(addr + 0x0001, value_le_hi);

        return hi && lo;
    }

    // Write word in big endian format (high/low)
    pub fn write_word_be(&mut self, addr: u16, value: u16) -> bool
    {
        let value_le_lo: u8 = (((value << 8) & 0xFF00) >> 8 & 0xFF) as u8;
        let value_le_hi: u8 = ((value >> 8) & 0x00FF) as u8;

        let hi = self.write_byte(addr, value_le_hi);
        let lo = self.write_byte(addr + 0x0001, value_le_lo);

        return hi && lo;
    }
}

<|endoftext|>


<commit_before>/*
 * CPU   Main Memory (2)
 *  |         |
 *  ------------------------
 *       |                 |
 *   Registers (1)        ROM (3)
 *
 *
 */

const MEMORY_SIZE: u16 = 0xffff;

pub struct Memory(Vec<u8>);

impl Memory {
    /// Init a new memory unit
    pub fn new() -> Memory {
        let mut mem: Vec<u8> = Vec::with_capacity(MEMORY_SIZE as usize);
        for _ in 0..MEMORY_SIZE {
            mem.push(0);
        }
        Memory(mem)
    }

    /// Read a byte from the memory
    pub fn read_byte(&self, addr: u16) -> u8 {
        self.0[addr as usize]
    }

    /// Read a range of bytes from the memory
    pub fn read_range(&self, addr: (u16, u16)) -> Vec<u8> {
        let mut a: Vec<u8> = Vec::with_capacity((addr.1 - addr.0) as usize);
        for x in addr.0..addr.1 {
            a.push(self.0[x as usize])
        }
        a
    }
}
<commit_msg>write to mem<commit_after>/*
 * CPU   Main Memory (2)
 *  |         |
 *  ------------------------
 *       |                 |
 *   Registers (1)        ROM (3)
 *
 *
 */

const MEMORY_SIZE: u16 = 0xffff;

pub struct Memory(Vec<u8>);

impl Memory {
    /// Init a new memory unit
    pub fn new() -> Memory {
        let mut mem: Vec<u8> = Vec::with_capacity(MEMORY_SIZE as usize);
        for _ in 0..MEMORY_SIZE {
            mem.push(0);
        }
        Memory(mem)
    }

    /// Read a byte from the memory
    pub fn read_byte(&self, addr: u16) -> u8 {
        self.0[addr as usize]
    }

    /// Read a range of bytes from the memory
    pub fn read_range(&self, addr: (u16, u16)) -> Vec<u8> {
        let mut a: Vec<u8> = Vec::with_capacity((addr.1 - addr.0) as usize);
        for x in addr.0..addr.1 {
            a.push(self.0[x as usize])
        }
        a
    }

    /// Write a byte to the memory
    pub fn write_byte(&mut self, addr: u16, v: u8) {
        self.0[addr as usize] = v;
    }

}

#[test]
fn read_write(){
    let mut mem = Memory::new();
    mem.write_byte(0xdeff, 0xb1);
    assert_eq!(mem.read_byte(0xdeff), 0xb1);
}
<|endoftext|>


<commit_before>// Copyright (c) 2015, The Radare Project. All rights reserved.
// See the COPYING file at the top-level directory of this distribution.
// Licensed under the BSD 3-Clause License:
// <http://opensource.org/licenses/BSD-3-Clause>
// This file may not be copied, modified, or distributed
// except according to those terms.

//! Graph visualization traits and functions to emit dot code.

use std::collections::HashMap;

macro_rules! add_strings {
	( $( $x: expr ),* ) => {
		{
			let mut s = String::new();
			$(
				s.push_str(&format!("{}", $x));
			 )*
				s
		}
	};
}

/// Represents the contents of a GraphViz attribute block
pub enum DotAttrBlock {
	/// The attribute block as string including the surrounding square brackets.
	/// Values have to be escaped manually.
	Raw(String),
	/// List of key-value pairs.
	/// Values will be escaped for you.
	Attributes(Vec<(String, String)>),
	/// Represents one line in a dot file
	Hybrid(String, Vec<(String, String)>),
}

impl DotAttrBlock {
	fn bake(&mut self) -> &String {
		let mut r = String::new();
		let attr = if let &mut DotAttrBlock::Hybrid(ref s, ref attr) = self {
			r.push_str(&s);
			attr.clone()
		} else {
			Vec::new()
		};

		if attr.len() > 0 {
			*self = DotAttrBlock::Attributes(attr);
		}

		let s: String = match self {
			&mut DotAttrBlock::Raw(ref l) => return l,
			&mut DotAttrBlock::Attributes(ref attrs) => {
				if attrs.len() == 0 {
					"".to_owned()
				} else {
					let mut t = " [".to_string();
					for &(ref k, ref v) in attrs {
						t.push_str(&*format!(" {}={}", k, v));
					}
					t.push_str(" ]");
					t
				}
			}
			_ => unreachable!(),
		};

		r.push_str(&s);
		r.push_str(";\n");
		*self = DotAttrBlock::Raw(r);
		if let &mut DotAttrBlock::Raw(ref r) = self { return r }
		unreachable!();
	}
}

/// This trait enables graphs to be generated from implementors.
pub trait GraphDot {
	type NodeIndex;
	type EdgeIndex;

	fn node_index_new(usize) -> Self::NodeIndex;
	fn edge_index_new(usize) -> Self::EdgeIndex;

	fn configure(&self) -> String;
	fn node_count(&self) -> usize;
	fn edge_count(&self) -> usize;
	//fn nodes(&self) -> Vec<Self::NodeType>;
	//fn edges(&self) -> Vec<Self::EdgeType>;
	//fn get_node(&self, n: usize) -> Option<&Self::NodeType>;

	/// Nodes with the same node_cluster return value will be put in the same
	/// graphviz-cluster.
	fn node_cluster(&self, _: &Self::NodeIndex) -> Option<usize> { Some(0) }

	fn node_skip(&self, &Self::NodeIndex) -> bool { false }
	fn node_attrs(&self, &Self::NodeIndex) -> DotAttrBlock;

	fn edge_skip(&self, &Self::EdgeIndex) -> bool { false }
	fn edge_attrs(&self, &Self::EdgeIndex) -> DotAttrBlock;

	fn edge_source(&self, &Self::EdgeIndex) -> Self::NodeIndex;
	fn edge_target(&self, &Self::EdgeIndex) -> Self::NodeIndex;
}

pub fn emit_dot<T: GraphDot>(g: &T) -> String {
	let mut result = String::new();
	result.push_str(&*g.configure());

	// Node configurations
	{
		let nodes = g.node_count();

		let mut links: Vec<usize> = Vec::with_capacity(nodes);
		let mut clustermap: HashMap<usize, (usize, usize)> = HashMap::new();

		for i in 0..nodes {
			let cid = g.node_cluster(&T::node_index_new(i));
			let entry = clustermap.entry(cid.unwrap());
			let ec = entry.or_insert((i, i));
			links.push(ec.1);
			ec.1 = i;
		}

		for (&cid, &(first, last)) in clustermap.iter() {
			result.push_str(&*format!("subgraph cluster_{} {{\n", cid));
			result.push_str(&*format!("rankdir=TB;\n"));
			let mut i = last;
			loop {
				result.push_str(&*g.node_attrs(&T::node_index_new(i)).bake());
				if i == first { break }
				i = links[i];
			}
			result.push_str("}\n");
		}
	}

	// Connect nodes by edges.
	for i in 0..g.edge_count() {
		let edge_i = &T::edge_index_new(i);
		if g.edge_skip(edge_i) { continue }
		result.push_str(g.edge_attrs(edge_i).bake());
	}

	result.push_str("\n}\n");
	result
}
<commit_msg>Simplifies the logic to associate nodes to clusters<commit_after>// Copyright (c) 2015, The Radare Project. All rights reserved.
// See the COPYING file at the top-level directory of this distribution.
// Licensed under the BSD 3-Clause License:
// <http://opensource.org/licenses/BSD-3-Clause>
// This file may not be copied, modified, or distributed
// except according to those terms.

//! Graph visualization traits and functions to emit dot code.

use std::collections::HashMap;

macro_rules! add_strings {
	( $( $x: expr ),* ) => {
		{
			let mut s = String::new();
			$(
				s.push_str(&format!("{}", $x));
			 )*
				s
		}
	};
}

/// Represents the contents of a GraphViz attribute block
pub enum DotAttrBlock {
	/// The attribute block as string including the surrounding square brackets.
	/// Values have to be escaped manually.
	Raw(String),
	/// List of key-value pairs.
	/// Values will be escaped for you.
	Attributes(Vec<(String, String)>),
	/// Represents one line in a dot file
	Hybrid(String, Vec<(String, String)>),
}

impl DotAttrBlock {
	fn bake(&mut self) -> &String {
		let mut r = String::new();
		let attr = if let &mut DotAttrBlock::Hybrid(ref s, ref attr) = self {
			r.push_str(&s);
			attr.clone()
		} else {
			Vec::new()
		};

		if attr.len() > 0 {
			*self = DotAttrBlock::Attributes(attr);
		}

		let s: String = match self {
			&mut DotAttrBlock::Raw(ref l) => return l,
			&mut DotAttrBlock::Attributes(ref attrs) => {
				if attrs.len() == 0 {
					"".to_owned()
				} else {
					let mut t = " [".to_string();
					for &(ref k, ref v) in attrs {
						t.push_str(&*format!(" {}={}", k, v));
					}
					t.push_str(" ]");
					t
				}
			}
			_ => unreachable!(),
		};

		r.push_str(&s);
		r.push_str(";\n");
		*self = DotAttrBlock::Raw(r);
		if let &mut DotAttrBlock::Raw(ref r) = self { return r }
		unreachable!();
	}
}

/// This trait enables graphs to be generated from implementors.
pub trait GraphDot {
	type NodeIndex;
	type EdgeIndex;

	fn node_index_new(usize) -> Self::NodeIndex;
	fn edge_index_new(usize) -> Self::EdgeIndex;

	fn configure(&self) -> String;
	fn node_count(&self) -> usize;
	fn edge_count(&self) -> usize;
	//fn nodes(&self) -> Vec<Self::NodeType>;
	//fn edges(&self) -> Vec<Self::EdgeType>;
	//fn get_node(&self, n: usize) -> Option<&Self::NodeType>;

	/// Nodes with the same node_cluster return value will be put in the same
	/// graphviz-cluster.
	fn node_cluster(&self, _: &Self::NodeIndex) -> Option<usize> { Some(0) }

	fn node_skip(&self, &Self::NodeIndex) -> bool { false }
	fn node_attrs(&self, &Self::NodeIndex) -> DotAttrBlock;

	fn edge_skip(&self, &Self::EdgeIndex) -> bool { false }
	fn edge_attrs(&self, &Self::EdgeIndex) -> DotAttrBlock;

	fn edge_source(&self, &Self::EdgeIndex) -> Self::NodeIndex;
	fn edge_target(&self, &Self::EdgeIndex) -> Self::NodeIndex;
}

pub fn emit_dot<T: GraphDot>(g: &T) -> String {
	let mut result = String::new();
	result.push_str(&*g.configure());

	// Node configurations
	{
		let nodes = g.node_count();
		let mut clustermap = HashMap::<usize, Vec<usize>>::new();

		for i in 0..nodes {
			let block = g.node_cluster(&T::node_index_new(i));
			clustermap.entry(block.unwrap())
			          .or_insert(Vec::new())
					  .push(i);
		}

		for (k, v) in clustermap.iter() {
			result.push_str(&*format!("subgraph cluster_{} {{\n", k));
			result.push_str(&*format!("rankdir=TB;\n"));
			for node in v.iter() {
				result.push_str(&*g.node_attrs(&T::node_index_new(*node)).bake());
			}
			result.push_str("}\n");
		}
	}

	// Connect nodes by edges.
	for i in 0..g.edge_count() {
		let edge_i = &T::edge_index_new(i);
		if g.edge_skip(edge_i) { continue }
		result.push_str(g.edge_attrs(edge_i).bake());
	}

	result.push_str("\n}\n");
	result
}
<|endoftext|>


<commit_before>// Copyright (c) 2016 Yusuke Sasaki
//
// This software is released under the MIT License.
// See http://opensource.org/licenses/mit-license.php or <LICENSE>.

use super::attr;
use super::{Var, Model};
use error::Result;
use itertools::*;

use std::ops::{Add, Sub, Mul};

/// Linear expression of variables
///
/// A linear expression consists of a constant term plus a list of coefficients and variables.
#[derive(Clone)]
pub struct LinExpr {
  vars: Vec<Var>,
  coeff: Vec<f64>,
  offset: f64
}

impl Into<(Vec<i32>, Vec<f64>, f64)> for LinExpr {
  fn into(self) -> (Vec<i32>, Vec<f64>, f64) {
    (self.vars.into_iter().map(|e| e.index()).collect(), self.coeff, self.offset)
  }
}

impl LinExpr {
  /// Create an empty linear expression.
  pub fn new() -> Self {
    LinExpr {
      vars: Vec::new(),
      coeff: Vec::new(),
      offset: 0.0
    }
  }

  /// Add a linear term into the expression.
  pub fn add_term(mut self, coeff: f64, var: Var) -> Self {
    self.coeff.push(coeff);
    self.vars.push(var);
    self
  }

  /// Add a constant into the expression.
  pub fn add_constant(mut self, constant: f64) -> Self {
    self.offset += constant;
    self
  }

  /// Get actual value of the expression.
  pub fn get_value(&self, model: &Model) -> Result<f64> {
    let vars = try!(model.get_values(attr::exports::X, self.vars.as_slice()));

    Ok(Zip::new((vars, self.coeff.iter())).fold(0.0, |acc, (ind, val)| acc + ind * val) + self.offset)
  }
}

impl<'a> Into<QuadExpr> for &'a Var {
  fn into(self) -> QuadExpr { QuadExpr::new().add_term(1.0, self.clone()) }
}

impl Into<QuadExpr> for LinExpr {
  fn into(self) -> QuadExpr {
    QuadExpr {
      lind: self.vars,
      lval: self.coeff,
      offset: self.offset,
      qrow: Vec::new(),
      qcol: Vec::new(),
      qval: Vec::new()
    }
  }
}

/// Quadratic expression of variables
///
/// A quadratic expression consists of a linear expression and a set of
/// variable-variable-coefficient triples to express the quadratic term.
#[derive(Clone)]
pub struct QuadExpr {
  lind: Vec<Var>,
  lval: Vec<f64>,
  qrow: Vec<Var>,
  qcol: Vec<Var>,
  qval: Vec<f64>,
  offset: f64
}

impl Into<(Vec<i32>, Vec<f64>, Vec<i32>, Vec<i32>, Vec<f64>, f64)> for QuadExpr {
  fn into(self) -> (Vec<i32>, Vec<f64>, Vec<i32>, Vec<i32>, Vec<f64>, f64) {
    (self.lind.into_iter().map(|e| e.index()).collect(),
     self.lval,
     self.qrow.into_iter().map(|e| e.index()).collect(),
     self.qcol.into_iter().map(|e| e.index()).collect(),
     self.qval,
     self.offset)
  }
}

impl QuadExpr {
  pub fn new() -> Self {
    QuadExpr {
      lind: Vec::new(),
      lval: Vec::new(),
      qrow: Vec::new(),
      qcol: Vec::new(),
      qval: Vec::new(),
      offset: 0.0
    }
  }

  /// Add a linear term into the expression.
  pub fn add_term(mut self, coeff: f64, var: Var) -> Self {
    self.lind.push(var);
    self.lval.push(coeff);
    self
  }

  /// Add a quadratic term into the expression.
  pub fn add_qterm(mut self, coeff: f64, row: Var, col: Var) -> Self {
    self.qval.push(coeff);
    self.qrow.push(row);
    self.qcol.push(col);
    self
  }

  /// Add a constant into the expression.
  pub fn add_constant(mut self, constant: f64) -> Self {
    self.offset += constant;
    self
  }

  /// Get actual value of the expression.
  pub fn get_value(&self, model: &Model) -> Result<f64> {
    let lind = try!(model.get_values(attr::exports::X, self.lind.as_slice()));
    let qrow = try!(model.get_values(attr::exports::X, self.qrow.as_slice()));
    let qcol = try!(model.get_values(attr::exports::X, self.qcol.as_slice()));

    Ok(Zip::new((lind, self.lval.iter())).fold(0.0, |acc, (ind, val)| acc + ind * val) +
       Zip::new((qrow, qcol, self.qval.iter())).fold(0.0, |acc, (row, col, val)| acc + row * col * val) +
       self.offset)
  }
}

impl Mul<f64> for Var {
  type Output = LinExpr;
  fn mul(self, rhs: f64) -> Self::Output { LinExpr::new().add_term(rhs, self) }
}

impl<'a> Mul<&'a Var> for f64 {
  type Output = LinExpr;
  fn mul(self, rhs: &'a Var) -> Self::Output { LinExpr::new().add_term(self, rhs.clone()) }
}

impl<'a> Mul for &'a Var {
  type Output = QuadExpr;
  fn mul(self, rhs: &'a Var) -> Self::Output { QuadExpr::new().add_qterm(1.0, self.clone(), rhs.clone()) }
}

impl Mul<f64> for QuadExpr {
  type Output = QuadExpr;
  fn mul(mut self, rhs: f64) -> Self::Output {
    for i in 0..(self.lval.len()) {
      self.lval[i] *= rhs;
    }
    for j in 0..(self.qval.len()) {
      self.qval[j] *= rhs;
    }
    self.offset *= rhs;
    self
  }
}

impl Add<f64> for LinExpr {
  type Output = LinExpr;
  fn add(self, rhs: f64) -> Self::Output { self.add_constant(rhs) }
}

impl Sub<f64> for LinExpr {
  type Output = LinExpr;
  fn sub(self, rhs: f64) -> Self::Output { self.add_constant(-rhs) }
}

impl Add for LinExpr {
  type Output = LinExpr;
  fn add(mut self, rhs: LinExpr) -> Self::Output {
    self.vars.extend(rhs.vars);
    self.coeff.extend(rhs.coeff);
    self.offset += rhs.offset;
    self
  }
}

impl Sub for LinExpr {
  type Output = LinExpr;
  fn sub(mut self, rhs: LinExpr) -> Self::Output {
    self.vars.extend(rhs.vars);
    self.coeff.extend(rhs.coeff.into_iter().map(|c| -c));
    self.offset -= rhs.offset;
    self
  }
}

impl Add<LinExpr> for QuadExpr {
  type Output = QuadExpr;
  fn add(mut self, rhs: LinExpr) -> Self::Output {
    self.lind.extend(rhs.vars);
    self.lval.extend(rhs.coeff);
    self.offset += rhs.offset;
    self
  }
}

impl Sub<LinExpr> for QuadExpr {
  type Output = QuadExpr;
  fn sub(mut self, rhs: LinExpr) -> Self::Output {
    self.lind.extend(rhs.vars);
    self.lval.extend(rhs.coeff.into_iter().map(|c| -c));
    self.offset -= rhs.offset;
    self
  }
}

impl Add for QuadExpr {
  type Output = QuadExpr;
  fn add(mut self, rhs: QuadExpr) -> QuadExpr {
    self.lind.extend(rhs.lind);
    self.lval.extend(rhs.lval);
    self.qrow.extend(rhs.qrow);
    self.qcol.extend(rhs.qcol);
    self.qval.extend(rhs.qval);
    self.offset += rhs.offset;
    self
  }
}

impl Sub for QuadExpr {
  type Output = QuadExpr;
  fn sub(mut self, rhs: QuadExpr) -> QuadExpr {
    self.lind.extend(rhs.lind);
    self.lval.extend(rhs.lval.into_iter().map(|c| -c));
    self.qrow.extend(rhs.qrow);
    self.qcol.extend(rhs.qcol);
    self.qval.extend(rhs.qval.into_iter().map(|c| -c));
    self.offset -= rhs.offset;
    self
  }
}

impl<'a> Add for &'a Var {
  type Output = LinExpr;
  fn add(self, rhs: &Var) -> LinExpr { LinExpr::new().add_term(1.0, self.clone()).add_term(1.0, rhs.clone()) }
}

impl<'a> Sub for &'a Var {
  type Output = LinExpr;
  fn sub(self, rhs: &Var) -> LinExpr { LinExpr::new().add_term(1.0, self.clone()).add_term(-1.0, rhs.clone()) }
}

impl<'a> Add<LinExpr> for &'a Var {
  type Output = LinExpr;
  fn add(self, rhs: LinExpr) -> LinExpr { rhs.add_term(1.0, self.clone()) }
}

impl<'a> Add<&'a Var> for LinExpr {
  type Output = LinExpr;
  fn add(self, rhs: &'a Var) -> LinExpr { self.add_term(1.0, rhs.clone()) }
}
<commit_msg>implement operator overloads<commit_after>// Copyright (c) 2016 Yusuke Sasaki
//
// This software is released under the MIT License.
// See http://opensource.org/licenses/mit-license.php or <LICENSE>.

use super::attr;
use super::{Var, Model};
use error::Result;
use itertools::*;

use std::ops::{Add, Sub, Mul, Neg};

/// Linear expression of variables
///
/// A linear expression consists of a constant term plus a list of coefficients and variables.
#[derive(Clone)]
pub struct LinExpr {
  vars: Vec<Var>,
  coeff: Vec<f64>,
  offset: f64
}

impl Into<(Vec<i32>, Vec<f64>, f64)> for LinExpr {
  fn into(self) -> (Vec<i32>, Vec<f64>, f64) {
    (self.vars.into_iter().map(|e| e.index()).collect(), self.coeff, self.offset)
  }
}

impl LinExpr {
  /// Create an empty linear expression.
  pub fn new() -> Self {
    LinExpr {
      vars: Vec::new(),
      coeff: Vec::new(),
      offset: 0.0
    }
  }

  /// Add a linear term into the expression.
  pub fn add_term(mut self, coeff: f64, var: Var) -> Self {
    self.coeff.push(coeff);
    self.vars.push(var);
    self
  }

  /// Add a constant into the expression.
  pub fn add_constant(mut self, constant: f64) -> Self {
    self.offset += constant;
    self
  }

  /// Get actual value of the expression.
  pub fn get_value(&self, model: &Model) -> Result<f64> {
    let vars = try!(model.get_values(attr::exports::X, self.vars.as_slice()));

    Ok(Zip::new((vars, self.coeff.iter())).fold(0.0, |acc, (ind, val)| acc + ind * val) + self.offset)
  }
}

/// Quadratic expression of variables
///
/// A quadratic expression consists of a linear expression and a set of
/// variable-variable-coefficient triples to express the quadratic term.
#[derive(Clone)]
pub struct QuadExpr {
  lind: Vec<Var>,
  lval: Vec<f64>,
  qrow: Vec<Var>,
  qcol: Vec<Var>,
  qval: Vec<f64>,
  offset: f64
}

impl Into<(Vec<i32>, Vec<f64>, Vec<i32>, Vec<i32>, Vec<f64>, f64)> for QuadExpr {
  fn into(self) -> (Vec<i32>, Vec<f64>, Vec<i32>, Vec<i32>, Vec<f64>, f64) {
    (self.lind.into_iter().map(|e| e.index()).collect(),
     self.lval,
     self.qrow.into_iter().map(|e| e.index()).collect(),
     self.qcol.into_iter().map(|e| e.index()).collect(),
     self.qval,
     self.offset)
  }
}

impl QuadExpr {
  pub fn new() -> Self {
    QuadExpr {
      lind: Vec::new(),
      lval: Vec::new(),
      qrow: Vec::new(),
      qcol: Vec::new(),
      qval: Vec::new(),
      offset: 0.0
    }
  }

  /// Add a linear term into the expression.
  pub fn add_term(mut self, coeff: f64, var: Var) -> Self {
    self.lind.push(var);
    self.lval.push(coeff);
    self
  }

  /// Add a quadratic term into the expression.
  pub fn add_qterm(mut self, coeff: f64, row: Var, col: Var) -> Self {
    self.qval.push(coeff);
    self.qrow.push(row);
    self.qcol.push(col);
    self
  }

  /// Add a constant into the expression.
  pub fn add_constant(mut self, constant: f64) -> Self {
    self.offset += constant;
    self
  }

  /// Get actual value of the expression.
  pub fn get_value(&self, model: &Model) -> Result<f64> {
    let lind = try!(model.get_values(attr::exports::X, self.lind.as_slice()));
    let qrow = try!(model.get_values(attr::exports::X, self.qrow.as_slice()));
    let qcol = try!(model.get_values(attr::exports::X, self.qcol.as_slice()));

    Ok(Zip::new((lind, self.lval.iter())).fold(0.0, |acc, (ind, val)| acc + ind * val) +
       Zip::new((qrow, qcol, self.qval.iter())).fold(0.0, |acc, (row, col, val)| acc + row * col * val) +
       self.offset)
  }
}

// Conversion into QuadExpr

impl Into<QuadExpr> for Var {
  fn into(self) -> QuadExpr { QuadExpr::new().add_term(1.0, self) }
}

impl<'a> Into<QuadExpr> for &'a Var {
  fn into(self) -> QuadExpr { QuadExpr::new().add_term(1.0, self.clone()) }
}

impl Into<QuadExpr> for LinExpr {
  fn into(self) -> QuadExpr {
    QuadExpr {
      lind: self.vars,
      lval: self.coeff,
      offset: self.offset,
      qrow: Vec::new(),
      qcol: Vec::new(),
      qval: Vec::new()
    }
  }
}

/// /////// Operator definition.

// Var + Var  => LinExpr
impl Add for Var {
  type Output = LinExpr;
  fn add(self, rhs: Var) -> LinExpr { LinExpr::new().add_term(1.0, self).add_term(1.0, rhs) }
}
impl<'a> Add<&'a Var> for Var {
  type Output = LinExpr;
  fn add(self, rhs: &Var) -> LinExpr { LinExpr::new().add_term(1.0, self).add_term(1.0, rhs.clone()) }
}
impl<'a> Add<Var> for &'a Var {
  type Output = LinExpr;
  fn add(self, rhs: Var) -> LinExpr { LinExpr::new().add_term(1.0, self.clone()).add_term(1.0, rhs) }
}
impl<'a, 'b> Add<&'b Var> for &'a Var {
  type Output = LinExpr;
  fn add(self, rhs: &Var) -> LinExpr { LinExpr::new().add_term(1.0, self.clone()).add_term(1.0, rhs.clone()) }
}

/// / Var - Var  => LinExpr
impl Sub for Var {
  type Output = LinExpr;
  fn sub(self, rhs: Var) -> LinExpr { LinExpr::new().add_term(1.0, self).add_term(-1.0, rhs) }
}
impl<'a> Sub<&'a Var> for Var {
  type Output = LinExpr;
  fn sub(self, rhs: &Var) -> LinExpr { LinExpr::new().add_term(1.0, self).add_term(-1.0, rhs.clone()) }
}
impl<'a> Sub<Var> for &'a Var {
  type Output = LinExpr;
  fn sub(self, rhs: Var) -> LinExpr { LinExpr::new().add_term(1.0, self.clone()).add_term(-1.0, rhs) }
}
impl<'a, 'b> Sub<&'b Var> for &'a Var {
  type Output = LinExpr;
  fn sub(self, rhs: &Var) -> LinExpr { LinExpr::new().add_term(1.0, self.clone()).add_term(-1.0, rhs.clone()) }
}

// -Var  => LinExpr
impl Neg for Var {
  type Output = LinExpr;
  fn neg(self) -> LinExpr { LinExpr::new().add_term(-1.0, self) }
}
impl<'a> Neg for &'a Var {
  type Output = LinExpr;
  fn neg(self) -> LinExpr { LinExpr::new().add_term(-1.0, self.clone()) }
}

// Var * f64  => LinExpr
impl Mul<f64> for Var {
  type Output = LinExpr;
  fn mul(self, rhs: f64) -> Self::Output { LinExpr::new().add_term(rhs, self) }
}
impl<'a> Mul<f64> for &'a Var {
  type Output = LinExpr;
  fn mul(self, rhs: f64) -> Self::Output { LinExpr::new().add_term(rhs, self.clone()) }
}
impl Mul<Var> for f64 {
  type Output = LinExpr;
  fn mul(self, rhs: Var) -> Self::Output { LinExpr::new().add_term(self, rhs) }
}
impl<'a> Mul<&'a Var> for f64 {
  type Output = LinExpr;
  fn mul(self, rhs: &'a Var) -> Self::Output { LinExpr::new().add_term(self, rhs.clone()) }
}

// Var * Var => QuadExpr
impl Mul for Var {
  type Output = QuadExpr;
  fn mul(self, rhs: Var) -> Self::Output { QuadExpr::new().add_qterm(1.0, self, rhs) }
}
impl<'a> Mul<&'a Var> for Var {
  type Output = QuadExpr;
  fn mul(self, rhs: &Var) -> Self::Output { QuadExpr::new().add_qterm(1.0, self, rhs.clone()) }
}
impl<'a> Mul<Var> for &'a Var {
  type Output = QuadExpr;
  fn mul(self, rhs: Var) -> Self::Output { QuadExpr::new().add_qterm(1.0, self.clone(), rhs) }
}
impl<'a, 'b> Mul<&'b Var> for &'a Var {
  type Output = QuadExpr;
  fn mul(self, rhs: &Var) -> Self::Output { QuadExpr::new().add_qterm(1.0, self.clone(), rhs.clone()) }
}

// LinExpr + Var  ==> LinExpr
impl Add<LinExpr> for Var {
  type Output = LinExpr;
  fn add(self, rhs: LinExpr) -> LinExpr { rhs.add_term(1.0, self) }
}
impl<'a> Add<LinExpr> for &'a Var {
  type Output = LinExpr;
  fn add(self, rhs: LinExpr) -> LinExpr { rhs.add_term(1.0, self.clone()) }
}
impl Add<Var> for LinExpr {
  type Output = LinExpr;
  fn add(self, rhs: Var) -> LinExpr { self.add_term(1.0, rhs) }
}
impl<'a> Add<&'a Var> for LinExpr {
  type Output = LinExpr;
  fn add(self, rhs: &'a Var) -> LinExpr { self.add_term(1.0, rhs.clone()) }
}

// LinExpr + f64 => LinExpr
impl Add<f64> for LinExpr {
  type Output = LinExpr;
  fn add(self, rhs: f64) -> Self::Output { self.add_constant(rhs) }
}
impl Add<LinExpr> for f64 {
  type Output = LinExpr;
  fn add(self, rhs: LinExpr) -> Self::Output { rhs.add_constant(self) }
}

// LinExpr - f64  => LinExpr
impl Sub<f64> for LinExpr {
  type Output = LinExpr;
  fn sub(self, rhs: f64) -> Self::Output { self.add_constant(-rhs) }
}

// f64 - LinExpr  => LinExpr
impl Sub<LinExpr> for f64 {
  type Output = LinExpr;
  fn sub(self, mut rhs: LinExpr) -> Self::Output {
    for c in rhs.coeff.iter_mut() {
      *c *= -1.0;
    }
    rhs.add_constant(-self)
  }
}

impl Add for LinExpr {
  type Output = LinExpr;
  fn add(mut self, rhs: LinExpr) -> Self::Output {
    self.vars.extend(rhs.vars);
    self.coeff.extend(rhs.coeff);
    self.offset += rhs.offset;
    self
  }
}

impl Sub for LinExpr {
  type Output = LinExpr;
  fn sub(mut self, rhs: LinExpr) -> Self::Output {
    self.vars.extend(rhs.vars);
    self.coeff.extend(rhs.coeff.into_iter().map(|c| -c));
    self.offset -= rhs.offset;
    self
  }
}

impl Mul<f64> for QuadExpr {
  type Output = QuadExpr;
  fn mul(mut self, rhs: f64) -> Self::Output {
    for i in 0..(self.lval.len()) {
      self.lval[i] *= rhs;
    }
    for j in 0..(self.qval.len()) {
      self.qval[j] *= rhs;
    }
    self.offset *= rhs;
    self
  }
}

impl Add<LinExpr> for QuadExpr {
  type Output = QuadExpr;
  fn add(mut self, rhs: LinExpr) -> Self::Output {
    self.lind.extend(rhs.vars);
    self.lval.extend(rhs.coeff);
    self.offset += rhs.offset;
    self
  }
}

impl Sub<LinExpr> for QuadExpr {
  type Output = QuadExpr;
  fn sub(mut self, rhs: LinExpr) -> Self::Output {
    self.lind.extend(rhs.vars);
    self.lval.extend(rhs.coeff.into_iter().map(|c| -c));
    self.offset -= rhs.offset;
    self
  }
}

impl Add for QuadExpr {
  type Output = QuadExpr;
  fn add(mut self, rhs: QuadExpr) -> QuadExpr {
    self.lind.extend(rhs.lind);
    self.lval.extend(rhs.lval);
    self.qrow.extend(rhs.qrow);
    self.qcol.extend(rhs.qcol);
    self.qval.extend(rhs.qval);
    self.offset += rhs.offset;
    self
  }
}

impl Sub for QuadExpr {
  type Output = QuadExpr;
  fn sub(mut self, rhs: QuadExpr) -> QuadExpr {
    self.lind.extend(rhs.lind);
    self.lval.extend(rhs.lval.into_iter().map(|c| -c));
    self.qrow.extend(rhs.qrow);
    self.qcol.extend(rhs.qcol);
    self.qval.extend(rhs.qval.into_iter().map(|c| -c));
    self.offset -= rhs.offset;
    self
  }
}
<|endoftext|>