<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

#[macro_use]
extern crate log;
extern crate osmpbfreader;
extern crate rustc_serialize;
extern crate docopt;
extern crate mimir;
extern crate rs_es;

use std::collections::HashSet;
use std::collections::HashMap;
use mimirsbrunn::rubber::Rubber;
use mimirsbrunn::objects::{Polygon, MultiPolygon};

pub type AdminsVec = Vec<mimir::Admin>;
pub type StreetsVec = Vec<mimir::Street>;
pub type ParsedPbf = osmpbfreader::OsmPbfReader<std::fs::File>;

#[derive(RustcDecodable, Debug)]
struct Args {
    flag_input: String,
    flag_level: Vec<u32>,
    flag_connection_string: String,
    flag_import_way: bool,
}

static USAGE: &'static str = "
Usage:
    osm2mimir --help
    osm2mimir --input=<file> [--connection-string=<connection-string>] --level=<level> ... [--import-way]

Options:
    -h, --help            Show this message.
    -i, --input=<file>    OSM PBF file.
    -l, --level=<level>   Admin levels to keep.
    -w, --import-way      By default, streets are not imported
    -c, --connection-string=<connection-string>
                          Elasticsearch parameters, [default: http://localhost:9200/munin]
";

#[derive(Debug)]
struct AdminMatcher {
    admin_levels: HashSet<u32>,
}
impl AdminMatcher {
    pub fn new(levels: HashSet<u32>) -> AdminMatcher {
        AdminMatcher { admin_levels: levels }
    }

    pub fn is_admin(&self, obj: &osmpbfreader::OsmObj) -> bool {
        match *obj {
            osmpbfreader::OsmObj::Relation(ref rel) => {
                rel.tags.get("boundary").map_or(false, |v| v == "administrative") &&
                rel.tags.get("admin_level").map_or(false, |lvl| {
                    self.admin_levels.contains(&lvl.parse::<u32>().unwrap_or(0))
                })
            }
            _ => false,
        }
    }
}

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()
}

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 = 0;
        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)
    }
}

fn parse_osm_pbf(path: &str) -> ParsedPbf {
    let path = std::path::Path::new(&path);
    osmpbfreader::OsmPbfReader::new(std::fs::File::open(&path).unwrap())
}

fn administrative_regions(pbf: &mut ParsedPbf, levels: HashSet<u32>) -> AdminsVec {
    let mut administrative_regions = AdminsVec::new();
    let matcher = AdminMatcher::new(levels);
    let objects = osmpbfreader::get_objs_and_deps(pbf, |o| matcher.is_admin(o)).unwrap();
    // load administratives regions
    for (_, obj) in &objects {
        if !matcher.is_admin(&obj) {
            continue;
        }
        if let &osmpbfreader::OsmObj::Relation(ref relation) = obj {
            let level = relation.tags
                                .get("admin_level")
                                .and_then(|s| s.parse().ok());
            let level = match level {
                None => {
                    info!("invalid admin_level for relation {}: admin_level {:?}",
                          relation.id,
                          relation.tags.get("admin_level"));
                    continue;
                }
                Some(l) => l,
            };
            // administrative region with name ?
            let name = match relation.tags.get("name") {
                Some(val) => val,
                None => {
                    warn!("adminstrative region without name for relation {}:  admin_level {} \
                           ignored.",
                          relation.id,
                          level);
                    continue;
                }
            };
            // admininstrative region without coordinates
            let coord_centre = relation.refs
                                       .iter()
                                       .find(|rf| rf.role == "admin_centre")
                                       .and_then(|r| {
                                           objects.get(&r.member).and_then(|value| {
                                               match value {
                                                   &osmpbfreader::OsmObj::Node(ref node) => {
                                                       Some(mimir::Coord {
                                                           lat: node.lat,
                                                           lon: node.lon,
                                                       })
                                                   }
                                                   _ => None,
                                               }
                                           })
                                       });

            let admin_id = match relation.tags.get("ref:INSEE") {
                Some(val) => format!("admin:fr:{}", val.trim_left_matches('0')),
                None => format!("admin:osm:{}", relation.id),
            };
            let zip_code = match relation.tags.get("addr:postcode") {
                Some(val) => &val[..],
                None => "",
            };
            let boundary = build_boundary(&relation, &objects);
            let admin = mimir::Admin {
                id: admin_id,
                level: level,
                name: name.to_string(),
                zip_code: zip_code.to_string(),
                // TODO weight value ?
                weight: 1,
                coord: coord_centre,
                boundary: boundary,
            };
            administrative_regions.push(admin);
        }
    }
    return administrative_regions;
}

fn streets(pbf: &mut ParsedPbf) -> StreetsVec {

    let is_valid_obj = |obj: &osmpbfreader::OsmObj| -> bool {
        match *obj {
            osmpbfreader::OsmObj::Way(ref way) => {
                way.tags.get("highway").map_or(false, |x| !x.is_empty()) &&
                way.tags.get("name").map_or(false, |x| !x.is_empty())
            }
            osmpbfreader::OsmObj::Relation(ref rel) => {
                rel.tags.get("type").map_or(false, |v| v == "associatedStreet")
            }
            _ => false,
        }
    };

    let mut objs_map = osmpbfreader::get_objs_and_deps(pbf, is_valid_obj).unwrap();
    // Sometimes, streets can be devided into several "way"s that still have the same street name.
    // The reason why a street is devided may be that a part of the street become a bridge/tunne/etc.
    // In this case, a "relation" tagged with (type = associatedStreet) is used to group all these "way"s.
    // In order not to have doublons in autocompleion, we should keep only one "way" in the relation
    // and remove all the rest way whose street name is the same.
    let mut objs_to_remove = Vec::<osmpbfreader::OsmId>::new();

    for (_, rel_obj) in &objs_map {
        if let &osmpbfreader::OsmObj::Relation(ref rel) = rel_obj {
            let mut found = false;
            for ref_obj in &rel.refs {
                if let &osmpbfreader::OsmId::Way(_) = &ref_obj.member {
                    if !found {
                        found = true;
                        continue;
                    }
                    objs_to_remove.push(ref_obj.member.clone());
                };
            }
        };
    }

    for osm_id in objs_to_remove {
        objs_map.remove(&osm_id);
    }

    objs_map.iter()
            .filter_map(|(_, obj)| {
                if let &osmpbfreader::OsmObj::Way(ref way) = obj {
                    way.tags.get("name").and_then(|way_name| {
                        Some(mimirsbrunn::Street {
                            id: way.id.to_string(),
                            street_name: way_name.to_string(),
                            name: way_name.to_string(),
                            weight: 1,
                            administrative_region: None,
                        })
                    })
                } else {
                    None
                }
            })
            .collect()

}
// TODO: template these two functions
fn index_admin(es_cnx_string: &str, admins: AdminsVec) {
    let mut rubber = Rubber::new(es_cnx_string);
    match rubber.clean_db_by_doc_type(&["admin"]) {
        Err(e) => panic!("failed to clean data for admin: {}", e),
        Ok(nb) => info!("Nb of cleaned indexed admins: {}", nb),
    }
    match rubber.bulk_index(admins.iter()) {
        Err(e) => panic!("failed to index admins of osm because: {}", e),
        Ok(nb) => info!("Nb of indexed adminstrative regions: {}", nb),
    }
}

fn index_ways(es_cnx_string: &str, streets: StreetsVec) {
    let mut rubber = Rubber::new(es_cnx_string);
    match rubber.clean_db_by_doc_type(&["street"]) {
        Err(e) => panic!("failed to clean data for street: {}", e),
        Ok(nb) => info!("Nb of cleaned indexed streets: {}", nb),
    }
    match rubber.bulk_index(streets.iter()) {
        Err(e) => panic!("failed to index streets of osm because: {}", e),
        Ok(nb) => info!("Nb of indexed street: {}", nb),
    }
}

fn index_settings(es_cnx_string: &str) {
    let mut rubber = Rubber::new(es_cnx_string);
    rubber.create_index();
}

fn main() {
    mimir::logger_init().unwrap();
    debug!("importing adminstrative region into Mimir");
    let args: Args = docopt::Docopt::new(USAGE)
                         .and_then(|d| d.decode())
                         .unwrap_or_else(|e| e.exit());

    let levels = args.flag_level.iter().cloned().collect();
    let mut parsed_pbf = parse_osm_pbf(&args.flag_input);

    let admins = administrative_regions(&mut parsed_pbf, levels);

    index_settings(&args.flag_connection_string);
    index_admin(&args.flag_connection_string, admins);

    let mut optinoal_streets: Option<StreetsVec> = None;
    if args.flag_import_way {
        optinoal_streets = Some(streets(&mut parsed_pbf));
    }

    if let Some(streets) = optinoal_streets {
        index_ways(&args.flag_connection_string, streets);
    }
}
<commit_msg>rename type<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

#[macro_use]
extern crate log;
extern crate osmpbfreader;
extern crate rustc_serialize;
extern crate docopt;
extern crate mimir;
extern crate rs_es;

