<commit_before>// Copyright © 2016, Canal TP and/or its affiliates. All rights reserved.
//
// This file is part of Navitia,
//     the software to build cool stuff with public transport.
//
// Hope you'll enjoy and contribute to this project,
//     powered by Canal TP (www.canaltp.fr).
// Help us simplify mobility and open public transport:
//     a non ending quest to the responsive locomotion way of traveling!
//
// LICENCE: This program is free software; you can redistribute it
// and/or modify it under the terms of the GNU Affero General Public
// License as published by the Free Software Foundation, either
// version 3 of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public
// License along with this program. If not, see
// <http://www.gnu.org/licenses/>.
//
// Stay tuned using
// twitter @navitia
// IRC #navitia on freenode
// https://groups.google.com/d/forum/navitia
// www.navitia.io
extern crate log;
extern crate osmpbfreader;
extern crate mimir;
extern crate osm_builder;

use std::collections::HashMap;
use mimir::objects::{Polygon, MultiPolygon};

struct BoundaryPart {
    nodes: Vec<osmpbfreader::Node>,
}

impl BoundaryPart {
    pub fn new(nodes: Vec<osmpbfreader::Node>) -> BoundaryPart {
        BoundaryPart { nodes: nodes }
    }
    pub fn first(&self) -> i64 {
        self.nodes.first().unwrap().id
    }
    pub fn last(&self) -> i64 {
        self.nodes.last().unwrap().id
    }
}

fn get_nodes(way: &osmpbfreader::Way,
             objects: &HashMap<osmpbfreader::OsmId, osmpbfreader::OsmObj>)
             -> Vec<osmpbfreader::Node> {
    way.nodes
       .iter()
       .filter_map(|node_id| objects.get(&osmpbfreader::OsmId::Node(*node_id)))
       .filter_map(|node_obj| {
           if let &osmpbfreader::OsmObj::Node(ref node) = node_obj {
               Some(node.clone())
           } else {
               None
           }
       })
       .collect()
}

#[test]
fn test_get_nodes() {
    let mut objects = HashMap::new();
    let way = osmpbfreader::Way {
        id: 12,
        nodes: vec![12, 15, 8, 68],
        tags: osmpbfreader::Tags::new(),
    };
    objects.insert(osmpbfreader::OsmId::Way(12),
                   osmpbfreader::OsmObj::Way(way.clone()));
    let node_12 = osmpbfreader::Node {
        id: 12,
        lat: 1.2,
        lon: 3.7,
        tags: osmpbfreader::Tags::new(),
    };
    objects.insert(osmpbfreader::OsmId::Node(12),
                   osmpbfreader::OsmObj::Node(node_12));
    let node_13 = osmpbfreader::Node {
        id: 13,
        lat: 1.5,
        lon: 3.5,
        tags: osmpbfreader::Tags::new(),
    };
    objects.insert(osmpbfreader::OsmId::Node(13),
                   osmpbfreader::OsmObj::Node(node_13));
    let node_15 = osmpbfreader::Node {
        id: 15,
        lat: 7.5,
        lon: 13.5,
        tags: osmpbfreader::Tags::new(),
    };
    objects.insert(osmpbfreader::OsmId::Node(15),
                   osmpbfreader::OsmObj::Node(node_15));
    let node_8 = osmpbfreader::Node {
        id: 8,
        lat: 5.5,
        lon: 63.5,
        tags: osmpbfreader::Tags::new(),
    };
    objects.insert(osmpbfreader::OsmId::Node(8),
                   osmpbfreader::OsmObj::Node(node_8));
    let node_68 = osmpbfreader::Node {
        id: 68,
        lat: 45.5,
        lon: 53.5,
        tags: osmpbfreader::Tags::new(),
    };
    objects.insert(osmpbfreader::OsmId::Node(68),
                   osmpbfreader::OsmObj::Node(node_68));

    let nodes = get_nodes(&way, &objects);
    assert_eq!(nodes.len(), 4);
    assert_eq!(nodes[0].id, 12);
    assert_eq!(nodes[1].id, 15);
    assert_eq!(nodes[2].id, 8);
    assert_eq!(nodes[3].id, 68);
}

pub fn build_boundary(relation: &osmpbfreader::Relation,
                      objects: &HashMap<osmpbfreader::OsmId, osmpbfreader::OsmObj>)
                      -> Option<MultiPolygon> {
    let mut boundary_parts: Vec<BoundaryPart> =
        relation.refs
                .iter()
                .filter(|rf| rf.role == "outer" || rf.role == "" || rf.role == "enclave")
                .filter_map(|refe| {
                    objects.get(&refe.member).or_else(|| {
                        warn!("missing element for relation {}", relation.id);
                        None
                    })
                })
                .filter_map(|way_obj| {
                    if let &osmpbfreader::OsmObj::Way(ref way) = way_obj {
                        Some(way)
                    } else {
                        None
                    }
                })
                .map(|way| get_nodes(&way, objects))
                .filter(|nodes| nodes.len() > 1)
                .map(|nodes| BoundaryPart::new(nodes))
                .collect();
    let mut multipoly = MultiPolygon { polygons: Vec::new() };
    // we want to try build a polygon for a least each way
    while !boundary_parts.is_empty() {
        let mut current = -1;
        let mut first = -2;
        let mut nb_try = 0;

        let mut outer: Vec<osmpbfreader::Node> = Vec::new();
        // we try to close the polygon, if we can't we want to at least have tried one time per
        // way. We could improve that latter by trying to attach the way to both side of the
        // polygon
        let max_try = boundary_parts.len();
        while current != first && nb_try < max_try {
            let mut i = 0;
            while i < boundary_parts.len() {
                if outer.is_empty() {
                    // our polygon is empty, we initialise it with the current way
                    first = boundary_parts[i].first();
                    current = boundary_parts[i].last();
                    outer.append(&mut boundary_parts[i].nodes);
                    // this way has been used, we remove it from the pool
                    boundary_parts.remove(i);
                    continue;
                }
                if current == boundary_parts[i].first() {
                    // the start of current way touch the polygon, we add it and remove it from the
                    // pool
                    current = boundary_parts[i].last();
                    outer.append(&mut boundary_parts[i].nodes);
                    boundary_parts.remove(i);
                } else if current == boundary_parts[i].last() {
                    // the end of the current way touch the polygon, we reverse the way and add it
                    current = boundary_parts[i].first();
                    boundary_parts[i].nodes.reverse();
                    outer.append(&mut boundary_parts[i].nodes);
                    boundary_parts.remove(i);
                } else {
                    i += 1;
                    // didnt do anything, we want to explore the next way, if we had do something we
                    // will have removed the current way and there will be no need to increment
                }
                if current == first {
                    // our polygon is closed, we create it and add it to the multipolygon
                    let polygon = Polygon::new(outer.iter()
                                                    .map(|n| {
                                                        mimir::Coord {
                                                            lat: n.lat,
                                                            lon: n.lon,
                                                        }
                                                    })
                                                    .collect());
                    multipoly.polygons.push(polygon);
                    break;
                }
            }
            nb_try += 1;
        }
    }
    debug!("polygon for relation {};\"{}\"",
           relation.id,
           multipoly.to_wkt());
    if multipoly.polygons.is_empty() {
        None
    } else {
        Some(multipoly)
    }
}

#[test]
fn test_build_bounadry_empty() {
    let objects = HashMap::new();
    let mut relation = osmpbfreader::Relation {
        id: 12,
        refs: vec![],
        tags: osmpbfreader::Tags::new(),
    };
    relation.refs.push(osmpbfreader::Ref {
        member: osmpbfreader::OsmId::Way(4),
        role: "outer".to_string(),
    });
    relation.refs.push(osmpbfreader::Ref {
        member: osmpbfreader::OsmId::Way(65),
        role: "outer".to_string(),
    });
    relation.refs.push(osmpbfreader::Ref {
        member: osmpbfreader::OsmId::Way(22),
        role: "".to_string(),
    });
    assert!(build_boundary(&relation, &objects).is_none());
}

#[test]
fn test_build_bounadry_not_closed() {
    let mut builder = osm_builder::OsmBuilder::new();
    let rel_id: osmpbfreader::OsmId;
    {
        let mut rel = builder.relation();
        rel_id = rel.relation_id;
        rel.outer(vec![named_node(3.4, 5.2, "start"),
                       named_node(5.4, 5.1, "1")])
           .outer(vec![named_node(5.4, 5.1, "1"),
                       named_node(2.4, 3.1, "2")])
           .outer(vec![named_node(2.4, 3.2, "2"), named_node(6.4, 6.1, "end")]);
    }
    if let osmpbfreader::OsmObj::Relation(ref relation) = builder.objects[&rel_id] {
        assert!(build_boundary(&relation, &builder.objects).is_none());
    } else {
        assert!(false);//this should not happen
    }
}

#[test]
fn test_build_bounadry_closed() {
    let mut builder = osm_builder::OsmBuilder::new();
    let rel_id: osmpbfreader::OsmId;
    {
        let mut rel = builder.relation();
        rel_id = rel.relation_id;
        rel.outer(vec![named_node(3.4, 5.2, "start"), named_node(5.4, 5.1, "1")])
           .outer(vec![named_node(5.4, 5.1, "1"), named_node(2.4, 3.1, "2")])
           .outer(vec![named_node(2.4, 3.2, "2"), named_node(6.4, 6.1, "start")]);
    }
    if let osmpbfreader::OsmObj::Relation(ref relation) = builder.objects[&rel_id] {
        let multipolygon = build_boundary(&relation, &builder.objects);
        assert!(multipolygon.is_some());
        let multipolygon = multipolygon.unwrap();
        assert_eq!(multipolygon.polygons.len(), 1);

    } else {
        assert!(false);//this should not happen
    }
}
<commit_msg>fix build<commit_after>// Copyright © 2016, Canal TP and/or its affiliates. All rights reserved.
//
// This file is part of Navitia,
//     the software to build cool stuff with public transport.
//
// Hope you'll enjoy and contribute to this project,
//     powered by Canal TP (www.canaltp.fr).
// Help us simplify mobility and open public transport:
//     a non ending quest to the responsive locomotion way of traveling!
//
// LICENCE: This program is free software; you can redistribute it
// and/or modify it under the terms of the GNU Affero General Public
// License as published by the Free Software Foundation, either
// version 3 of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public
// License along with this program. If not, see
// <http://www.gnu.org/licenses/>.
//
// Stay tuned using
// twitter @navitia
// IRC #navitia on freenode
// https://groups.google.com/d/forum/navitia
// www.navitia.io
extern crate log;
extern crate osmpbfreader;
extern crate mimir;
extern crate osm_builder;