use std::collections::HashSet;
use std::collections::HashMap;
use mimirsbrunn::rubber::Rubber;
use mimirsbrunn::objects::{Polygon, MultiPolygon};

pub type AdminsVec = Vec<mimir::Admin>;
pub type StreetsVec = Vec<mimir::Street>;
pub type OsmPbfReader = osmpbfreader::OsmPbfReader<std::fs::File>;

#[derive(RustcDecodable, Debug)]
struct Args {
    flag_input: String,
    flag_level: Vec<u32>,
    flag_connection_string: String,
    flag_import_way: bool,
}

static USAGE: &'static str = "
Usage:
    osm2mimir --help
    osm2mimir --input=<file> [--connection-string=<connection-string>] --level=<level> ... [--import-way]

Options:
    -h, --help            Show this message.
    -i, --input=<file>    OSM PBF file.
    -l, --level=<level>   Admin levels to keep.
    -w, --import-way      By default, streets are not imported
    -c, --connection-string=<connection-string>
                          Elasticsearch parameters, [default: http://localhost:9200/munin]
";

#[derive(Debug)]
struct AdminMatcher {
    admin_levels: HashSet<u32>,
}
impl AdminMatcher {
    pub fn new(levels: HashSet<u32>) -> AdminMatcher {
        AdminMatcher { admin_levels: levels }
    }

    pub fn is_admin(&self, obj: &osmpbfreader::OsmObj) -> bool {
        match *obj {
            osmpbfreader::OsmObj::Relation(ref rel) => {
                rel.tags.get("boundary").map_or(false, |v| v == "administrative") &&
                rel.tags.get("admin_level").map_or(false, |lvl| {
                    self.admin_levels.contains(&lvl.parse::<u32>().unwrap_or(0))
                })
            }
            _ => false,
        }
    }
}

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()
}

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 = 0;
        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)
    }
}

fn parse_osm_pbf(path: &str) -> OsmPbfReader {
    let path = std::path::Path::new(&path);
    osmpbfreader::OsmPbfReader::new(std::fs::File::open(&path).unwrap())
}

fn administrative_regions(pbf: &mut OsmPbfReader, levels: HashSet<u32>) -> AdminsVec {
    let mut administrative_regions = AdminsVec::new();
    let matcher = AdminMatcher::new(levels);
    let objects = osmpbfreader::get_objs_and_deps(pbf, |o| matcher.is_admin(o)).unwrap();
    // load administratives regions
    for (_, obj) in &objects {
        if !matcher.is_admin(&obj) {
            continue;
        }
        if let &osmpbfreader::OsmObj::Relation(ref relation) = obj {
            let level = relation.tags
                                .get("admin_level")
                                .and_then(|s| s.parse().ok());
            let level = match level {
                None => {
                    info!("invalid admin_level for relation {}: admin_level {:?}",
                          relation.id,
                          relation.tags.get("admin_level"));
                    continue;
                }
                Some(l) => l,
            };
            // administrative region with name ?
            let name = match relation.tags.get("name") {
                Some(val) => val,
                None => {
                    warn!("adminstrative region without name for relation {}:  admin_level {} \
                           ignored.",
                          relation.id,
                          level);
                    continue;
                }
            };
            // admininstrative region without coordinates
            let coord_centre = relation.refs
                                       .iter()
                                       .find(|rf| rf.role == "admin_centre")
                                       .and_then(|r| {
                                           objects.get(&r.member).and_then(|value| {
                                               match value {
                                                   &osmpbfreader::OsmObj::Node(ref node) => {
                                                       Some(mimir::Coord {
                                                           lat: node.lat,
                                                           lon: node.lon,
                                                       })
                                                   }
                                                   _ => None,
                                               }
                                           })
                                       });

            let admin_id = match relation.tags.get("ref:INSEE") {
                Some(val) => format!("admin:fr:{}", val.trim_left_matches('0')),
                None => format!("admin:osm:{}", relation.id),
            };
            let zip_code = match relation.tags.get("addr:postcode") {
                Some(val) => &val[..],
                None => "",
            };
            let boundary = build_boundary(&relation, &objects);
            let admin = mimir::Admin {
                id: admin_id,
                level: level,
                name: name.to_string(),
                zip_code: zip_code.to_string(),
                // TODO weight value ?
                weight: 1,
                coord: coord_centre,
                boundary: boundary,
            };
            administrative_regions.push(admin);
        }
    }
    return administrative_regions;
}

fn streets(pbf: &mut OsmPbfReader) -> StreetsVec {

    let is_valid_obj = |obj: &osmpbfreader::OsmObj| -> bool {
        match *obj {
            osmpbfreader::OsmObj::Way(ref way) => {
                way.tags.get("highway").map_or(false, |x| !x.is_empty()) &&
                way.tags.get("name").map_or(false, |x| !x.is_empty())
            }
            osmpbfreader::OsmObj::Relation(ref rel) => {
                rel.tags.get("type").map_or(false, |v| v == "associatedStreet")
            }
            _ => false,
        }
    };

    let mut objs_map = osmpbfreader::get_objs_and_deps(pbf, is_valid_obj).unwrap();
    // Sometimes, streets can be devided into several "way"s that still have the same street name.
    // The reason why a street is devided may be that a part of the street become a bridge/tunne/etc.
    // In this case, a "relation" tagged with (type = associatedStreet) is used to group all these "way"s.
    // In order not to have doublons in autocompleion, we should keep only one "way" in the relation
    // and remove all the rest way whose street name is the same.
    let mut objs_to_remove = Vec::<osmpbfreader::OsmId>::new();

    for (_, rel_obj) in &objs_map {
        if let &osmpbfreader::OsmObj::Relation(ref rel) = rel_obj {
            let mut found = false;
            for ref_obj in &rel.refs {
                if let &osmpbfreader::OsmId::Way(_) = &ref_obj.member {
                    if !found {
                        found = true;
                        continue;
                    }
                    objs_to_remove.push(ref_obj.member.clone());
                };
            }
        };
    }

    for osm_id in objs_to_remove {
        objs_map.remove(&osm_id);
    }

    objs_map.iter()
            .filter_map(|(_, obj)| {
                if let &osmpbfreader::OsmObj::Way(ref way) = obj {
                    way.tags.get("name").and_then(|way_name| {
                        Some(mimirsbrunn::Street {
                            id: way.id.to_string(),
                            street_name: way_name.to_string(),
                            name: way_name.to_string(),
                            weight: 1,
                            administrative_region: None,
                        })
                    })
                } else {
                    None
                }
            })
            .collect()

}
// TODO: template these two functions
fn index_admin(es_cnx_string: &str, admins: AdminsVec) {
    let mut rubber = Rubber::new(es_cnx_string);
    match rubber.clean_db_by_doc_type(&["admin"]) {
        Err(e) => panic!("failed to clean data for admin: {}", e),
        Ok(nb) => info!("Nb of cleaned indexed admins: {}", nb),
    }
    match rubber.bulk_index(admins.iter()) {
        Err(e) => panic!("failed to index admins of osm because: {}", e),
        Ok(nb) => info!("Nb of indexed adminstrative regions: {}", nb),
    }
}

fn index_ways(es_cnx_string: &str, streets: StreetsVec) {
    let mut rubber = Rubber::new(es_cnx_string);
    match rubber.clean_db_by_doc_type(&["street"]) {
        Err(e) => panic!("failed to clean data for street: {}", e),
        Ok(nb) => info!("Nb of cleaned indexed streets: {}", nb),
    }
    match rubber.bulk_index(streets.iter()) {
        Err(e) => panic!("failed to index streets of osm because: {}", e),
        Ok(nb) => info!("Nb of indexed street: {}", nb),
    }
}

fn index_settings(es_cnx_string: &str) {
    let mut rubber = Rubber::new(es_cnx_string);
    rubber.create_index();
}

fn main() {
    mimir::logger_init().unwrap();
    debug!("importing adminstrative region into Mimir");
    let args: Args = docopt::Docopt::new(USAGE)
                         .and_then(|d| d.decode())
                         .unwrap_or_else(|e| e.exit());

    let levels = args.flag_level.iter().cloned().collect();
    let mut parsed_pbf = parse_osm_pbf(&args.flag_input);

    let admins = administrative_regions(&mut parsed_pbf, levels);

    index_settings(&args.flag_connection_string);
    index_admin(&args.flag_connection_string, admins);

    let mut optinoal_streets: Option<StreetsVec> = None;
    if args.flag_import_way {
        optinoal_streets = Some(streets(&mut parsed_pbf));
    }

    if let Some(streets) = optinoal_streets {
        index_ways(&args.flag_connection_string, streets);
    }
}
<|endoftext|>


<commit_before>use std::f64;

use deflate::calculate_block_size_auto_type;
use lz77::{Lz77Store, ZopfliBlockState};
use Options;

/// Finds minimum of function `f(i)` where `i` is of type `usize`, `f(i)` is of type
/// `f64`, `i` is in range `start-end` (excluding `end`).
/// Returns the index to the minimum and the minimum value.
fn find_minimum<F>(f: F, start: usize, end: usize) -> (usize, f64)
    where F: Fn(usize) -> f64
{
    let mut start = start;
    let mut end = end;
    if end - start < 1024 {
        let mut best = f64::MAX;
        let mut result = start;
        for i in start..end {
            let v = f(i);
            if v < best {
                best = v;
                result = i;
            }
        }
        (result, best)
    } else {
        /* Try to find minimum faster by recursively checking multiple points. */
        let num = 9;  /* Good value: 9. ?!?!?!?! */
        let mut p = vec![0; num];
        let mut vp = vec![0.0; num];
        let mut besti;
        let mut best;
        let mut lastbest = f64::MAX;
        let mut pos = start;

        while end - start > num {
            for i in 0..num {
                p[i] = start + (i + 1) * ((end - start) / (num + 1));
                vp[i] = f(p[i]);
            }

            besti = 0;
            best = vp[0];

            for (i, &item) in vp.iter().enumerate().take(num).skip(1) {
                if item < best {
                  best = item;
                  besti = i;
                }
            }
            if best > lastbest {
                break;
            }

            start = if besti == 0 { start } else { p[besti - 1] };
            end = if besti == num - 1 { end } else { p[besti + 1] };

            pos = p[besti];
            lastbest = best;
        }
        (pos, lastbest)
    }
}

/// Returns estimated cost of a block in bits.  It includes the size to encode the
/// tree and the size to encode all literal, length and distance symbols and their
/// extra bits.
///
/// litlens: lz77 lit/lengths
/// dists: ll77 distances
/// lstart: start of block
/// lend: end of block (not inclusive)
fn estimate_cost(lz77: &Lz77Store, lstart: usize, lend: usize) -> f64 {
    calculate_block_size_auto_type(lz77, lstart, lend)
}

/// Finds next block to try to split, the largest of the available ones.
/// The largest is chosen to make sure that if only a limited amount of blocks is
/// requested, their sizes are spread evenly.
/// lz77size: the size of the LL77 data, which is the size of the done array here.
/// done: array indicating which blocks starting at that position are no longer
///     splittable (splitting them increases rather than decreases cost).
/// splitpoints: the splitpoints found so far.
/// npoints: the amount of splitpoints found so far.
/// lstart: output variable, giving start of block.
/// lend: output variable, giving end of block.
/// returns 1 if a block was found, 0 if no block found (all are done).
fn find_largest_splittable_block(lz77size: usize, done: &[u8], splitpoints: &[usize]) -> Option<(usize, usize)> {
    let mut longest = 0;
    let mut found = None;

    let mut last = 0;

    for &item in splitpoints.iter() {
        if done[last] == 0 && item - last > longest {
            found = Some((last, item));
            longest = item - last;
        }
        last = item;
    }

    let end = lz77size - 1;
    if done[last] == 0 && end - last > longest {
        found = Some((last, end));
    }

    found
}

/// Prints the block split points as decimal and hex values in the terminal.
fn print_block_split_points(lz77: &Lz77Store, lz77splitpoints: &[usize]) {
    let nlz77points = lz77splitpoints.len();
    let mut splitpoints = Vec::with_capacity(nlz77points);

    /* The input is given as lz77 indices, but we want to see the uncompressed
    index values. */
    let mut pos = 0;
    if nlz77points > 0 {
        for (i, item) in lz77.litlens.iter().enumerate() {
            let length = item.size();
            if lz77splitpoints[splitpoints.len()] == i {
                splitpoints.push(pos);
                if splitpoints.len() == nlz77points {
                    break;
                }
            }
            pos += length;
        }
    }
    assert!(splitpoints.len() == nlz77points);

    println!("block split points: {} (hex: {})", splitpoints.iter().map(|&sp| format!("{}", sp)).collect::<Vec<_>>().join(" "), splitpoints.iter().map(|&sp| format!("{:x}", sp)).collect::<Vec<_>>().join(" "));
}

/// Does blocksplitting on LZ77 data.
/// The output splitpoints are indices in the LZ77 data.
/// maxblocks: set a limit to the amount of blocks. Set to 0 to mean no limit.
pub fn blocksplit_lz77(options: &Options, lz77: &Lz77Store, maxblocks: usize, splitpoints: &mut Vec<usize>) {
    if lz77.size() < 10 {
        return;  /* This code fails on tiny files. */
    }

    let mut numblocks = 1;
    let mut done = vec![0; lz77.size()];
    let mut lstart = 0;
    let mut lend = lz77.size();

    while maxblocks != 0 && numblocks < maxblocks {
        assert!(lstart < lend);
        let find_minimum_result = find_minimum(|i|
            estimate_cost(lz77, lstart, i) + estimate_cost(lz77, i, lend), lstart + 1, lend
        );
        let llpos = find_minimum_result.0;
        let splitcost = find_minimum_result.1;

        assert!(llpos > lstart);
        assert!(llpos < lend);

        let origcost = estimate_cost(lz77, lstart, lend);

        if splitcost > origcost || llpos == lstart + 1 || llpos == lend {
            done[lstart] = 1;
        } else {
            splitpoints.push(llpos);
            splitpoints.sort();
            numblocks += 1;
        }

        // If `find_largest_splittable_block` returns `None`, no further split will
        // likely reduce compression.
        let is_finished = find_largest_splittable_block(lz77.size(), &done, splitpoints)
            .map_or(true, |(start, end)| {
                lstart = start;
                lend = end;
                lend - lstart < 10
            });

        if is_finished { break }
    }

    if options.verbose {
        print_block_split_points(lz77, splitpoints);
    }
}

/// Does blocksplitting on uncompressed data.
/// The output splitpoints are indices in the uncompressed bytes.
///
/// options: general program options.
/// in: uncompressed input data
/// instart: where to start splitting
/// inend: where to end splitting (not inclusive)
/// maxblocks: maximum amount of blocks to split into, or 0 for no limit
/// splitpoints: dynamic array to put the resulting split point coordinates into.
///   The coordinates are indices in the input array.
/// npoints: pointer to amount of splitpoints, for the dynamic array. The amount of
///   blocks is the amount of splitpoitns + 1.
pub fn blocksplit(options: &Options, in_data: &[u8], instart: usize, inend: usize, maxblocks: usize, splitpoints: &mut Vec<usize>) {
    splitpoints.clear();
    let mut store = Lz77Store::new();

    /* Unintuitively, Using a simple LZ77 method here instead of lz77_optimal
    results in better blocks. */
    {
        let mut state = ZopfliBlockState::new_without_cache(options, instart, inend);
        store.greedy(&mut state, in_data, instart, inend);
    }

    let mut lz77splitpoints = Vec::with_capacity(maxblocks);
    blocksplit_lz77(options, &store, maxblocks, &mut lz77splitpoints);

    let nlz77points = lz77splitpoints.len();

    /* Convert LZ77 positions to positions in the uncompressed input. */
    let mut pos = instart;
    if nlz77points > 0 {
        for (i, item) in store.litlens.iter().enumerate() {
            let length = item.size();
            if lz77splitpoints[splitpoints.len()] == i {
                splitpoints.push(pos);
                if splitpoints.len() == nlz77points {
                    break;
                }
            }
            pos += length;
        }
    }
    assert!(splitpoints.len() == nlz77points);
}
<commit_msg>Calculate results and min at the same time<commit_after>use std::f64;

use deflate::calculate_block_size_auto_type;
use lz77::{Lz77Store, ZopfliBlockState};
use Options;

/// Finds minimum of function `f(i)` where `i` is of type `usize`, `f(i)` is of type
/// `f64`, `i` is in range `start-end` (excluding `end`).
/// Returns the index to the minimum and the minimum value.
fn find_minimum<F>(f: F, start: usize, end: usize) -> (usize, f64)
    where F: Fn(usize) -> f64
{
    let mut start = start;
    let mut end = end;
    if end - start < 1024 {
        let mut best = f64::MAX;
        let mut result = start;
        for i in start..end {
            let v = f(i);
            if v < best {
                best = v;
                result = i;
            }
        }
        (result, best)
    } else {
        /* Try to find minimum faster by recursively checking multiple points. */
        let num = 9;  /* Good value: 9. ?!?!?!?! */
        let mut p = vec![0; num];
        let mut vp = vec![0.0; num];
        let mut lastbest = f64::MAX;
        let mut pos = start;

        while end - start > num {
            let mut besti = 0;
            let mut best = f64::MAX;
            for i in 0..num {
                p[i] = start + (i + 1) * ((end - start) / (num + 1));
                vp[i] = f(p[i]);
                if vp[i] < best {
                    best = vp[i];
                    besti = i;
                }
            }
            if best > lastbest {
                break;
            }

            start = if besti == 0 { start } else { p[besti - 1] };
            end = if besti == num - 1 { end } else { p[besti + 1] };

            pos = p[besti];
            lastbest = best;
        }
        (pos, lastbest)
    }
}