use std::collections::HashMap;
use mimir::objects::{Polygon, MultiPolygon};
use osm_builder::named_node;

struct BoundaryPart {
    nodes: Vec<osmpbfreader::Node>,
}

impl BoundaryPart {
    pub fn new(nodes: Vec<osmpbfreader::Node>) -> BoundaryPart {
        BoundaryPart { nodes: nodes }
    }
    pub fn first(&self) -> i64 {
        self.nodes.first().unwrap().id
    }
    pub fn last(&self) -> i64 {
        self.nodes.last().unwrap().id
    }
}

fn get_nodes(way: &osmpbfreader::Way,
             objects: &HashMap<osmpbfreader::OsmId, osmpbfreader::OsmObj>)
             -> Vec<osmpbfreader::Node> {
    way.nodes
       .iter()
       .filter_map(|node_id| objects.get(&osmpbfreader::OsmId::Node(*node_id)))
       .filter_map(|node_obj| {
           if let &osmpbfreader::OsmObj::Node(ref node) = node_obj {
               Some(node.clone())
           } else {
               None
           }
       })
       .collect()
}

#[test]
fn test_get_nodes() {
    let mut objects = HashMap::new();
    let way = osmpbfreader::Way {
        id: 12,
        nodes: vec![12, 15, 8, 68],
        tags: osmpbfreader::Tags::new(),
    };
    objects.insert(osmpbfreader::OsmId::Way(12),
                   osmpbfreader::OsmObj::Way(way.clone()));
    let node_12 = osmpbfreader::Node {
        id: 12,
        lat: 1.2,
        lon: 3.7,
        tags: osmpbfreader::Tags::new(),
    };
    objects.insert(osmpbfreader::OsmId::Node(12),
                   osmpbfreader::OsmObj::Node(node_12));
    let node_13 = osmpbfreader::Node {
        id: 13,
        lat: 1.5,
        lon: 3.5,
        tags: osmpbfreader::Tags::new(),
    };
    objects.insert(osmpbfreader::OsmId::Node(13),
                   osmpbfreader::OsmObj::Node(node_13));
    let node_15 = osmpbfreader::Node {
        id: 15,
        lat: 7.5,
        lon: 13.5,
        tags: osmpbfreader::Tags::new(),
    };
    objects.insert(osmpbfreader::OsmId::Node(15),
                   osmpbfreader::OsmObj::Node(node_15));
    let node_8 = osmpbfreader::Node {
        id: 8,
        lat: 5.5,
        lon: 63.5,
        tags: osmpbfreader::Tags::new(),
    };
    objects.insert(osmpbfreader::OsmId::Node(8),
                   osmpbfreader::OsmObj::Node(node_8));
    let node_68 = osmpbfreader::Node {
        id: 68,
        lat: 45.5,
        lon: 53.5,
        tags: osmpbfreader::Tags::new(),
    };
    objects.insert(osmpbfreader::OsmId::Node(68),
                   osmpbfreader::OsmObj::Node(node_68));

    let nodes = get_nodes(&way, &objects);
    assert_eq!(nodes.len(), 4);
    assert_eq!(nodes[0].id, 12);
    assert_eq!(nodes[1].id, 15);
    assert_eq!(nodes[2].id, 8);
    assert_eq!(nodes[3].id, 68);
}

pub fn build_boundary(relation: &osmpbfreader::Relation,
                      objects: &HashMap<osmpbfreader::OsmId, osmpbfreader::OsmObj>)
                      -> Option<MultiPolygon> {
    let mut boundary_parts: Vec<BoundaryPart> =
        relation.refs
                .iter()
                .filter(|rf| rf.role == "outer" || rf.role == "" || rf.role == "enclave")
                .filter_map(|refe| {
                    objects.get(&refe.member).or_else(|| {
                        warn!("missing element for relation {}", relation.id);
                        None
                    })
                })
                .filter_map(|way_obj| {
                    if let &osmpbfreader::OsmObj::Way(ref way) = way_obj {
                        Some(way)
                    } else {
                        None
                    }
                })
                .map(|way| get_nodes(&way, objects))
                .filter(|nodes| nodes.len() > 1)
                .map(|nodes| BoundaryPart::new(nodes))
                .collect();
    let mut multipoly = MultiPolygon { polygons: Vec::new() };
    // we want to try build a polygon for a least each way
    while !boundary_parts.is_empty() {
        let mut current = -1;
        let mut first = -2;
        let mut nb_try = 0;

        let mut outer: Vec<osmpbfreader::Node> = Vec::new();
        // we try to close the polygon, if we can't we want to at least have tried one time per
        // way. We could improve that latter by trying to attach the way to both side of the
        // polygon
        let max_try = boundary_parts.len();
        while current != first && nb_try < max_try {
            let mut i = 0;
            while i < boundary_parts.len() {
                if outer.is_empty() {
                    // our polygon is empty, we initialise it with the current way
                    first = boundary_parts[i].first();
                    current = boundary_parts[i].last();
                    outer.append(&mut boundary_parts[i].nodes);
                    // this way has been used, we remove it from the pool
                    boundary_parts.remove(i);
                    continue;
                }
                if current == boundary_parts[i].first() {
                    // the start of current way touch the polygon, we add it and remove it from the
                    // pool
                    current = boundary_parts[i].last();
                    outer.append(&mut boundary_parts[i].nodes);
                    boundary_parts.remove(i);
                } else if current == boundary_parts[i].last() {
                    // the end of the current way touch the polygon, we reverse the way and add it
                    current = boundary_parts[i].first();
                    boundary_parts[i].nodes.reverse();
                    outer.append(&mut boundary_parts[i].nodes);
                    boundary_parts.remove(i);
                } else {
                    i += 1;
                    // didnt do anything, we want to explore the next way, if we had do something we
                    // will have removed the current way and there will be no need to increment
                }
                if current == first {
                    // our polygon is closed, we create it and add it to the multipolygon
                    let polygon = Polygon::new(outer.iter()
                                                    .map(|n| {
                                                        mimir::Coord {
                                                            lat: n.lat,
                                                            lon: n.lon,
                                                        }
                                                    })
                                                    .collect());
                    multipoly.polygons.push(polygon);
                    break;
                }
            }
            nb_try += 1;
        }
    }
    debug!("polygon for relation {};\"{}\"",
           relation.id,
           multipoly.to_wkt());
    if multipoly.polygons.is_empty() {
        None
    } else {
        Some(multipoly)
    }
}

#[test]
fn test_build_bounadry_empty() {
    let objects = HashMap::new();
    let mut relation = osmpbfreader::Relation {
        id: 12,
        refs: vec![],
        tags: osmpbfreader::Tags::new(),
    };
    relation.refs.push(osmpbfreader::Ref {
        member: osmpbfreader::OsmId::Way(4),
        role: "outer".to_string(),
    });
    relation.refs.push(osmpbfreader::Ref {
        member: osmpbfreader::OsmId::Way(65),
        role: "outer".to_string(),
    });
    relation.refs.push(osmpbfreader::Ref {
        member: osmpbfreader::OsmId::Way(22),
        role: "".to_string(),
    });
    assert!(build_boundary(&relation, &objects).is_none());
}

#[test]
fn test_build_bounadry_not_closed() {
    let mut builder = osm_builder::OsmBuilder::new();
    let rel_id: osmpbfreader::OsmId;
    {
        let mut rel = builder.relation();
        rel_id = rel.relation_id;
        rel.outer(vec![named_node(3.4, 5.2, "start"),
                       named_node(5.4, 5.1, "1")])
           .outer(vec![named_node(5.4, 5.1, "1"),
                       named_node(2.4, 3.1, "2")])
           .outer(vec![named_node(2.4, 3.2, "2"), named_node(6.4, 6.1, "end")]);
    }
    if let osmpbfreader::OsmObj::Relation(ref relation) = builder.objects[&rel_id] {
        assert!(build_boundary(&relation, &builder.objects).is_none());
    } else {
        assert!(false);//this should not happen
    }
}

#[test]
fn test_build_bounadry_closed() {
    let mut builder = osm_builder::OsmBuilder::new();
    let rel_id: osmpbfreader::OsmId;
    {
        let mut rel = builder.relation();
        rel_id = rel.relation_id;
        rel.outer(vec![named_node(3.4, 5.2, "start"), named_node(5.4, 5.1, "1")])
           .outer(vec![named_node(5.4, 5.1, "1"), named_node(2.4, 3.1, "2")])
           .outer(vec![named_node(2.4, 3.2, "2"), named_node(6.4, 6.1, "start")]);
    }
    if let osmpbfreader::OsmObj::Relation(ref relation) = builder.objects[&rel_id] {
        let multipolygon = build_boundary(&relation, &builder.objects);
        assert!(multipolygon.is_some());
        let multipolygon = multipolygon.unwrap();
        assert_eq!(multipolygon.polygons.len(), 1);

    } else {
        assert!(false);//this should not happen
    }
}
<|endoftext|>


<commit_before>// #![feature(phase)]
// #[phase(plugin, link)] extern crate log;

use racer::codecleaner::{code_chunks,CodeIndicesIter};
// use codecleaner::{code_chunks,CodeIndicesIter};
// mod codecleaner;

#[cfg(test)] use racer::testutils::{rejustify, slice};

pub struct StmtIndicesIter<'a> {
    src: &'a str,
    it: CodeIndicesIter<'a>,
    pos: usize,
    start: usize,
    end: usize,
    bracelevel: i32,
    parenlevel: i32,
    is_macro: bool,
    enddelim: u8
}

impl<'a> Iterator for StmtIndicesIter<'a> {
    type Item = (usize, usize);

    #[inline]
    fn next(&mut self) -> Option<(usize, usize)> {
        let semicolon: u8 = ";".as_bytes()[0];
        let hash: u8 = "#".as_bytes()[0];
        let openbrace: u8 = "{".as_bytes()[0];
        let closebrace: u8 = "}".as_bytes()[0];
        let openparen: u8 = "(".as_bytes()[0];
        let closeparen: u8 = ")".as_bytes()[0];
        let closesqbrace: u8 = "]".as_bytes()[0];
        let bang: u8 = "!".as_bytes()[0];
        let whitespace = " \t\r\n".as_bytes();

        let __u: u8 = "u".as_bytes()[0];
        let __s: u8 = "s".as_bytes()[0];
        let __e: u8 = "e".as_bytes()[0];

        let src_bytes = self.src.as_bytes();

        loop {

            // do we need the next chunk?
            if self.end <= self.pos {
                // get the next chunk of code
                match self.it.next() {
                    Some((start, end)) => {
                        self.end = end;
                        if self.start == self.pos {
                            self.start = start;
                        }
                        self.pos = start;
                    }
                    None => {
                        // no more chunks. finished
                        if self.start < self.end {
                            let start = self.start;
                            self.start = self.end;
                            return Some((start, self.end));
                        } else {
                            return None
                        }

                    }
                }
            }

            // if this is a new stmt block, skip the whitespace
            if self.pos == self.start {
                while self.pos < self.end {
                    if !whitespace.contains(&src_bytes[self.pos]) {
                        break;
                    } else {
                        self.pos += 1;
                    }
                }
                self.start = self.pos;
            }

            // if the statement starts with 'macro_rules!' then we're in a macro
            // We need to know this because a closeparen can terminate a macro
            if (self.end - self.pos) > 12 &&
                &self.src[self.pos..self.pos+12] == "macro_rules!" {
                self.is_macro = true;
            }

            // iterate through the chunk, looking for stmt end
            while self.pos < self.end {
                if src_bytes[self.pos] == openparen {

                    // macros can be terminated by closeparen if opened by one
                    if self.is_macro &&
                        self.bracelevel == 0 &&
                        self.parenlevel == 0 {
                        self.enddelim = closeparen;
                    }

                    // also macro invocations can too
                    if self.pos > 0 && src_bytes[self.pos-1] == bang &&
                        self.bracelevel == 0 &&
                        self.parenlevel == 0 {
                        self.enddelim = closeparen;
                    }

                    self.parenlevel += 1;

                } else if src_bytes[self.pos] == closeparen {
                    self.parenlevel -= 1;

                } else if src_bytes[self.pos] == openbrace {
                    // if we are top level and stmt is not a 'use' then
                    // closebrace finishes the stmt
                    if self.bracelevel == 0 &&
                        self.parenlevel == 0 &&
                       !(is_a_use_stmt(self.src, self.start, self.pos)) {
                           self.enddelim = closebrace;
                    }
                    self.bracelevel += 1;

                } else if src_bytes[self.pos] == closebrace {
                    self.bracelevel -= 1;
                    // have we reached the end of the scope?
                    if self.bracelevel < 0 {
                        return None;
                    }
                }

                // attribute   #[foo = bar]
                if self.bracelevel == 0 && self.start == self.pos &&
                    src_bytes[self.pos] == hash {
                    self.enddelim = closesqbrace;
                }

                if self.bracelevel == 0 && self.parenlevel == 0 &&
                   src_bytes[self.pos] == self.enddelim {
                    let start = self.start;
                    self.start = self.pos+1;
                    self.pos = self.pos+1;
                    self.enddelim = semicolon;
                    self.is_macro = false;
                    return Some((start, self.pos));
                }

                self.pos += 1;
            }

        }
    }
}

fn is_a_use_stmt(src: &str, start: usize, pos: usize) -> bool {
    let src_bytes = src.as_bytes();
    let whitespace = " {\t\r\n".as_bytes();
    (pos > 3 && &src_bytes[start..start+3] == "use".as_bytes() &&
     whitespace.contains(&src_bytes[start+3])) ||
        (pos > 7 && &src_bytes[start..(start+7)] == "pub use".as_bytes() &&
                      whitespace.contains(&src_bytes[start+7]))
}

pub fn iter_stmts<'a>(src: &'a str) -> StmtIndicesIter<'a> {
    let semicolon: u8 = ";".as_bytes()[0];
    StmtIndicesIter{src: src, it: code_chunks(src),
                    pos: 0, start: 0, end: 0, bracelevel: 0,
                    parenlevel: 0, enddelim: semicolon, is_macro: false}
}