/// Returns estimated cost of a block in bits.  It includes the size to encode the
/// tree and the size to encode all literal, length and distance symbols and their
/// extra bits.
///
/// litlens: lz77 lit/lengths
/// dists: ll77 distances
/// lstart: start of block
/// lend: end of block (not inclusive)
fn estimate_cost(lz77: &Lz77Store, lstart: usize, lend: usize) -> f64 {
    calculate_block_size_auto_type(lz77, lstart, lend)
}

/// Finds next block to try to split, the largest of the available ones.
/// The largest is chosen to make sure that if only a limited amount of blocks is
/// requested, their sizes are spread evenly.
/// lz77size: the size of the LL77 data, which is the size of the done array here.
/// done: array indicating which blocks starting at that position are no longer
///     splittable (splitting them increases rather than decreases cost).
/// splitpoints: the splitpoints found so far.
/// npoints: the amount of splitpoints found so far.
/// lstart: output variable, giving start of block.
/// lend: output variable, giving end of block.
/// returns 1 if a block was found, 0 if no block found (all are done).
fn find_largest_splittable_block(lz77size: usize, done: &[u8], splitpoints: &[usize]) -> Option<(usize, usize)> {
    let mut longest = 0;
    let mut found = None;

    let mut last = 0;

    for &item in splitpoints.iter() {
        if done[last] == 0 && item - last > longest {
            found = Some((last, item));
            longest = item - last;
        }
        last = item;
    }

    let end = lz77size - 1;
    if done[last] == 0 && end - last > longest {
        found = Some((last, end));
    }

    found
}

/// Prints the block split points as decimal and hex values in the terminal.
fn print_block_split_points(lz77: &Lz77Store, lz77splitpoints: &[usize]) {
    let nlz77points = lz77splitpoints.len();
    let mut splitpoints = Vec::with_capacity(nlz77points);

    /* The input is given as lz77 indices, but we want to see the uncompressed
    index values. */
    let mut pos = 0;
    if nlz77points > 0 {
        for (i, item) in lz77.litlens.iter().enumerate() {
            let length = item.size();
            if lz77splitpoints[splitpoints.len()] == i {
                splitpoints.push(pos);
                if splitpoints.len() == nlz77points {
                    break;
                }
            }
            pos += length;
        }
    }
    assert!(splitpoints.len() == nlz77points);

    println!("block split points: {} (hex: {})", splitpoints.iter().map(|&sp| format!("{}", sp)).collect::<Vec<_>>().join(" "), splitpoints.iter().map(|&sp| format!("{:x}", sp)).collect::<Vec<_>>().join(" "));
}

/// Does blocksplitting on LZ77 data.
/// The output splitpoints are indices in the LZ77 data.
/// maxblocks: set a limit to the amount of blocks. Set to 0 to mean no limit.
pub fn blocksplit_lz77(options: &Options, lz77: &Lz77Store, maxblocks: usize, splitpoints: &mut Vec<usize>) {
    if lz77.size() < 10 {
        return;  /* This code fails on tiny files. */
    }

    let mut numblocks = 1;
    let mut done = vec![0; lz77.size()];
    let mut lstart = 0;
    let mut lend = lz77.size();

    while maxblocks != 0 && numblocks < maxblocks {
        assert!(lstart < lend);
        let find_minimum_result = find_minimum(|i|
            estimate_cost(lz77, lstart, i) + estimate_cost(lz77, i, lend), lstart + 1, lend
        );
        let llpos = find_minimum_result.0;
        let splitcost = find_minimum_result.1;

        assert!(llpos > lstart);
        assert!(llpos < lend);

        let origcost = estimate_cost(lz77, lstart, lend);

        if splitcost > origcost || llpos == lstart + 1 || llpos == lend {
            done[lstart] = 1;
        } else {
            splitpoints.push(llpos);
            splitpoints.sort();
            numblocks += 1;
        }

        // If `find_largest_splittable_block` returns `None`, no further split will
        // likely reduce compression.
        let is_finished = find_largest_splittable_block(lz77.size(), &done, splitpoints)
            .map_or(true, |(start, end)| {
                lstart = start;
                lend = end;
                lend - lstart < 10
            });

        if is_finished { break }
    }

    if options.verbose {
        print_block_split_points(lz77, splitpoints);
    }
}

/// Does blocksplitting on uncompressed data.
/// The output splitpoints are indices in the uncompressed bytes.
///
/// options: general program options.
/// in: uncompressed input data
/// instart: where to start splitting
/// inend: where to end splitting (not inclusive)
/// maxblocks: maximum amount of blocks to split into, or 0 for no limit
/// splitpoints: dynamic array to put the resulting split point coordinates into.
///   The coordinates are indices in the input array.
/// npoints: pointer to amount of splitpoints, for the dynamic array. The amount of
///   blocks is the amount of splitpoitns + 1.
pub fn blocksplit(options: &Options, in_data: &[u8], instart: usize, inend: usize, maxblocks: usize, splitpoints: &mut Vec<usize>) {
    splitpoints.clear();
    let mut store = Lz77Store::new();

    /* Unintuitively, Using a simple LZ77 method here instead of lz77_optimal
    results in better blocks. */
    {
        let mut state = ZopfliBlockState::new_without_cache(options, instart, inend);
        store.greedy(&mut state, in_data, instart, inend);
    }

    let mut lz77splitpoints = Vec::with_capacity(maxblocks);
    blocksplit_lz77(options, &store, maxblocks, &mut lz77splitpoints);

    let nlz77points = lz77splitpoints.len();

    /* Convert LZ77 positions to positions in the uncompressed input. */
    let mut pos = instart;
    if nlz77points > 0 {
        for (i, item) in store.litlens.iter().enumerate() {
            let length = item.size();
            if lz77splitpoints[splitpoints.len()] == i {
                splitpoints.push(pos);
                if splitpoints.len() == nlz77points {
                    break;
                }
            }
            pos += length;
        }
    }
    assert!(splitpoints.len() == nlz77points);
}
<|endoftext|>


<commit_before>use std::old_io::{File, Open, Read, Write};
use std::old_io::IoError;
use std::old_io::IoResult;
use super::GapBuffer;
use super::gap_buffer;
use super::Position;
use super::Range;

pub struct Buffer {
    data: GapBuffer,
    pub path: Option<Path>,
    pub cursor: Position,
}

impl Buffer {
    /// Returns the contents of the buffer as a string.
    ///
    /// # Examples
    ///
    /// ```
    /// let mut buffer = scribe::buffer::new();
    /// buffer.insert("scribe");
    /// assert_eq!(buffer.data(), "scribe");
    /// ```
    pub fn data(&self) -> String {
        self.data.to_string()
    }

    /// Writes the contents of the buffer to its path.
    ///
    /// # Examples
    ///
    /// ```
    /// # use std::old_io::{File, Open, Read};
    ///
    /// // Set up a buffer and point it to a path.
    /// let mut buffer = scribe::buffer::new();
    /// let write_path = Path::new("my_doc");
    /// buffer.path = Some(write_path.clone());
    ///
    /// // Put some data into the buffer and save it.
    /// buffer.insert("scribe");
    /// buffer.save();
    ///
    /// # let saved_data = File::open_mode(&write_path, Open, Read)
    /// #   .unwrap().read_to_string().unwrap();
    /// # assert_eq!(saved_data, "scribe");
    ///
    /// # std::old_io::fs::unlink(&write_path);
    /// ```
    pub fn save(&self) -> Option<IoError> {
        let path = match self.path.clone() {
            Some(p) => p,
            None => Path::new(""),
        };

        // Try to open and write to the file, returning any errors encountered.
        let mut file = match File::open_mode(&path, Open, Write) {
            Ok(f) => f,
            Err(error) => return Some(error),
        };
        match file.write(self.data().as_bytes()) {
            Ok(_) => (),
            Err(error) => return Some(error),
        }

        return None
    }

    /// Inserts `data` into the buffer at the cursor position.
    ///
    /// # Examples
    ///
    /// ```
    /// let mut buffer = scribe::buffer::new();
    /// buffer.insert("scribe");
    /// assert_eq!(buffer.data(), "scribe");
    /// ```
    pub fn insert(&mut self, data: &str) {
        self.data.insert(data, &self.cursor);
    }

    pub fn get_cursor(&self) -> Position {
        Position{ line: self.cursor.line, offset: self.cursor.offset }
    }

    /// Moves the buffer cursor to the specified location. The location is
    /// bounds-checked against the buffer data and the cursor will not be
    /// updated if it is out-of-bounds.
    ///
    /// # Examples
    ///
    /// ```
    /// let mut buffer = scribe::buffer::new();
    /// let in_bounds = scribe::buffer::Position{ line: 0, offset: 2 };
    /// let out_of_bounds = scribe::buffer::Position{ line: 2, offset: 2 };
    /// buffer.insert("scribe");
    ///
    /// buffer.move_cursor(in_bounds);
    /// assert_eq!(buffer.get_cursor().line, 0);
    /// assert_eq!(buffer.get_cursor().offset, 2);
    ///
    /// buffer.move_cursor(out_of_bounds);
    /// assert_eq!(buffer.get_cursor().line, 0);
    /// assert_eq!(buffer.get_cursor().offset, 2);
    /// ```
    pub fn move_cursor(&mut self, position: Position) {
        if self.data.in_bounds(&position) {
            self.cursor = position;
        }
    }
}

/// Creates a new empty buffer. The buffer's cursor is set to the beginning of the buffer.
///
/// # Examples
///
/// ```
/// let buffer = scribe::buffer::new();
/// # assert_eq!(buffer.cursor.line, 0);
/// # assert_eq!(buffer.cursor.offset, 0);
/// ```
pub fn new() -> Buffer {
    let data = gap_buffer::new(String::new());
    let cursor = Position{ line: 0, offset: 0 };

    Buffer{ data: data, path: None, cursor: cursor }
}

/// Creates a new buffer by reading the UTF-8 interpreted file contents of the specified path.
/// The buffer's cursor is set to the beginning of the buffer.
///
/// # Examples
///
/// ```
/// let buffer = scribe::buffer::from_file(&Path::new("tests/sample/file")).unwrap();
/// assert_eq!(buffer.data(), "it works!\n");
/// # assert_eq!(buffer.cursor.line, 0);
/// # assert_eq!(buffer.cursor.offset, 0);
/// ```
pub fn from_file(path: &Path) -> IoResult<Buffer> {
    // Try to open and read the file, returning any errors encountered.
    let mut file = match File::open_mode(path, Open, Read) {
        Ok(f) => f,
        Err(error) => return Err(error),
    };
    let mut data = match file.read_to_string() {
        Ok(d) => d,
        Err(error) => return Err(error),
    };

    let data = gap_buffer::new(data);
    let cursor = Position{ line: 0, offset: 0 };

    // Create a new buffer using the loaded data, path, and other defaults.
    Ok(Buffer{ data: data, path: Some(path.clone()), cursor: cursor })
}
<commit_msg>Replace get_cursor method with dereferenced cursor type.<commit_after>use std::old_io::{File, Open, Read, Write};
use std::old_io::IoError;
use std::old_io::IoResult;
use std::ops::Deref;
use super::GapBuffer;
use super::gap_buffer;
use super::Position;
use super::Range;

pub struct Buffer {
    data: GapBuffer,
    pub path: Option<Path>,
    pub cursor: Cursor,
}

/// Read-only wrapper for a `Position`, to allow field level access to a
/// buffer's cursor while simultaneously enforcing bounds-checking when
/// updating its value.
pub struct Cursor {
    position: Position,
}

impl Deref for Cursor {
    type Target = Position;

    fn deref(&self) -> &Position {
        &self.position
    }
}

impl Buffer {
    /// Returns the contents of the buffer as a string.
    ///
    /// # Examples
    ///
    /// ```
    /// let mut buffer = scribe::buffer::new();
    /// buffer.insert("scribe");
    /// assert_eq!(buffer.data(), "scribe");
    /// ```
    pub fn data(&self) -> String {
        self.data.to_string()
    }

    /// Writes the contents of the buffer to its path.
    ///
    /// # Examples
    ///
    /// ```
    /// # use std::old_io::{File, Open, Read};
    ///
    /// // Set up a buffer and point it to a path.
    /// let mut buffer = scribe::buffer::new();
    /// let write_path = Path::new("my_doc");
    /// buffer.path = Some(write_path.clone());
    ///
    /// // Put some data into the buffer and save it.
    /// buffer.insert("scribe");
    /// buffer.save();
    ///
    /// # let saved_data = File::open_mode(&write_path, Open, Read)
    /// #   .unwrap().read_to_string().unwrap();
    /// # assert_eq!(saved_data, "scribe");
    ///
    /// # std::old_io::fs::unlink(&write_path);
    /// ```
    pub fn save(&self) -> Option<IoError> {
        let path = match self.path.clone() {
            Some(p) => p,
            None => Path::new(""),
        };

        // Try to open and write to the file, returning any errors encountered.
        let mut file = match File::open_mode(&path, Open, Write) {
            Ok(f) => f,
            Err(error) => return Some(error),
        };
        match file.write(self.data().as_bytes()) {
            Ok(_) => (),
            Err(error) => return Some(error),
        }

        return None
    }

    /// Inserts `data` into the buffer at the cursor position.
    ///
    /// # Examples
    ///
    /// ```
    /// let mut buffer = scribe::buffer::new();
    /// buffer.insert("scribe");
    /// assert_eq!(buffer.data(), "scribe");
    /// ```
    pub fn insert(&mut self, data: &str) {
        self.data.insert(data, &self.cursor);
    }

    /// Moves the buffer cursor to the specified location. The location is
    /// bounds-checked against the buffer data and the cursor will not be
    /// updated if it is out-of-bounds.
    ///
    /// # Examples
    ///
    /// ```
    /// let mut buffer = scribe::buffer::new();
    /// let in_bounds = scribe::buffer::Position{ line: 0, offset: 2 };
    /// let out_of_bounds = scribe::buffer::Position{ line: 2, offset: 2 };
    /// buffer.insert("scribe");
    ///
    /// buffer.move_cursor(in_bounds);
    /// assert_eq!(buffer.cursor.line, 0);
    /// assert_eq!(buffer.cursor.offset, 2);
    ///
    /// buffer.move_cursor(out_of_bounds);
    /// assert_eq!(buffer.cursor.line, 0);
    /// assert_eq!(buffer.cursor.offset, 2);
    /// ```
    pub fn move_cursor(&mut self, position: Position) {
        if self.data.in_bounds(&position) {
            self.cursor.position = position;
        }
    }
}

/// Creates a new empty buffer. The buffer's cursor is set to the beginning of the buffer.
///
/// # Examples
///
/// ```
/// let buffer = scribe::buffer::new();
/// # assert_eq!(buffer.cursor.line, 0);
/// # assert_eq!(buffer.cursor.offset, 0);
/// ```
pub fn new() -> Buffer {
    let data = gap_buffer::new(String::new());
    let cursor = Cursor{ position: Position{ line: 0, offset: 0 }};

    Buffer{ data: data, path: None, cursor: cursor }
}

/// Creates a new buffer by reading the UTF-8 interpreted file contents of the specified path.
/// The buffer's cursor is set to the beginning of the buffer.
///
/// # Examples
///
/// ```
/// let buffer = scribe::buffer::from_file(&Path::new("tests/sample/file")).unwrap();
/// assert_eq!(buffer.data(), "it works!\n");
/// # assert_eq!(buffer.cursor.line, 0);
/// # assert_eq!(buffer.cursor.offset, 0);
/// ```
pub fn from_file(path: &Path) -> IoResult<Buffer> {
    // Try to open and read the file, returning any errors encountered.
    let mut file = match File::open_mode(path, Open, Read) {
        Ok(f) => f,
        Err(error) => return Err(error),
    };
    let mut data = match file.read_to_string() {
        Ok(d) => d,
        Err(error) => return Err(error),
    };

    let data = gap_buffer::new(data);
    let cursor = Cursor{ position: Position{ line: 0, offset: 0 }};

    // Create a new buffer using the loaded data, path, and other defaults.
    Ok(Buffer{ data: data, path: Some(path.clone()), cursor: cursor })
}
<|endoftext|>


<commit_before>extern crate ggez;
#[macro_use]
extern crate gfx;
extern crate gfx_device_gl;
extern crate cgmath;

use cgmath::{Deg, Matrix4, Point3, Vector3};
use gfx::texture;
use gfx::traits::FactoryExt;
use gfx::Factory;

use ggez::conf;
use ggez::event;
use ggez::{Context, GameResult};
use ggez::graphics;
use std::time::Duration;

type ColorFormat = gfx::format::Srgba8;
type DepthFormat = gfx::format::DepthStencil;

gfx_defines!{
    vertex Vertex {
        pos: [f32; 4] = "a_Pos",
        tex_coord: [f32; 2] = "a_TexCoord",
    }

    constant Locals {
        transform: [[f32; 4]; 4] = "u_Transform",
    }

    pipeline pipe {
        vbuf: gfx::VertexBuffer<Vertex> = (),
        transform: gfx::Global<[[f32; 4]; 4]> = "u_Transform",
        locals: gfx::ConstantBuffer<Locals> = "Locals",
        color: gfx::TextureSampler<[f32; 4]> = "t_Color",
        out_color: gfx::RenderTarget<ColorFormat> = "Target0",
        out_depth: gfx::DepthTarget<DepthFormat> =
            gfx::preset::depth::LESS_EQUAL_WRITE,
    }
}