#[test]
fn iterates_single_use_stmts() {
    let src = &rejustify("
    use std::Foo; // a comment
    use std::Bar;
    ")[];
    let mut it = iter_stmts(src);
    assert_eq!("use std::Foo;", slice(src, it.next().unwrap()));
    assert_eq!("use std::Bar;", slice(src, it.next().unwrap()));
}

#[test]
fn iterates_use_stmt_over_two_lines() {
    let src = &rejustify("
    use std::{Foo,
              Bar}; // a comment
    ")[];
    let mut it = iter_stmts(src);
    assert_eq!("use std::{Foo,
          Bar};", slice(src, it.next().unwrap()));
}

#[test]
fn iterates_use_stmt_without_the_prefix() {
    let src = &rejustify("
    pub use {Foo,
              Bar}; // this is also legit apparently
    ")[];
    let mut it = iter_stmts(src);
    assert_eq!("pub use {Foo,
          Bar};", slice(src, it.next().unwrap()));
}

#[test]
fn iterates_while_stmt() {
    let src = &rejustify("
    while self.pos < 3 { }
    ")[];
    let mut it = iter_stmts(src);
    assert_eq!("while self.pos < 3 { }", slice(src, it.next().unwrap()));
}

#[test]
fn iterates_lambda_arg() {
    let src = &rejustify("
    myfn(|n|{});
    ")[];
    let mut it = iter_stmts(src);
    assert_eq!("myfn(|n|{});", slice(src, it.next().unwrap()));
}

#[test]
fn iterates_macro() {
    let src = "
    mod foo;
    macro_rules! otry(
        ($e:expr) => (match $e { Some(e) => e, None => return })
    )
    mod bar;
    ";
    let mut it = iter_stmts(src);
    assert_eq!("mod foo;", slice(src, it.next().unwrap()));
    assert_eq!("macro_rules! otry(
        ($e:expr) => (match $e { Some(e) => e, None => return })
    )", slice(src, it.next().unwrap()));
    assert_eq!("mod bar;", slice(src, it.next().unwrap()));
}

#[test]
fn iterates_macro_invocation() {
    let src = "
    mod foo;
    local_data_key!(local_stdout: Box<Writer + Send>)  // no ';'
    mod bar;
    ";
    let mut it = iter_stmts(src);
    assert_eq!("mod foo;", slice(src, it.next().unwrap()));
    assert_eq!("local_data_key!(local_stdout: Box<Writer + Send>)", slice(src, it.next().unwrap()));
    assert_eq!("mod bar;", slice(src, it.next().unwrap()));
}

// #[test]
// fn iterates_if_else_stmt() {
//     let src = rejustify("
//     if self.pos < 3 { } else { }
//     ");
//     let mut it = iter_stmts(src.as_slice());
//     assert_eq!("if self.pos < 3 { } else { }", slice(src.as_slice(), it.next().unwrap()));
// }

#[test]
fn iterates_inner_scope() {
    let src = "
    while self.pos < 3 {
       let a = 35;
       return a + 35;  // should iterate this
    }
    {
       b = foo;       // but not this
    }
    ";

    let scope = &src[25..];
    let mut it = iter_stmts(scope);

    assert_eq!("let a = 35;", slice(scope, it.next().unwrap()));
    assert_eq!("return a + 35;", slice(scope, it.next().unwrap()));
    assert_eq!(None, it.next());
}

#[test]
fn iterates_module_attribute() {
    let src = &rejustify("
    #![license = \"BSD\"]
    #[test]
    ")[];
    let mut it = iter_stmts(src);
    assert_eq!("#![license = \"BSD\"]", slice(src, it.next().unwrap()));
    assert_eq!("#[test]", slice(src, it.next().unwrap()));
}

#[test]
fn iterates_half_open_subscope_if_is_the_last_thing() {
    let src = "
    let something = 35;
    while self.pos < 3 {
       let a = 35;
       return a + 35;  // should iterate this
    ";

    let scope = src;
    let mut it = iter_stmts(scope);
    assert_eq!("let something = 35;", slice(scope, it.next().unwrap()));
    assert_eq!("while self.pos < 3 {
       let a = 35;
       return a + 35;  // should iterate this
    ", slice(scope, it.next().unwrap()));
}

// fn main() {
//     use std::io::BufferedReader;
//     use std::io::File;
//     use std::str;

//     let filetxt = BufferedReader::new(File::open(&Path::new("/usr/local/src/rust/src/libstd/io/stdio.rs"))).read_to_end().unwrap();
//     let src = str::from_utf8(filetxt.as_slice()).unwrap();

//     for (start,end) in iter_stmts(src) {
//         println!("BLOB |{}|",src.slice(start,end));
//     }

// }
<commit_msg>Review codeiter<commit_after>// #![feature(phase)]
// #[phase(plugin, link)] extern crate log;

use racer::codecleaner::{code_chunks,CodeIndicesIter};
// use codecleaner::{code_chunks,CodeIndicesIter};
// mod codecleaner;

#[cfg(test)] use racer::testutils::{rejustify, slice};

pub struct StmtIndicesIter<'a> {
    src: &'a str,
    it: CodeIndicesIter<'a>,
    pos: usize,
    end: usize
}

impl<'a> Iterator for StmtIndicesIter<'a> {
    type Item = (usize, usize);

    #[inline]
    fn next(&mut self) -> Option<(usize, usize)> {

        let src_bytes = self.src.as_bytes();
        let mut enddelim = b';';
        let mut bracelevel = 02;
        let mut parenlevel = 0i32;
        let mut start = self.pos;

        // loop on all code_chuncks until we find a relevant open/close pattern
        loop {

            // do we need the next chunk?
            if self.end == self.pos {
                // get the next chunk of code
                match self.it.next() {
                    Some((ch_start, ch_end)) => {
                        self.end = ch_end;
                        if start == self.pos { start = ch_start; }
                        self.pos = ch_start;
                    }
                    None => {
                        // no more chunks. finished
                        return if start < self.end { Some((start, self.end)) }
                        else { None }
                    }
                }
            }

            if start == self.pos {
                // if this is a new stmt block, skip the whitespace
                for &b in src_bytes[self.pos..self.end].iter() {
                    match b {
                        b' ' | b'\r' | b'\n' | b'\t' => { self.pos += 1; },
                        _ => { break; }
                    }
                }
                start = self.pos;

                // test attribute   #[foo = bar]
                if self.pos<self.end && src_bytes[self.pos] == b'#' {
                    enddelim = b']'
                };
            }

            // iterate through the chunk, looking for stmt end
            for &b in src_bytes[self.pos..self.end].iter() {

                self.pos += 1;

                match b {
                    b'(' => { parenlevel += 1; },
                    b')' => { parenlevel -= 1; },
                    b'{' => {
                        // if we are top level and stmt is not a 'use' then
                        // closebrace finishes the stmt
                        if bracelevel == 0 && parenlevel == 0
                            && !(is_a_use_stmt(self.src, start, self.pos)) {
                            enddelim = b'}';
                        }
                        bracelevel += 1;
                    },
                    b'}' => {
                        // have we reached the end of the scope?
                        if bracelevel == 0 { return None; }
                        bracelevel -= 1;
                    },
                    b'!' => {
                        // macro if followed by at least one space or (
                        // FIXME: test with boolean 'not' expression
                        if parenlevel == 0 && bracelevel == 0
                            && self.pos < self.end && (self.pos-start)>1 {
                            match src_bytes[self.pos] {
                                b' ' | b'\r' | b'\n' | b'\t' | b'('  => {
                                    enddelim = b')';
                                },
                                _ => {}
                            }
                        }
                    }
                    _ => {}
                }

                if enddelim == b && bracelevel == 0 && parenlevel == 0 {
                    return Some((start, self.pos));
                }
            }
        }
    }
}

fn is_a_use_stmt(src: &str, start: usize, pos: usize) -> bool {
    let src_bytes = src.as_bytes();
    let whitespace = " {\t\r\n".as_bytes();
    (pos > 3 && &src_bytes[start..start+3] == b"use" &&
     whitespace.contains(&src_bytes[start+3])) ||
    (pos > 7 && &src_bytes[start..(start+7)] == b"pub use" &&
     whitespace.contains(&src_bytes[start+7]))
}

pub fn iter_stmts<'a>(src: &'a str) -> StmtIndicesIter<'a> {
    StmtIndicesIter{src: src, it: code_chunks(src), pos: 0, end: 0}
}

#[test]
fn iterates_single_use_stmts() {
    let src = &rejustify("
    use std::Foo; // a comment
    use std::Bar;
    ")[];
    let mut it = iter_stmts(src);
    assert_eq!("use std::Foo;", slice(src, it.next().unwrap()));
    assert_eq!("use std::Bar;", slice(src, it.next().unwrap()));
}

#[test]
fn iterates_use_stmt_over_two_lines() {
    let src = &rejustify("
    use std::{Foo,
              Bar}; // a comment
    ")[];
    let mut it = iter_stmts(src);
    assert_eq!("use std::{Foo,
          Bar};", slice(src, it.next().unwrap()));
}

#[test]
fn iterates_use_stmt_without_the_prefix() {
    let src = &rejustify("
    pub use {Foo,
              Bar}; // this is also legit apparently
    ")[];
    let mut it = iter_stmts(src);
    assert_eq!("pub use {Foo,
          Bar};", slice(src, it.next().unwrap()));
}

#[test]
fn iterates_while_stmt() {
    let src = &rejustify("
    while self.pos < 3 { }
    ")[];
    let mut it = iter_stmts(src);
    assert_eq!("while self.pos < 3 { }", slice(src, it.next().unwrap()));
}

#[test]
fn iterates_lambda_arg() {
    let src = &rejustify("
    myfn(|n|{});
    ")[];
    let mut it = iter_stmts(src);
    assert_eq!("myfn(|n|{});", slice(src, it.next().unwrap()));
}

#[test]
fn iterates_macro() {
    let src = "
    mod foo;
    macro_rules! otry(
        ($e:expr) => (match $e { Some(e) => e, None => return })
    )
    mod bar;
    ";
    let mut it = iter_stmts(src);
    assert_eq!("mod foo;", slice(src, it.next().unwrap()));
    assert_eq!("macro_rules! otry(
        ($e:expr) => (match $e { Some(e) => e, None => return })
    )", slice(src, it.next().unwrap()));
    assert_eq!("mod bar;", slice(src, it.next().unwrap()));
}

#[test]
fn iterates_macro_invocation() {
    let src = "
    mod foo;
    local_data_key!(local_stdout: Box<Writer + Send>)  // no ';'
    mod bar;
    ";
    let mut it = iter_stmts(src);
    assert_eq!("mod foo;", slice(src, it.next().unwrap()));
    assert_eq!("local_data_key!(local_stdout: Box<Writer + Send>)", slice(src, it.next().unwrap()));
    assert_eq!("mod bar;", slice(src, it.next().unwrap()));
}

// #[test]
// fn iterates_if_else_stmt() {
//     let src = rejustify("
//     if self.pos < 3 { } else { }
//     ");
//     let mut it = iter_stmts(src.as_slice());
//     assert_eq!("if self.pos < 3 { } else { }", slice(src.as_slice(), it.next().unwrap()));
// }

#[test]
fn iterates_inner_scope() {
    let src = "
    while self.pos < 3 {
       let a = 35;
       return a + 35;  // should iterate this
    }
    {
       b = foo;       // but not this
    }
    ";

    let scope = &src[25..];
    let mut it = iter_stmts(scope);

    assert_eq!("let a = 35;", slice(scope, it.next().unwrap()));
    assert_eq!("return a + 35;", slice(scope, it.next().unwrap()));
    assert_eq!(None, it.next());
}

#[test]
fn iterates_module_attribute() {
    let src = &rejustify("
    #![license = \"BSD\"]
    #[test]
    ")[];
    let mut it = iter_stmts(src);
    assert_eq!("#![license = \"BSD\"]", slice(src, it.next().unwrap()));
    assert_eq!("#[test]", slice(src, it.next().unwrap()));
}

#[test]
fn iterates_half_open_subscope_if_is_the_last_thing() {
    let src = "
    let something = 35;
    while self.pos < 3 {
       let a = 35;
       return a + 35;  // should iterate this
    ";

    let scope = src;
    let mut it = iter_stmts(scope);
    assert_eq!("let something = 35;", slice(scope, it.next().unwrap()));
    assert_eq!("while self.pos < 3 {
       let a = 35;
       return a + 35;  // should iterate this
    ", slice(scope, it.next().unwrap()));
}

// fn main() {
//     use std::io::BufferedReader;
//     use std::io::File;
//     use std::str;

//     let filetxt = BufferedReader::new(File::open(&Path::new("/usr/local/src/rust/src/libstd/io/stdio.rs"))).read_to_end().unwrap();
//     let src = str::from_utf8(filetxt.as_slice()).unwrap();

//     for (start,end) in iter_stmts(src) {
//         println!("BLOB |{}|",src.slice(start,end));
//     }

// }
<|endoftext|>


<commit_before>#![allow(dead_code)]
use utils;
//use std::ops::{Index, Deref, DerefMut};
use std::cell::RefCell;
use std::rc::Rc;

pub type MemShared = Rc<RefCell<Memory>>;

pub 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
    }

    pub 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
                match addr
                {
                    0xD016          => self.data[(addr - self.offset) as usize] = 0xC0 | val,
                    0xD019          => self.data[(addr - self.offset) as usize] = 0x70 | val,
                    0xD01A          => self.data[(addr - self.offset) as usize] = 0xF0 | val,
                    0xD01E...0xD01F => (),                             // cannot be written - panic/fail on try?
                    0xD020...0xD02E => self.data[(addr - self.offset) as usize] = 0xF0 | val,
                    0xD02F...0xD03F => (),                             // write ignored
                    0xD040...0xD3FF => self.write(0xD000 + (addr % 0x0040), val), // same as 0xD000-0xD03F
                    _ => self.data[(addr - self.offset) as usize] = val
                }

            },
            _ => panic!("Can't write to ROM!")
        }
    }

    pub fn read(&mut self, addr: u16) -> u8
    {
        match self.bank_type
        {
            MemType::IO => {
                // TODO: IO access has specific behavior depending on address
                match addr
                {
                    0xD016          => 0xC0 | self.data[(addr - self.offset) as usize],
                    0xD018          => 0x01 | self.data[(addr - self.offset) as usize],
                    0xD019          => 0x70 | self.data[(addr - self.offset) as usize],
                    0xD01A          => 0xF0 | self.data[(addr - self.offset) as usize],
                    0xD01E...0xD01F => {                                  // cannot be written, cleared on read
                        let value = self.data[(addr - self.offset) as usize];
                        self.data[(addr - self.offset) as usize] = 0;
                        value
                    },
                    0xD020...0xD02E => 0xF0 | self.data[(addr - self.offset) as usize],
                    0xD02F...0xD03F => 0xFF,                              // always returns 0xFF
                    0xD040...0xD3FF => self.read(0xD000 + (addr % 0x0040)),          // same as 0xD000-0xD03F
                    _ => 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_shared() -> MemShared
    {
        Rc::new(RefCell::new(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")
        }
    }

    // returns specific modifiable memory bank
    pub fn get_ram_bank(&mut self, bank_type: MemType) -> (&mut MemBank)
    {
        match bank_type
        {
            MemType::RAM => &mut self.ram,
            MemType::IO  => &mut self.io,
            _            => panic!("Unrecognized RAM bank"),
        }
    }

    // returns specific non-modifiable memory bank
    pub fn get_rom_bank(&mut self, bank_type: MemType) -> (&mut MemBank)
    {
        match bank_type
        {
            MemType::BASIC   => &mut self.basic,
            MemType::CHARGEN => &mut self.chargen,
            MemType::KERNAL  => &mut self.kernal,
            _                => panic!("Unrecognized ROM Abank"),
        }
    }

    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);

        if self.io_on == false { panic!("oops"); }
    }

    // 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>fixed wrong RAM addressing (0xC000-0xCFFF)<commit_after>#![allow(dead_code)]
use utils;
//use std::ops::{Index, Deref, DerefMut};
use std::cell::RefCell;
use std::rc::Rc;

pub type MemShared = Rc<RefCell<Memory>>;

pub 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
    }

    pub 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
                match addr
                {
                    0xD016          => self.data[(addr - self.offset) as usize] = 0xC0 | val,
                    0xD019          => self.data[(addr - self.offset) as usize] = 0x70 | val,
                    0xD01A          => self.data[(addr - self.offset) as usize] = 0xF0 | val,
                    0xD01E...0xD01F => (),                             // cannot be written - panic/fail on try?
                    0xD020...0xD02E => self.data[(addr - self.offset) as usize] = 0xF0 | val,
                    0xD02F...0xD03F => (),                             // write ignored
                    0xD040...0xD3FF => self.write(0xD000 + (addr % 0x0040), val), // same as 0xD000-0xD03F
                    _ => self.data[(addr - self.offset) as usize] = val
                }

            },
            _ => panic!("Can't write to ROM!")
        }
    }

    pub fn read(&mut self, addr: u16) -> u8
    {
        match self.bank_type
        {
            MemType::IO => {
                // TODO: IO access has specific behavior depending on address
                match addr
                {
                    0xD016          => 0xC0 | self.data[(addr - self.offset) as usize],
                    0xD018          => 0x01 | self.data[(addr - self.offset) as usize],
                    0xD019          => 0x70 | self.data[(addr - self.offset) as usize],
                    0xD01A          => 0xF0 | self.data[(addr - self.offset) as usize],
                    0xD01E...0xD01F => {                                  // cannot be written, cleared on read
                        let value = self.data[(addr - self.offset) as usize];
                        self.data[(addr - self.offset) as usize] = 0;
                        value
                    },
                    0xD020...0xD02E => 0xF0 | self.data[(addr - self.offset) as usize],
                    0xD02F...0xD03F => 0xFF,                              // always returns 0xFF
                    0xD040...0xD3FF => self.read(0xD000 + (addr % 0x0040)),          // same as 0xD000-0xD03F
                    _ => 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_shared() -> MemShared
    {
        Rc::new(RefCell::new(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...0xBFFF => if self.basic_on { &mut self.basic } else { &mut self.ram },
            0xC000...0xCFFF => &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")
        }
    }

    // returns specific modifiable memory bank
    pub fn get_ram_bank(&mut self, bank_type: MemType) -> (&mut MemBank)
    {
        match bank_type
        {
            MemType::RAM => &mut self.ram,
            MemType::IO  => &mut self.io,
            _            => panic!("Unrecognized RAM bank"),
        }
    }

    // returns specific non-modifiable memory bank
    pub fn get_rom_bank(&mut self, bank_type: MemType) -> (&mut MemBank)
    {
        match bank_type
        {
            MemType::BASIC   => &mut self.basic,
            MemType::CHARGEN => &mut self.chargen,
            MemType::KERNAL  => &mut self.kernal,
            _                => panic!("Unrecognized ROM Abank"),
        }
    }

    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);

        if self.io_on == false { panic!("oops"); }
    }

    // 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>#![allow(dead_code)]
// Copyright 2012-2014 Dustin Hiatt. See the COPYRIGHT
// file at the top-level directory.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//
//! A statically-sized ring buffer that acts as an MPMC queue.  Differs
//! from the ring buffer-backed VecDeque in that this structure
//! is lockless and threadsafe.  Threadsafety is achieved using only
//! CAS operations, making this queue ideal for high throughput.  This
//! queue is not ideal for situations where a long wait is expected
//! as any getter is blocked in a spinlock until an item is put.  Locks
//! due to resource starvation are avoided by yielding the spin lock to
//! the scheduler every few thousand iterations.  This queue is cache-aware
//! and performs best with cache line sizes of 64 bytes.
//!
//! Because this queue is threadsafe, it is safe to pass an Arc around
//! to spawned threads and call put, without wrapping the struct itself
//! in a mutex.

//! Benchmarks:
//! test ringbuffer::rbtest::bench_rb_batch     ... bench:    443876 ns/iter (+/- 19276)
//! ringbuffer::rbtest::bench_rb_get       ... bench:        42 ns/iter (+/- 2)
//! ringbuffer::rbtest::bench_rb_lifecycle ... bench:        24 ns/iter (+/- 0)
//! ringbuffer::rbtest::bench_rb_put       ... bench:        36 ns/iter (+/- 5)
//! ringbuffer::rbtest::bench_vecdeque     ... bench:      2934 ns/iter (+/- 394)
//!
//! The final benchmark is comparable to the bench_rb_lifecycle in terms
//! of functionality.

/// #Examples
///
/// ```
/// use marble::ringbuffer::RingBuffer;
///
/// use std::sync::Arc;
/// use std::thread;
///
/// let rb = Arc::new(RingBuffer::new(1));
///
/// let rbc = rb.clone();
/// let join = thread::spawn(move || {
/// 	loop {
/// 		let result = rbc.get();
/// 		match result {
/// 			Err(_) => break,
/// 			_ => ()
///			}
///		}
/// });
///
/// rb.put(1);
/// rb.dispose();
/// join.join();
/// ```

use std::cell::UnsafeCell;
use std::default::Default;
use std::marker;
use std::sync::atomic::{ATOMIC_USIZE_INIT, AtomicUsize, Ordering};
use std::thread::yield_now;
use std::vec::Vec;

// Node will wrap items in the buffer and keep track of enough
// meta data to know if queue and dequere are referencing the
// correct item.  This is achieved through the atomic position
// field.
struct Node<T> {
	item: 	  Option<T>,
	position: AtomicUsize,
}

impl<T> Node<T> {
	// new creates a new node with its atomic position set to
	// position.  No item by default.
	fn new(position: usize) -> Node<T> {
		Node {
			position: AtomicUsize::new(position),
			item: None,
		}
	}
}

/// RingBuffer is a threadsafe MPMC queue that's statically-sized.
/// Puts are blocked on a full queue and gets are blocked on an empty
/// queue.  In either case, calling dispose will free any blocked threads
/// and return an error.
pub struct RingBuffer<T> {
	queue: 	   AtomicUsize,
	// padding is here to ensure that queue and dequeue end on different
	// cache lines to prevent false sharing.
	_padding0: [u64;8],
	dequeue:   AtomicUsize,
	_padding1: [u64;8],
	disposed:  AtomicUsize,
	_padding2: [u64;8],
	mask:      usize,
	// positions is unsafecell so we can grab a node mutably in the
	// put and get functions, which themselves can be called on an
	// immutable ring buffer.
	positions: UnsafeCell<Vec<Node<T>>>,
}

// these implementations are required to access a ringbuffer in a separate
// lifetime and thread using only a wrapping Arc.
unsafe impl<T> marker::Send for RingBuffer<T> {}
unsafe impl<T> marker::Sync for RingBuffer<T> {}

impl<T> Default for RingBuffer<T> {
	// this is convenient so we don't have to create 0 for atomics
	// and empty arrays with every constructor call.
	fn default() -> RingBuffer<T> {
		RingBuffer{
			queue:     ATOMIC_USIZE_INIT,
			_padding0: [0;8],
			dequeue:   ATOMIC_USIZE_INIT,
			_padding1: [0;8],
			disposed:  ATOMIC_USIZE_INIT,
			_padding2: [0;8],
			mask: 	   0,
			positions: UnsafeCell::new(vec![]),
		}
	}
}

/// RingBufferError is returned when a thread gets or puts on a disposed
/// RingBuffer.  Any blocked threads will be freed and will received this
/// error.
pub enum RingBufferError { Disposed }

impl<T> RingBuffer<T> {
	/// new creates a new RingBuffer with the specified capacity.  It
	/// is important to note that capacity will be rounded up to the next
	/// power of two.  This is done to improve performance by avoiding a
	/// costly modulo call.  To get the actual capacity of the ring buffer
	/// call cap().
	pub fn new(cap: usize) -> RingBuffer<T> {
		let calculated_capacity = cap.next_power_of_two();
		let mut positions = Vec::<Node<T>>::with_capacity(calculated_capacity);

		for i in 0..calculated_capacity {
			positions.push(Node::new(i as usize));
		}

		RingBuffer{
			mask: calculated_capacity-1,
			positions: UnsafeCell::new(positions),
			..Default::default()
		}
	}

	/// cap returns the actual capacity of the ring buffer.  This
	/// different than length, which returns the actual number of
	/// items in the ring buffer.  If cap == len, then the ring
	/// buffer is full.
	pub fn cap(&self) -> usize {
		unsafe {
			let positions = self.positions.get();
			(*positions).len()
		}
	}

	/// len returns the number of items in the ring buffer at this
	/// moment.
	pub fn len(&self) -> usize {
		self.queue.load(Ordering::Relaxed) - self.dequeue.load(Ordering::Relaxed)
	}

	/// dispose frees any resources consumed by this ring buffer and
	/// releases any threads that are currently in spin locks.  Any subsequent
	/// calls to put or get will return an error.
	pub fn dispose(&self) {
		self.disposed.store(1, Ordering::Relaxed);
	}

	/// put will add item to the ring buffer.  If the ring buffer is full
	/// this operation blocks until it can be put.  Returns an error if
	/// this ring buffer is disposed.
	pub fn put(&self, item: T) -> Result<(), RingBufferError> {
		unsafe {
			let mut position = self.queue.load(Ordering::Relaxed);
			let mut i = 0;

			loop {
				if self.disposed.load(Ordering::Relaxed) == 1 {
					return Err(RingBufferError::Disposed);
				}

				let positions = self.positions.get();
				let n = (*positions).get_unchecked_mut(position&self.mask);
				let diff = n.position.load(Ordering::Acquire) - position;
				if diff == 0 {
					if self.queue.compare_and_swap(position, position+1, Ordering::Relaxed) == position {
						n.item = Some(item);
						n.position.store(position+1, Ordering::Release);
						return Ok(());
					}
				} else {
					position = self.queue.load(Ordering::Relaxed);
				}

				if i == 10000 {
					i = 0;
					yield_now();
				} else {
					i += 1;
				}
			}
		}
	}

	/// get retrieves the next item from the ring buffer.  This method blocks
	/// if the ring buffer is empty until an item is placed.  Returns an error
	/// if the ring buffer is disposed.
	pub fn get(&self) -> Result<T, RingBufferError> {
		unsafe {
			let mut position = self.dequeue.load(Ordering::Relaxed);
			let mut i = 0;
			loop {
				if self.disposed.load(Ordering::SeqCst) == 1 {
					return Err(RingBufferError::Disposed);
				}
				let positions = self.positions.get();
				let n = (*positions).get_unchecked_mut(position&self.mask);
				let diff = n.position.load(Ordering::Acquire) - (position + 1);
				if diff == 0 {
					if self.dequeue.compare_and_swap(position, position+1, Ordering::Relaxed) == position {
						let data = n.item.take().unwrap();
						n.position.store(position+self.mask+1, Ordering::Release);
						return Ok(data);
					}
				} else {
					position = self.dequeue.load(Ordering::Relaxed);
				}

				if i == 10000 {
					i = 0;
					yield_now();
				} else {
					i += 1;
				}
			}
		}
	}
}

#[cfg(test)]
#[allow(unused_must_use)]
mod rbtest {
	extern crate test;

	use self::test::Bencher;

	use std::collections::vec_deque::VecDeque;
	use std::sync::{Arc, Mutex};
	use std::sync::atomic::{AtomicUsize, Ordering};
	use std::sync::mpsc::channel;
	use std::thread;

    use super::*;

   	#[test]
	fn test_simple_put_get() {
		let rb = RingBuffer::new(10);
		let number = 5;
		rb.put(number);
		assert_eq!(1, rb.len());
		let result = rb.get();
		match result {
			Ok(x) => assert_eq!(x, 5),
			Err(x) => panic!(x)
		}
	}

	#[test]
	fn test_fill_and_empty() {
		let rb = RingBuffer::new(8);
		for i in 0..rb.cap() {
			rb.put(i);
		}

		for i in 0..rb.cap() {
			let result = rb.get();
			match result {
				Ok(x) => assert_eq!(x, i),
				Err(x) => panic!(x)
			}
		}

		assert_eq!(0, rb.len());
	}

	#[test]
	fn test_fill_and_dispose() {
		let rb = RingBuffer::new(8);
		let arb = Arc::new(rb);
		let mut vec = vec![];

		for i in 0..arb.cap()+1 {
			let trb = arb.clone();
			let join = thread::spawn(move || {
				trb.put(i);
			});

			vec.push(join);
		}

		arb.dispose();
		for j in vec {
			j.join();
		}
	}

	#[test]
	fn test_get_put_on_dispose() {
		let rb = RingBuffer::new(2);
		rb.dispose();

		let result = rb.get();
		match result {
			Ok(_) => panic!("Should return error."),
			_ => ()
		}

		let result = rb.put(3);
		match result {
			Ok(_) => panic!("Should return error."),
			_ => ()
		}
	}

	#[bench]
	fn bench_rb_put(b: &mut Bencher) {
		b.iter(|| {
			let rb = RingBuffer::new(2);
			rb.put(1);
		});
	}

	#[bench]
	fn bench_rb_get(b: &mut Bencher) {
		b.iter(|| {
			let rb = RingBuffer::new(2);
			rb.put(1);
			rb.get();
		});
	}

	#[bench]
	fn bench_rb_batch(b: &mut Bencher) {
		b.iter(|| {
			const NUM_ITEMS:usize = 1000;
			let rb = Arc::new(RingBuffer::new(NUM_ITEMS));
			let num_done = Arc::new(AtomicUsize::new(0));
			let num_sent = Arc::new(AtomicUsize::new(0));
			let (tx, rx) = channel();

			for _ in 0..8 {
				let rb = rb.clone();
				let tx = tx.clone();
				let num_done = num_done.clone();
				thread::spawn(move || {
					loop {
						let result = rb.get();

						match result {
							Ok(x) => {
								num_done.fetch_add(1, Ordering::SeqCst);
								if x == NUM_ITEMS-2 {
									tx.send(()).unwrap();
								}
							},
							_ => break
						}
					}
				});
			}

			for _ in 0..8 {
				let rb = rb.clone();
				let num_sent = num_sent.clone();
				thread::spawn(move || {
					loop {
						let previous = num_sent.fetch_add(1, Ordering::SeqCst);
						if previous >= NUM_ITEMS {
							break
						}
						rb.put(previous);
					}
				});
			}

			rx.recv().unwrap();
			rb.dispose();
		});
	}

	#[bench]
	fn bench_rb_lifecycle(b: &mut Bencher) {
		let rb = Arc::new(RingBuffer::new(1));

		let rbc = rb.clone();
		let join = thread::spawn(move || {
			loop {
				let result = rbc.get();
				match result {
					Err(_) => break,
					_ => ()
				}
			}
		});

		b.iter(|| {
			let rb = rb.clone();
			rb.put(1);
		});

		rb.dispose();
		join.join();
	}

	#[bench]
	fn bench_vecdeque(b: &mut Bencher) {
		let rb = VecDeque::new();
		let arc = Arc::new(Mutex::new(rb));

		let clone = arc.clone();
		thread::spawn(move || {
			loop {
				let mut rb = clone.lock().unwrap();
				let result = rb.pop_front();
				match result {
					Some(x) => {if x == 2 { break }},
					None => ()
				}
			}
		});

		b.iter(|| {
			let mut rb = arc.lock().unwrap();
			rb.push_back(1);
		});

		let mut rb = arc.lock().unwrap();
		rb.push_back(2);
	}
}<commit_msg>Added repr(C) to ensure the padding is in the correct location in the struct.<commit_after>#![allow(dead_code)]
// Copyright 2012-2014 Dustin Hiatt. See the COPYRIGHT
// file at the top-level directory.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//
//! A statically-sized ring buffer that acts as an MPMC queue.  Differs
//! from the ring buffer-backed VecDeque in that this structure
//! is lockless and threadsafe.  Threadsafety is achieved using only
//! CAS operations, making this queue ideal for high throughput.  This
//! queue is not ideal for situations where a long wait is expected
//! as any getter is blocked in a spinlock until an item is put.  Locks
//! due to resource starvation are avoided by yielding the spin lock to
//! the scheduler every few thousand iterations.  This queue is cache-aware
//! and performs best with cache line sizes of 64 bytes.
//!
//! Because this queue is threadsafe, it is safe to pass an Arc around
//! to spawned threads and call put, without wrapping the struct itself
//! in a mutex.

//! Benchmarks:
//! test ringbuffer::rbtest::bench_rb_batch     ... bench:    443876 ns/iter (+/- 19276)
//! ringbuffer::rbtest::bench_rb_get       ... bench:        42 ns/iter (+/- 2)
//! ringbuffer::rbtest::bench_rb_lifecycle ... bench:        24 ns/iter (+/- 0)
//! ringbuffer::rbtest::bench_rb_put       ... bench:        36 ns/iter (+/- 5)
//! ringbuffer::rbtest::bench_vecdeque     ... bench:      2934 ns/iter (+/- 394)
//!
//! The final benchmark is comparable to the bench_rb_lifecycle in terms
//! of functionality.

/// #Examples
///
/// ```
/// use marble::ringbuffer::RingBuffer;
///
/// use std::sync::Arc;
/// use std::thread;
///
/// let rb = Arc::new(RingBuffer::new(1));
///
/// let rbc = rb.clone();
/// let join = thread::spawn(move || {
/// 	loop {
/// 		let result = rbc.get();
/// 		match result {
/// 			Err(_) => break,
/// 			_ => ()
///			}
///		}
/// });
///
/// rb.put(1);
/// rb.dispose();
/// join.join();
/// ```

use std::cell::UnsafeCell;
use std::default::Default;
use std::marker;
use std::sync::atomic::{ATOMIC_USIZE_INIT, AtomicUsize, Ordering};
use std::thread::yield_now;
use std::vec::Vec;

// Node will wrap items in the buffer and keep track of enough
// meta data to know if queue and dequere are referencing the
// correct item.  This is achieved through the atomic position
// field.
struct Node<T> {
	item: 	  Option<T>,
	position: AtomicUsize,
}

impl<T> Node<T> {
	// new creates a new node with its atomic position set to
	// position.  No item by default.
	fn new(position: usize) -> Node<T> {
		Node {
			position: AtomicUsize::new(position),
			item: None,
		}
	}
}

/// RingBuffer is a threadsafe MPMC queue that's statically-sized.
/// Puts are blocked on a full queue and gets are blocked on an empty
/// queue.  In either case, calling dispose will free any blocked threads
/// and return an error.
#[repr(C)]
pub struct RingBuffer<T> {
	queue: 	   AtomicUsize,
	// padding is here to ensure that queue and dequeue end on different
	// cache lines to prevent false sharing.
	_padding0: [u64;8],
	dequeue:   AtomicUsize,
	_padding1: [u64;8],
	disposed:  AtomicUsize,
	_padding2: [u64;8],
	mask:      usize,
	// positions is unsafecell so we can grab a node mutably in the
	// put and get functions, which themselves can be called on an
	// immutable ring buffer.
	positions: UnsafeCell<Vec<Node<T>>>,
}

// these implementations are required to access a ringbuffer in a separate
// lifetime and thread using only a wrapping Arc.
unsafe impl<T> marker::Send for RingBuffer<T> {}
unsafe impl<T> marker::Sync for RingBuffer<T> {}

impl<T> Default for RingBuffer<T> {
	// this is convenient so we don't have to create 0 for atomics
	// and empty arrays with every constructor call.
	fn default() -> RingBuffer<T> {
		RingBuffer{
			queue:     ATOMIC_USIZE_INIT,
			_padding0: [0;8],
			dequeue:   ATOMIC_USIZE_INIT,
			_padding1: [0;8],
			disposed:  ATOMIC_USIZE_INIT,
			_padding2: [0;8],
			mask: 	   0,
			positions: UnsafeCell::new(vec![]),
		}
	}
}

/// RingBufferError is returned when a thread gets or puts on a disposed
/// RingBuffer.  Any blocked threads will be freed and will received this
/// error.
pub enum RingBufferError { Disposed }

impl<T> RingBuffer<T> {
	/// new creates a new RingBuffer with the specified capacity.  It
	/// is important to note that capacity will be rounded up to the next
	/// power of two.  This is done to improve performance by avoiding a
	/// costly modulo call.  To get the actual capacity of the ring buffer
	/// call cap().
	pub fn new(cap: usize) -> RingBuffer<T> {
		let calculated_capacity = cap.next_power_of_two();
		let mut positions = Vec::<Node<T>>::with_capacity(calculated_capacity);

		for i in 0..calculated_capacity {
			positions.push(Node::new(i as usize));
		}

		RingBuffer{
			mask: calculated_capacity-1,
			positions: UnsafeCell::new(positions),
			..Default::default()
		}
	}

	/// cap returns the actual capacity of the ring buffer.  This
	/// different than length, which returns the actual number of
	/// items in the ring buffer.  If cap == len, then the ring
	/// buffer is full.
	pub fn cap(&self) -> usize {
		unsafe {
			let positions = self.positions.get();
			(*positions).len()
		}
	}

	/// len returns the number of items in the ring buffer at this
	/// moment.
	pub fn len(&self) -> usize {
		self.queue.load(Ordering::Relaxed) - self.dequeue.load(Ordering::Relaxed)
	}

	/// dispose frees any resources consumed by this ring buffer and
	/// releases any threads that are currently in spin locks.  Any subsequent
	/// calls to put or get will return an error.
	pub fn dispose(&self) {
		self.disposed.store(1, Ordering::Relaxed);
	}

	/// put will add item to the ring buffer.  If the ring buffer is full
	/// this operation blocks until it can be put.  Returns an error if
	/// this ring buffer is disposed.
	pub fn put(&self, item: T) -> Result<(), RingBufferError> {
		unsafe {
			let mut position = self.queue.load(Ordering::Relaxed);
			let mut i = 0;

			loop {
				if self.disposed.load(Ordering::Relaxed) == 1 {
					return Err(RingBufferError::Disposed);
				}

				let positions = self.positions.get();
				let n = (*positions).get_unchecked_mut(position&self.mask);
				let diff = n.position.load(Ordering::Acquire) - position;
				if diff == 0 {
					if self.queue.compare_and_swap(position, position+1, Ordering::Relaxed) == position {
						n.item = Some(item);
						n.position.store(position+1, Ordering::Release);
						return Ok(());
					}
				} else {
					position = self.queue.load(Ordering::Relaxed);
				}

				if i == 10000 {
					i = 0;
					yield_now();
				} else {
					i += 1;
				}
			}
		}
	}

	/// get retrieves the next item from the ring buffer.  This method blocks
	/// if the ring buffer is empty until an item is placed.  Returns an error
	/// if the ring buffer is disposed.
	pub fn get(&self) -> Result<T, RingBufferError> {
		unsafe {
			let mut position = self.dequeue.load(Ordering::Relaxed);
			let mut i = 0;
			loop {
				if self.disposed.load(Ordering::SeqCst) == 1 {
					return Err(RingBufferError::Disposed);
				}
				let positions = self.positions.get();
				let n = (*positions).get_unchecked_mut(position&self.mask);
				let diff = n.position.load(Ordering::Acquire) - (position + 1);
				if diff == 0 {
					if self.dequeue.compare_and_swap(position, position+1, Ordering::Relaxed) == position {
						let data = n.item.take().unwrap();
						n.position.store(position+self.mask+1, Ordering::Release);
						return Ok(data);
					}
				} else {
					position = self.dequeue.load(Ordering::Relaxed);
				}

				if i == 10000 {
					i = 0;
					yield_now();
				} else {
					i += 1;
				}
			}
		}
	}
}

#[cfg(test)]
#[allow(unused_must_use)]
mod rbtest {
	extern crate test;

	use self::test::Bencher;

	use std::collections::vec_deque::VecDeque;
	use std::sync::{Arc, Mutex};
	use std::sync::atomic::{AtomicUsize, Ordering};
	use std::sync::mpsc::channel;
	use std::thread;

    use super::*;

   	#[test]
	fn test_simple_put_get() {
		let rb = RingBuffer::new(10);
		let number = 5;
		rb.put(number);
		assert_eq!(1, rb.len());
		let result = rb.get();
		match result {
			Ok(x) => assert_eq!(x, 5),
			Err(x) => panic!(x)
		}
	}

	#[test]
	fn test_fill_and_empty() {
		let rb = RingBuffer::new(8);
		for i in 0..rb.cap() {
			rb.put(i);
		}

		for i in 0..rb.cap() {
			let result = rb.get();
			match result {
				Ok(x) => assert_eq!(x, i),
				Err(x) => panic!(x)
			}
		}

		assert_eq!(0, rb.len());
	}

	#[test]
	fn test_fill_and_dispose() {
		let rb = RingBuffer::new(8);
		let arb = Arc::new(rb);
		let mut vec = vec![];

		for i in 0..arb.cap()+1 {
			let trb = arb.clone();
			let join = thread::spawn(move || {
				trb.put(i);
			});

			vec.push(join);
		}

		arb.dispose();
		for j in vec {
			j.join();
		}
	}

	#[test]
	fn test_get_put_on_dispose() {
		let rb = RingBuffer::new(2);
		rb.dispose();

		let result = rb.get();
		match result {
			Ok(_) => panic!("Should return error."),
			_ => ()
		}

		let result = rb.put(3);
		match result {
			Ok(_) => panic!("Should return error."),
			_ => ()
		}
	}

	#[bench]
	fn bench_rb_put(b: &mut Bencher) {
		b.iter(|| {
			let rb = RingBuffer::new(2);
			rb.put(1);
		});
	}

	#[bench]
	fn bench_rb_get(b: &mut Bencher) {
		b.iter(|| {
			let rb = RingBuffer::new(2);
			rb.put(1);
			rb.get();
		});
	}

	#[bench]
	fn bench_rb_batch(b: &mut Bencher) {
		b.iter(|| {
			const NUM_ITEMS:usize = 1000;
			let rb = Arc::new(RingBuffer::new(NUM_ITEMS));
			let num_done = Arc::new(AtomicUsize::new(0));
			let num_sent = Arc::new(AtomicUsize::new(0));
			let (tx, rx) = channel();

			for _ in 0..8 {
				let rb = rb.clone();
				let tx = tx.clone();
				let num_done = num_done.clone();
				thread::spawn(move || {
					loop {
						let result = rb.get();

						match result {
							Ok(x) => {
								num_done.fetch_add(1, Ordering::SeqCst);
								if x == NUM_ITEMS-2 {
									tx.send(()).unwrap();
								}
							},
							_ => break
						}
					}
				});
			}

			for _ in 0..8 {
				let rb = rb.clone();
				let num_sent = num_sent.clone();
				thread::spawn(move || {
					loop {
						let previous = num_sent.fetch_add(1, Ordering::SeqCst);
						if previous >= NUM_ITEMS {
							break
						}
						rb.put(previous);
					}
				});
			}

			rx.recv().unwrap();
			rb.dispose();
		});
	}

	#[bench]
	fn bench_rb_lifecycle(b: &mut Bencher) {
		let rb = Arc::new(RingBuffer::new(1));

		let rbc = rb.clone();
		let join = thread::spawn(move || {
			loop {
				let result = rbc.get();
				match result {
					Err(_) => break,
					_ => ()
				}
			}
		});

		b.iter(|| {
			let rb = rb.clone();
			rb.put(1);
		});

		rb.dispose();
		join.join();
	}

	#[bench]
	fn bench_vecdeque(b: &mut Bencher) {
		let rb = VecDeque::new();
		let arc = Arc::new(Mutex::new(rb));

		let clone = arc.clone();
		thread::spawn(move || {
			loop {
				let mut rb = clone.lock().unwrap();
				let result = rb.pop_front();
				match result {
					Some(x) => {if x == 2 { break }},
					None => ()
				}
			}
		});

		b.iter(|| {
			let mut rb = arc.lock().unwrap();
			rb.push_back(1);
		});

		let mut rb = arc.lock().unwrap();
		rb.push_back(2);
	}
}<|endoftext|>


<commit_before>extern crate http;
extern crate nickel;
extern crate mysql;
extern crate serialize;
extern crate time;

use std::io::net::ip::Ipv4Addr;
use nickel::{
    IntoErrorHandler,
    Nickel,
};

use database::Database;

mod controllers;
mod database;
mod note;
mod settings;
mod util;

fn main() {
    // Initialize database connection.
    let database = Database::new();
    if settings::CREATE_DATABASE {
        println!("Creating database");
        match database.create() {
            Ok(_) => println!("Initialized database"),
            Err(e) => fail!("Failed to initialize database: {}", e)
        }
    }

    // Create web server.
    let mut server = Nickel::new();
    let mut router = Nickel::router();

    // Routes.
    router.get("/",      controllers::get_home);
    router.get("/:code", controllers::get_note);
    router.post("/",     controllers::post_note);

    // Middleware.
    server.utilize(Nickel::json_body_parser());
    server.utilize(router);

    // Error handling.
    server.handle_error(IntoErrorHandler::from_fn(controllers::custom_404));

    // Start web server.
    server.listen(Ipv4Addr(127, 0, 0, 1), 3000);
}
<commit_msg>Fix whitespace<commit_after>extern crate http;
extern crate nickel;
extern crate mysql;
extern crate serialize;
extern crate time;

use std::io::net::ip::Ipv4Addr;
use nickel::{
    IntoErrorHandler,
    Nickel,
};

use database::Database;

mod controllers;
mod database;
mod note;
mod settings;
mod util;

fn main() {
    // Initialize database connection.
    let database = Database::new();
    if settings::CREATE_DATABASE {
        println!("Creating database");
        match database.create() {
            Ok(_) => println!("Initialized database"),
            Err(e) => fail!("Failed to initialize database: {}", e)
        }
    }

    // Create web server.
    let mut server = Nickel::new();
    let mut router = Nickel::router();

    // Routes.
    router.get("/",      controllers::get_home);
    router.get("/:code", controllers::get_note);
    router.post("/",     controllers::post_note);

    // Middleware.
    server.utilize(Nickel::json_body_parser());
    server.utilize(router);

    // Error handling.
    server.handle_error(IntoErrorHandler::from_fn(controllers::custom_404));

    // Start web server.
    server.listen(Ipv4Addr(127, 0, 0, 1), 3000);
}
<|endoftext|>


<commit_before>#![allow(clippy::large_enum_variant)]
#![allow(dead_code)]
#![allow(deprecated)] // because of `Error::description` deprecation in `error_chain`

use std::io;
use std::path::PathBuf;

use clap::Shell;
use error_chain::error_chain;
use lazy_static::lazy_static;
use regex::Regex;
use strsim::damerau_levenshtein;

use super::rustup_mode::CompletionCommand;
use crate::dist::temp;
use crate::TOOLS;

error_chain! {
    links {
        Rustup(crate::Error, crate::ErrorKind);
    }

    foreign_links {
        Clap(clap::Error);
        Temp(temp::Error);
        Io(io::Error);
        Term(term::Error);
    }

    errors {
        InvalidCustomToolchainName(t: String) {
            display("invalid custom toolchain name: '{}'", t)
        }
        PermissionDenied {
            description("permission denied")
        }
        ToolchainNotInstalled(t: String) {
            description("toolchain is not installed")
            display("toolchain '{}' is not installed", t)
        }
        InvalidToolchainName(t: String) {
            description("invalid toolchain name")
            display("invalid toolchain name: '{}'{}", t, maybe_suggest_toolchain(t))
        }
        InfiniteRecursion {
            description("infinite recursion detected")
        }
        NoExeName {
            description("couldn't determine self executable name")
        }
        UnknownProxyName(n: String) {
            description("unknown proxy name")
            display(
                "unknown proxy name: '{}'; valid proxy names are {}",
                n,
                valid_proxy_names(),
            )
        }
        NotSelfInstalled(p: PathBuf) {
            description("rustup is not installed")
            display("rustup is not installed at '{}'", p.display())
        }
        WindowsUninstallMadness {
            description("failure during windows uninstall")
        }
        UnsupportedCompletionShell(shell: Shell, cmd: CompletionCommand) {
            description("completion script for shell not yet supported for tool")
            display("{} does not currently support completions for {}", cmd, shell)
        }
        TargetAllSpecifiedWithTargets(t: Vec<String>) {
            description(
                "the `all` target, which installs all available targets, \
                 cannot be combined with other targets"
            )
            display("`rustup target add {}` includes `all`", t.join(" "))
        }
        WritingShellProfile {
            path: PathBuf,
        } {
            description("could not amend shell profile")
            display("could not amend shell profile: '{}'", path.display())
        }
    }
}

fn valid_proxy_names() -> String {
    TOOLS
        .iter()
        .map(|s| format!("'{}'", s))
        .collect::<Vec<_>>()
        .join(", ")
}

fn maybe_suggest_toolchain(bad_name: &str) -> String {
    let bad_name = &bad_name.to_ascii_lowercase();
    static VALID_CHANNELS: &[&str] = &["stable", "beta", "nightly"];
    lazy_static! {
        static ref NUMBERED: Regex = Regex::new(r"^\d+\.\d+$").unwrap();
    }

    if NUMBERED.is_match(bad_name) {
        return format!(
            ". Toolchain numbers tend to have three parts, e.g. {}.0",
            bad_name
        );
    }

    // Suggest only for very small differences
    // High number can result in inaccurate suggestions for short queries e.g. `rls`
    const MAX_DISTANCE: usize = 3;

    let mut scored: Vec<_> = VALID_CHANNELS
        .iter()
        .filter_map(|s| {
            let distance = damerau_levenshtein(bad_name, s);
            if distance <= MAX_DISTANCE {
                Some((distance, s))
            } else {
                None
            }
        })
        .collect();
    scored.sort();
    if scored.is_empty() {
        String::new()
    } else {
        format!(". Did you mean '{}'?", scored[0].1)
    }
}
<commit_msg>Add the missing tools for valid_proxy_names<commit_after>#![allow(clippy::large_enum_variant)]
#![allow(dead_code)]
#![allow(deprecated)] // because of `Error::description` deprecation in `error_chain`

use std::io;
use std::path::PathBuf;

use clap::Shell;
use error_chain::error_chain;
use lazy_static::lazy_static;
use regex::Regex;
use strsim::damerau_levenshtein;

use super::rustup_mode::CompletionCommand;
use crate::dist::temp;
use crate::{TOOLS, DUP_TOOLS};

error_chain! {
    links {
        Rustup(crate::Error, crate::ErrorKind);
    }

    foreign_links {
        Clap(clap::Error);
        Temp(temp::Error);
        Io(io::Error);
        Term(term::Error);
    }

    errors {
        InvalidCustomToolchainName(t: String) {
            display("invalid custom toolchain name: '{}'", t)
        }
        PermissionDenied {
            description("permission denied")
        }
        ToolchainNotInstalled(t: String) {
            description("toolchain is not installed")
            display("toolchain '{}' is not installed", t)
        }
        InvalidToolchainName(t: String) {
            description("invalid toolchain name")
            display("invalid toolchain name: '{}'{}", t, maybe_suggest_toolchain(t))
        }
        InfiniteRecursion {
            description("infinite recursion detected")
        }
        NoExeName {
            description("couldn't determine self executable name")
        }
        UnknownProxyName(n: String) {
            description("unknown proxy name")
            display(
                "unknown proxy name: '{}'; valid proxy names are {}",
                n,
                valid_proxy_names(),
            )
        }
        NotSelfInstalled(p: PathBuf) {
            description("rustup is not installed")
            display("rustup is not installed at '{}'", p.display())
        }
        WindowsUninstallMadness {
            description("failure during windows uninstall")
        }
        UnsupportedCompletionShell(shell: Shell, cmd: CompletionCommand) {
            description("completion script for shell not yet supported for tool")
            display("{} does not currently support completions for {}", cmd, shell)
        }
        TargetAllSpecifiedWithTargets(t: Vec<String>) {
            description(
                "the `all` target, which installs all available targets, \
                 cannot be combined with other targets"
            )
            display("`rustup target add {}` includes `all`", t.join(" "))
        }
        WritingShellProfile {
            path: PathBuf,
        } {
            description("could not amend shell profile")
            display("could not amend shell profile: '{}'", path.display())
        }
    }
}

fn valid_proxy_names() -> String {
    TOOLS
        .iter().chain(DUP_TOOLS.iter())
        .map(|s| format!("'{}'", s))
        .collect::<Vec<_>>()
        .join(", ")
}

fn maybe_suggest_toolchain(bad_name: &str) -> String {
    let bad_name = &bad_name.to_ascii_lowercase();
    static VALID_CHANNELS: &[&str] = &["stable", "beta", "nightly"];
    lazy_static! {
        static ref NUMBERED: Regex = Regex::new(r"^\d+\.\d+$").unwrap();
    }

    if NUMBERED.is_match(bad_name) {
        return format!(
            ". Toolchain numbers tend to have three parts, e.g. {}.0",
            bad_name
        );
    }

    // Suggest only for very small differences
    // High number can result in inaccurate suggestions for short queries e.g. `rls`
    const MAX_DISTANCE: usize = 3;

    let mut scored: Vec<_> = VALID_CHANNELS
        .iter()
        .filter_map(|s| {
            let distance = damerau_levenshtein(bad_name, s);
            if distance <= MAX_DISTANCE {
                Some((distance, s))
            } else {
                None
            }
        })
        .collect();
    scored.sort();
    if scored.is_empty() {
        String::new()
    } else {
        format!(". Did you mean '{}'?", scored[0].1)
    }
}
<|endoftext|>


<commit_before>use parse_error::ParseError;
use std::{iter, slice};
use map_file::SectorState;

#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[repr(u8)]
pub enum Phase {
    Copying = b'?',
    Trimming = b'*',
    Scraping = b'/',
    Retrying = b'-',
    Filling = b'F',
    Generating = b'G',
    Finished = b'+',
}

impl Phase {
    pub fn from_char(c: char) -> Result<Phase, ParseError> {
        use self::Phase::*;
        for state in Self::values() {
            if c as u8 == state as u8 {
                return Ok(state.clone())
            }
        }
        Err(ParseError::new("phase"))
    }

    pub fn as_char(&self) -> char {
        *self as u8 as char
    }

    fn values() -> iter::Cloned<slice::Iter<'static, Phase>> {
        use self::Phase::*;
        static PHASES: [Phase; 5] = [Copying, Trimming, Scraping, Retrying, Finished];
        PHASES.iter().cloned()
    }

    pub fn next(&self) -> Option<Self> {
        use self::Phase::*;
        match *self {
            Copying => Some(Trimming),
            Trimming => Some(Scraping),
            Scraping => Some(Retrying),
            Retrying => Some(Finished),
            Filling => None,
            Generating => None,
            Finished => None,
        }

    }

    pub fn target_sectors(&self) -> Option<SectorState> {
        use self::Phase::*;
        match *self {
            Copying => Some(SectorState::Untried),
            Trimming => Some(SectorState::Untrimmed),
            Scraping => Some(SectorState::Unscraped),
            Retrying => Some(SectorState::Bad),
            Filling => None,
            Generating => None,
            Finished => None,
        }
    }

    pub fn name(&self) -> String {
        format!("{:?}", self)
    }
}
<commit_msg>Fix warning about unused import.<commit_after>use map_file::SectorState;
use parse_error::ParseError;
use phase::Phase::*;
use std::{iter, slice};

#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[repr(u8)]
pub enum Phase {
    Copying = b'?',
    Trimming = b'*',
    Scraping = b'/',
    Retrying = b'-',
    Filling = b'F',
    Generating = b'G',
    Finished = b'+',
}

static PHASES: [Phase; 5] = [Copying, Trimming, Scraping, Retrying, Finished];

impl Phase {
    pub fn from_char(c: char) -> Result<Phase, ParseError> {
        for state in Self::values() {
            if c as u8 == state as u8 {
                return Ok(state.clone())
            }
        }
        Err(ParseError::new("phase"))
    }

    pub fn as_char(&self) -> char {
        *self as u8 as char
    }

    fn values() -> iter::Cloned<slice::Iter<'static, Phase>> {
        PHASES.iter().cloned()
    }

    pub fn next(&self) -> Option<Self> {
        match *self {
            Copying => Some(Trimming),
            Trimming => Some(Scraping),
            Scraping => Some(Retrying),
            Retrying => Some(Finished),
            Filling => None,
            Generating => None,
            Finished => None,
        }

    }

    pub fn target_sectors(&self) -> Option<SectorState> {
        match *self {
            Copying => Some(SectorState::Untried),
            Trimming => Some(SectorState::Untrimmed),
            Scraping => Some(SectorState::Unscraped),
            Retrying => Some(SectorState::Bad),
            Filling => None,
            Generating => None,
            Finished => None,
        }
    }

    pub fn name(&self) -> String {
        format!("{:?}", self)
    }
}
<|endoftext|>