impl Vertex {
    fn new(p: [i8; 3], t: [i8; 2]) -> Vertex {
        Vertex {
            pos: [p[0] as f32, p[1] as f32, p[2] as f32, 1.0],
            tex_coord: [t[0] as f32, t[1] as f32],
        }
    }
}

fn default_view() -> Matrix4<f32> {
    Matrix4::look_at(Point3::new(1.5f32, -5.0, 3.0),
                     Point3::new(0f32, 0.0, 0.0),
                     Vector3::unit_z())
}

struct MainState {
    text: graphics::Text,
    frames: usize,
    data: pipe::Data<gfx_device_gl::Resources>,
    pso: gfx::PipelineState<gfx_device_gl::Resources, pipe::Meta>,
    encoder: gfx::Encoder<gfx_device_gl::Resources, gfx_device_gl::CommandBuffer>,
    slice: gfx::Slice<gfx_device_gl::Resources>,
}

impl MainState {
    fn new(ctx: &mut Context) -> Self {

        let font = graphics::Font::new(ctx, "/DejaVuSerif.ttf", 48).unwrap();
        let text = graphics::Text::new(ctx, "Hello world!", &font).unwrap();

        let gfx = &mut ctx.gfx_context;
        let color_view = gfx.get_color_view();
        let depth_view = gfx.get_depth_view();
        let factory = gfx.get_factory();

        let vs = br#"#version 150 core

in vec4 a_Pos;
in vec2 a_TexCoord;
out vec2 v_TexCoord;

uniform Locals {
    mat4 u_Transform;
};

void main() {
    v_TexCoord = a_TexCoord;
    gl_Position = u_Transform * a_Pos;
    gl_ClipDistance[0] = 1.0;
}"#;
        let fs = br#"#version 150 core

in vec2 v_TexCoord;
out vec4 Target0;
uniform sampler2D t_Color;

void main() {
    vec4 tex = texture(t_Color, v_TexCoord);
    float blend = dot(v_TexCoord-vec2(0.5,0.5), v_TexCoord-vec2(0.5,0.5));
    Target0 = mix(tex, vec4(0.0,0.0,0.0,0.0), blend*1.0);
}"#;

        let vertex_data = [// top (0, 0, 1)
                           Vertex::new([-100, -100, 100], [0, 0]),
                           Vertex::new([100, -100, 100], [1, 0]),
                           Vertex::new([100, 100, 100], [1, 1]),
                           Vertex::new([-100, 100, 100], [0, 1]),
                           // bottom (0, 0, -1)
                           Vertex::new([-100, 100, -100], [1, 0]),
                           Vertex::new([100, 100, -100], [0, 0]),
                           Vertex::new([100, -100, -100], [0, 1]),
                           Vertex::new([-100, -100, -100], [1, 1]),
                           // right (1, 0, 0)
                           Vertex::new([100, -100, -100], [0, 0]),
                           Vertex::new([100, 100, -100], [1, 0]),
                           Vertex::new([100, 100, 100], [1, 1]),
                           Vertex::new([100, -100, 100], [0, 1]),
                           // left (-1, 0, 0)
                           Vertex::new([-100, -100, 100], [1, 0]),
                           Vertex::new([-100, 100, 100], [0, 0]),
                           Vertex::new([-100, 100, -100], [0, 1]),
                           Vertex::new([-100, -100, -100], [1, 1]),
                           // front (0, 1, 0)
                           Vertex::new([100, 100, -100], [1, 0]),
                           Vertex::new([-100, 100, -100], [0, 0]),
                           Vertex::new([-100, 100, 100], [0, 1]),
                           Vertex::new([100, 100, 100], [1, 1]),
                           // back (0, -1, 0)
                           Vertex::new([100, -100, 100], [0, 0]),
                           Vertex::new([-100, -100, 100], [1, 0]),
                           Vertex::new([-100, -100, -100], [1, 1]),
                           Vertex::new([100, -100, -100], [0, 1])];

        #[cfg_attr(rustfmt, rustfmt_skip)]
        let index_data: &[u16] = &[
             0,  1,  2,  2,  3,  0, // top
             4,  5,  6,  6,  7,  4, // bottom
             8,  9, 10, 10, 11,  8, // right
            12, 13, 14, 14, 15, 12, // left
            16, 17, 18, 18, 19, 16, // front
            20, 21, 22, 22, 23, 20, // back
        ];

        let (vbuf, slice) = factory.create_vertex_buffer_with_slice(&vertex_data, index_data);

        let texels = [[0x20, 0xA0, 0xC0, 0x00]];
        let (_, texture_view) = factory
            .create_texture_immutable::<gfx::format::Rgba8>(
                texture::Kind::D2(1, 1, texture::AaMode::Single),
                &[&texels],
            )
            .unwrap();

        let sinfo = texture::SamplerInfo::new(texture::FilterMethod::Bilinear,
                                              texture::WrapMode::Clamp);

        let pso = factory
            .create_pipeline_simple(vs, fs, pipe::new())
            .unwrap();

        let proj = cgmath::perspective(Deg(45.0f32), 4.0 / 3.0, 1.0, 10.0);

        let data = pipe::Data {
            vbuf: vbuf,
            transform: (proj * default_view()).into(),
            locals: factory.create_constant_buffer(1),
            color: (texture_view, factory.create_sampler(sinfo)),
            out_color: color_view,
            out_depth: depth_view,
        };

        let encoder: gfx::Encoder<_, _> = factory.create_command_buffer().into();

        MainState {
            text: text,
            frames: 0,
            data: data,
            pso: pso,
            encoder: encoder,
            slice: slice,
        }
    }
}

impl event::EventHandler for MainState {
    fn update(&mut self, _ctx: &mut Context, _dt: Duration) -> GameResult<()> {
        Ok(())
    }

    fn draw(&mut self, ctx: &mut Context) -> GameResult<()> {
        // self.encoder.clear(&self.data.out_color, [0.3, 0.2, 0.1, 1.0].into());
        // self.encoder.draw(&self.slice, &self.pso, &self.data);
        // self.encoder.flush(ctx.gfx_context.get_device());

        {
            let encoder = ctx.gfx_context.get_encoder();
            encoder.clear(&self.data.out_color, [0.3, 0.2, 0.1, 1.0].into());
            encoder.draw(&self.slice, &self.pso, &self.data);
        }

        let dest_point = graphics::Point::new(self.text.width() as f32 / 2.0 + 10.0,
                                              self.text.height() as f32 / 2.0 + 10.0);
        graphics::draw(ctx, &self.text, dest_point, 0.0)?;
        graphics::present(ctx);
        self.frames += 1;
        if (self.frames % 100) == 0 {
            println!("FPS: {}", ggez::timer::get_fps(ctx));
        }
        Ok(())
    }
}

pub fn main() {
    let c = conf::Conf::new();
    let ctx = &mut Context::load_from_conf("helloworld", "ggez", c).unwrap();
    let state = &mut MainState::new(ctx);
    if let Err(e) = event::run(ctx, state) {
        println!("Error encountered: {}", e);
    } else {
        println!("Game exited cleanly.");
    }
}
<commit_msg>Updated cube example to be more informative.  :-P<commit_after>extern crate ggez;
#[macro_use]
extern crate gfx;
extern crate gfx_device_gl;
extern crate cgmath;

use cgmath::{Deg, Matrix4, Point3, Vector3};
use gfx::texture;
use gfx::traits::FactoryExt;
use gfx::Factory;

use ggez::conf;
use ggez::event;
use ggez::{Context, GameResult};
use ggez::graphics;
use std::time::Duration;

type ColorFormat = gfx::format::Srgba8;
type DepthFormat = gfx::format::DepthStencil;

gfx_defines!{
    vertex Vertex {
        pos: [f32; 4] = "a_Pos",
        tex_coord: [f32; 2] = "a_TexCoord",
    }

    constant Locals {
        transform: [[f32; 4]; 4] = "u_Transform",
    }

    pipeline pipe {
        vbuf: gfx::VertexBuffer<Vertex> = (),
        transform: gfx::Global<[[f32; 4]; 4]> = "u_Transform",
        locals: gfx::ConstantBuffer<Locals> = "Locals",
        color: gfx::TextureSampler<[f32; 4]> = "t_Color",
        out_color: gfx::RenderTarget<ColorFormat> = "Target0",
        out_depth: gfx::DepthTarget<DepthFormat> =
            gfx::preset::depth::LESS_EQUAL_WRITE,
    }
}

impl Vertex {
    fn new(p: [i8; 3], t: [i8; 2]) -> Vertex {
        Vertex {
            pos: [p[0] as f32, p[1] as f32, p[2] as f32, 1.0],
            tex_coord: [t[0] as f32, t[1] as f32],
        }
    }
}

fn default_view() -> Matrix4<f32> {
    Matrix4::look_at(Point3::new(1.5f32, -5.0, 3.0),
                     Point3::new(0f32, 0.0, 0.0),
                     Vector3::unit_z())
}

struct MainState {
    text1: graphics::Text,
    text2: graphics::Text,
    frames: usize,
    data: pipe::Data<gfx_device_gl::Resources>,
    pso: gfx::PipelineState<gfx_device_gl::Resources, pipe::Meta>,
    encoder: gfx::Encoder<gfx_device_gl::Resources, gfx_device_gl::CommandBuffer>,
    slice: gfx::Slice<gfx_device_gl::Resources>,
}

impl MainState {
    fn new(ctx: &mut Context) -> Self {

        let font = graphics::Font::new(ctx, "/DejaVuSerif.ttf", 24).unwrap();
        let text1 = graphics::Text::new(ctx, "Doesn't actually successfully", &font).unwrap();
        let text2 = graphics::Text::new(ctx, "draw a cube yet, sorry.", &font).unwrap();

        let gfx = &mut ctx.gfx_context;
        let color_view = gfx.get_color_view();
        let depth_view = gfx.get_depth_view();
        let factory = gfx.get_factory();

        let vs = br#"#version 150 core

in vec4 a_Pos;
in vec2 a_TexCoord;
out vec2 v_TexCoord;

uniform Locals {
    mat4 u_Transform;
};

void main() {
    v_TexCoord = a_TexCoord;
    gl_Position = u_Transform * a_Pos;
    gl_ClipDistance[0] = 1.0;
}"#;
        let fs = br#"#version 150 core

in vec2 v_TexCoord;
out vec4 Target0;
uniform sampler2D t_Color;

void main() {
    vec4 tex = texture(t_Color, v_TexCoord);
    float blend = dot(v_TexCoord-vec2(0.5,0.5), v_TexCoord-vec2(0.5,0.5));
    Target0 = mix(tex, vec4(0.0,0.0,0.0,0.0), blend*1.0);
}"#;

        let vertex_data = [// top (0, 0, 1)
                           Vertex::new([-100, -100, 100], [0, 0]),
                           Vertex::new([100, -100, 100], [1, 0]),
                           Vertex::new([100, 100, 100], [1, 1]),
                           Vertex::new([-100, 100, 100], [0, 1]),
                           // bottom (0, 0, -1)
                           Vertex::new([-100, 100, -100], [1, 0]),
                           Vertex::new([100, 100, -100], [0, 0]),
                           Vertex::new([100, -100, -100], [0, 1]),
                           Vertex::new([-100, -100, -100], [1, 1]),
                           // right (1, 0, 0)
                           Vertex::new([100, -100, -100], [0, 0]),
                           Vertex::new([100, 100, -100], [1, 0]),
                           Vertex::new([100, 100, 100], [1, 1]),
                           Vertex::new([100, -100, 100], [0, 1]),
                           // left (-1, 0, 0)
                           Vertex::new([-100, -100, 100], [1, 0]),
                           Vertex::new([-100, 100, 100], [0, 0]),
                           Vertex::new([-100, 100, -100], [0, 1]),
                           Vertex::new([-100, -100, -100], [1, 1]),
                           // front (0, 1, 0)
                           Vertex::new([100, 100, -100], [1, 0]),
                           Vertex::new([-100, 100, -100], [0, 0]),
                           Vertex::new([-100, 100, 100], [0, 1]),
                           Vertex::new([100, 100, 100], [1, 1]),
                           // back (0, -1, 0)
                           Vertex::new([100, -100, 100], [0, 0]),
                           Vertex::new([-100, -100, 100], [1, 0]),
                           Vertex::new([-100, -100, -100], [1, 1]),
                           Vertex::new([100, -100, -100], [0, 1])];

        #[cfg_attr(rustfmt, rustfmt_skip)]
        let index_data: &[u16] = &[
             0,  1,  2,  2,  3,  0, // top
             4,  5,  6,  6,  7,  4, // bottom
             8,  9, 10, 10, 11,  8, // right
            12, 13, 14, 14, 15, 12, // left
            16, 17, 18, 18, 19, 16, // front
            20, 21, 22, 22, 23, 20, // back
        ];

        let (vbuf, slice) = factory.create_vertex_buffer_with_slice(&vertex_data, index_data);

        let texels = [[0x20, 0xA0, 0xC0, 0x00]];
        let (_, texture_view) = factory
            .create_texture_immutable::<gfx::format::Rgba8>(
                texture::Kind::D2(1, 1, texture::AaMode::Single),
                &[&texels],
            )
            .unwrap();

        let sinfo = texture::SamplerInfo::new(texture::FilterMethod::Bilinear,
                                              texture::WrapMode::Clamp);

        let pso = factory
            .create_pipeline_simple(vs, fs, pipe::new())
            .unwrap();

        let proj = cgmath::perspective(Deg(45.0f32), 4.0 / 3.0, 1.0, 10.0);

        let data = pipe::Data {
            vbuf: vbuf,
            transform: (proj * default_view()).into(),
            locals: factory.create_constant_buffer(1),
            color: (texture_view, factory.create_sampler(sinfo)),
            out_color: color_view,
            out_depth: depth_view,
        };

        let encoder: gfx::Encoder<_, _> = factory.create_command_buffer().into();

        MainState {
            text1: text1,
            text2: text2,
            frames: 0,
            data: data,
            pso: pso,
            encoder: encoder,
            slice: slice,
        }
    }
}

impl event::EventHandler for MainState {
    fn update(&mut self, _ctx: &mut Context, _dt: Duration) -> GameResult<()> {
        Ok(())
    }

    fn draw(&mut self, ctx: &mut Context) -> GameResult<()> {
        // self.encoder.clear(&self.data.out_color, [0.3, 0.2, 0.1, 1.0].into());
        // self.encoder.draw(&self.slice, &self.pso, &self.data);
        // self.encoder.flush(ctx.gfx_context.get_device());

        {
            let encoder = ctx.gfx_context.get_encoder();
            encoder.clear(&self.data.out_color, [0.3, 0.2, 0.1, 1.0].into());
            encoder.draw(&self.slice, &self.pso, &self.data);
        }

        let dest_point1 = graphics::Point::new(self.text1.width() as f32 / 2.0 + 10.0,
                                              self.text1.height() as f32 / 2.0 + 10.0);
        let dest_point2 = graphics::Point::new(self.text2.width() as f32 / 2.0 + 10.0,
                                              self.text2.height() as f32 / 2.0 + 50.0);
        graphics::draw(ctx, &self.text1, dest_point1, 0.0)?;
        graphics::draw(ctx, &self.text2, dest_point2, 0.0)?;
        graphics::present(ctx);
        self.frames += 1;
        if (self.frames % 100) == 0 {
            println!("FPS: {}", ggez::timer::get_fps(ctx));
        }
        Ok(())
    }
}

pub fn main() {
    let c = conf::Conf::new();
    let ctx = &mut Context::load_from_conf("helloworld", "ggez", c).unwrap();
    let state = &mut MainState::new(ctx);
    if let Err(e) = event::run(ctx, state) {
        println!("Error encountered: {}", e);
    } else {
        println!("Game exited cleanly.");
    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2013-2015 Sandstorm Development Group, Inc. and contributors
// Licensed under the MIT License:
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

//! Echo server with a bounded buffer pool.

extern crate gj;
use std::net::ToSocketAddrs;
use std::cell::RefCell;
use std::rc::Rc;
use gj::io::{AsyncRead, AsyncWrite};

struct BufferPool {
    buffers: Vec<Vec<u8>>,
    fulfiller: Option<Box<gj::PromiseFulfiller<Vec<u8>, ::std::io::Error>>>,
}

impl BufferPool {
    pub fn new(num_buffers: usize) -> BufferPool {
        BufferPool { buffers: vec![vec![0; 1024]; num_buffers], fulfiller: None }
    }

    pub fn pop(&mut self) -> gj::Promise<Vec<u8>, ::std::io::Error> {
        match self.buffers.pop() {
            Some(buf) => gj::Promise::fulfilled(buf),
            None => {
                let (promise, fulfiller) = gj::new_promise_and_fulfiller();
                assert!(self.fulfiller.is_none(), "only supports one waiting task");
                self.fulfiller = Some(fulfiller);
                promise
            }
        }
    }

    pub fn push(&mut self, buf: Vec<u8>) {
        match self.fulfiller.take() {
            Some(fulfiller) => fulfiller.fulfill(buf),
            None => self.buffers.push(buf),
        }
    }
}

struct Reaper {
    buffer_pool: Rc<RefCell<BufferPool>>,
}

impl gj::TaskReaper<ThreadedState, gj::io::Error<ThreadedState>> for Reaper {
    fn task_succeeded(&mut self, (_, buf): ThreadedState) {
        self.buffer_pool.borrow_mut().push(buf);
    }
    fn task_failed(&mut self, error: gj::io::Error<ThreadedState>) {
        self.buffer_pool.borrow_mut().push(error.state.1);
        println!("Task failed: {}", error.error);
    }
}

type ThreadedState = (::gj::io::tcp::Stream, Vec<u8>);

fn echo<S,B>(stream: S, buf: B) -> gj::Promise<(S, B), gj::io::Error<(S, B)>>
    where S: AsyncRead + AsyncWrite, B: ::std::ops::DerefMut<Target=[u8]> + 'static
{
    stream.try_read(buf, 1).then(move |(stream, buf, n)| {
        if n == 0 {
            // EOF
            Ok(gj::Promise::fulfilled((stream, buf)))
        } else {
            Ok(stream.write(gj::io::Slice::new(buf, n)).then_else(move |r| match r {
                Ok((stream, slice)) => Ok(echo(stream, slice.buf)),
                Err(gj::io::Error {state: (stream, slice), error}) =>
                    Err(gj::io::Error::new((stream, slice.buf), error)),
            }))
        }
    })
}

fn accept_loop(receiver: gj::io::tcp::Listener,
               mut task_set: gj::TaskSet<ThreadedState, gj::io::Error<ThreadedState>>,
               buffer_pool: Rc<RefCell<BufferPool>>)
               -> gj::Promise<(), ::std::io::Error>
{
    let buf_promise = buffer_pool.borrow_mut().pop();
    buf_promise.then(move |buf| {
        Ok(receiver.accept().lift().then(move |(receiver, stream)| {
            task_set.add(echo(stream, buf));
            Ok(accept_loop(receiver, task_set, buffer_pool))
        }))
    })
}

pub fn main() {
    let args: Vec<String> = ::std::env::args().collect();
    if args.len() != 2 {
        println!("usage: {} HOST:PORT", args[0]);
        return;
    }
    let buffer_pool = Rc::new(RefCell::new(BufferPool::new(64)));

    gj::EventLoop::top_level(move |wait_scope| {

        let addr = try!(args[1].to_socket_addrs()).next().expect("could not parse address");
        let listener = try!(::gj::io::tcp::Listener::bind(addr));
        let reaper = Box::new(Reaper { buffer_pool: buffer_pool.clone() });
        accept_loop(listener, gj::TaskSet::new(reaper), buffer_pool).lift().wait(wait_scope)
    }).unwrap();
}
<commit_msg>Don't panic if there are no buffers.<commit_after>// Copyright (c) 2013-2015 Sandstorm Development Group, Inc. and contributors
// Licensed under the MIT License:
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

//! Echo server with a bounded buffer pool.

extern crate gj;
use std::net::ToSocketAddrs;
use std::cell::RefCell;
use std::rc::Rc;
use gj::io::{AsyncRead, AsyncWrite};

struct BufferPool {
    buffers: Vec<Vec<u8>>,
    fulfiller: Option<Box<gj::PromiseFulfiller<Vec<u8>, ()>>>,
}

impl BufferPool {
    pub fn new(num_buffers: usize) -> BufferPool {
        BufferPool { buffers: vec![vec![0; 1024]; num_buffers], fulfiller: None }
    }

    pub fn pop(&mut self) -> gj::Promise<Vec<u8>, ()> {
        match self.buffers.pop() {
            Some(buf) => gj::Promise::fulfilled(buf),
            None => {
                if self.fulfiller.is_some() {
                    gj::Promise::rejected(())
                } else {
                    let (promise, fulfiller) = gj::new_promise_and_fulfiller();
                    self.fulfiller = Some(fulfiller);
                    promise
                }
            }
        }
    }

    pub fn push(&mut self, buf: Vec<u8>) {
        match self.fulfiller.take() {
            Some(fulfiller) => fulfiller.fulfill(buf),
            None => self.buffers.push(buf),
        }
    }
}

struct Reaper {
    buffer_pool: Rc<RefCell<BufferPool>>,
}

impl gj::TaskReaper<ThreadedState, gj::io::Error<ThreadedState>> for Reaper {
    fn task_succeeded(&mut self, (_, buf): ThreadedState) {
        self.buffer_pool.borrow_mut().push(buf);
    }
    fn task_failed(&mut self, error: gj::io::Error<ThreadedState>) {
        self.buffer_pool.borrow_mut().push(error.state.1);
        println!("Task failed: {}", error.error);
    }
}

type ThreadedState = (::gj::io::tcp::Stream, Vec<u8>);

fn echo<S,B>(stream: S, buf: B) -> gj::Promise<(S, B), gj::io::Error<(S, B)>>
    where S: AsyncRead + AsyncWrite, B: ::std::ops::DerefMut<Target=[u8]> + 'static
{
    stream.try_read(buf, 1).then(move |(stream, buf, n)| {
        if n == 0 {
            // EOF
            Ok(gj::Promise::fulfilled((stream, buf)))
        } else {
            Ok(stream.write(gj::io::Slice::new(buf, n)).then_else(move |r| match r {
                Ok((stream, slice)) => Ok(echo(stream, slice.buf)),
                Err(gj::io::Error {state: (stream, slice), error}) =>
                    Err(gj::io::Error::new((stream, slice.buf), error)),
            }))
        }
    })
}

fn accept_loop(receiver: gj::io::tcp::Listener,
               mut task_set: gj::TaskSet<ThreadedState, gj::io::Error<ThreadedState>>,
               buffer_pool: Rc<RefCell<BufferPool>>)
               -> gj::Promise<(), ::std::io::Error>
{
    let buf_promise = buffer_pool.borrow_mut().pop().map_err(|()| {
        ::std::io::Error::new(::std::io::ErrorKind::Other, "No available buffers")});
    buf_promise.then(move |buf| {
        Ok(receiver.accept().lift().then(move |(receiver, stream)| {
            task_set.add(echo(stream, buf));
            Ok(accept_loop(receiver, task_set, buffer_pool))
        }))
    })
}

pub fn main() {
    let args: Vec<String> = ::std::env::args().collect();
    if args.len() != 2 {
        println!("usage: {} HOST:PORT", args[0]);
        return;
    }
    let buffer_pool = Rc::new(RefCell::new(BufferPool::new(64)));

    gj::EventLoop::top_level(move |wait_scope| {
        let addr = try!(args[1].to_socket_addrs()).next().expect("could not parse address");
        let listener = try!(::gj::io::tcp::Listener::bind(addr));
        let reaper = Box::new(Reaper { buffer_pool: buffer_pool.clone() });
        accept_loop(listener, gj::TaskSet::new(reaper), buffer_pool).lift().wait(wait_scope)
    }).unwrap();
}
<|endoftext|>


<commit_before>extern crate ease;
extern crate rustc_serialize;

use std::collections::HashMap;
use ease::{Url, Request};

#[derive(RustcDecodable, Debug)]
struct Response {
    args: HashMap<String, String>,
    data: Option<String>,
    files: Option<HashMap<String, String>>,
    form: Option<HashMap<String, String>>,
    headers: HashMap<String, String>,
    json: Option<String>,
    origin: String,
    url: String,
}

fn main() {
    let url = Url::parse("http://httpbin.org/post").unwrap();
    println!("{:#?}", Request::new(url).post().unwrap().json_as::<Response>());

    let url = Url::parse("http://httpbin.org/get").unwrap();
    println!("{:#?}", Request::new(url).get().unwrap().json_as::<Response>());
}
<commit_msg>Make error handling in example better.<commit_after>extern crate ease;
extern crate rustc_serialize;

use std::collections::HashMap;
use ease::{Url, Request};

#[derive(RustcDecodable, Debug)]
struct Response {
    args: HashMap<String, String>,
    data: Option<String>,
    files: Option<HashMap<String, String>>,
    form: Option<HashMap<String, String>>,
    headers: HashMap<String, String>,
    json: Option<String>,
    origin: String,
    url: String,
}

fn main() {
    let url = Url::parse("http://httpbin.org/post").unwrap();
    println!("{:#?}", Request::new(url).post().and_then(|res| res.json_as::<Response>()));

    let url = Url::parse("http://httpbin.org/get").unwrap();
    println!("{:#?}", Request::new(url).get().and_then(|res| res.json_as::<Response>()));
}
<|endoftext|>


<commit_before>extern crate ruroonga;
use ruroonga::*;
use std::ffi::CStr;
use std::str;

fn main() {
    unsafe {
        let rc = grn_init();
        let ctx = grn_ctx_open(rc);
        let slice = CStr::from_ptr(ruroonga::grn_get_version());
        println!("Hello in Ruroonga with Groonga: {}", str::from_utf8(slice.to_bytes()).unwrap());
        let _ = grn_fin();
    }
}
<commit_msg>example: Use ruroonga::grn_ctx_close<commit_after>extern crate ruroonga;
use ruroonga::*;
use std::ffi::CStr;
use std::str;

fn main() {
    unsafe {
        let rc = grn_init();
        let ctx = grn_ctx_open(rc);
        let slice = CStr::from_ptr(ruroonga::grn_get_version());
        println!("Hello in Ruroonga with Groonga: {}", str::from_utf8(slice.to_bytes()).unwrap());
        let rc = grn_ctx_close(ctx);
        let _ = grn_fin();
    }
}
<|endoftext|>