<commit_before>//#![feature(proc_macro, conservative_impl_trait, generators)]
#![feature(proc_macro_non_items, conservative_impl_trait, generators)]
extern crate bytes;
extern crate futures_await as futures;
extern crate tokio_core;
extern crate tokio_io;

mod cmd;
mod ftp;
mod error;

use std::io;
use futures::prelude::*;

/*
#[async]
fn server() -> io::Result<()> {
    Ok(())
}
*/

use tokio_core::reactor::Core;
fn main() {
    let mut core = Core::new().expect("Cannot create tokio Core");
    let server = async_block! {
        Ok(())
    };
    let result: Result<_, io::Error> = core.run(server);
    if let Err(error) = result {
        println!("Error running the server: {}", error);
    }

}
<commit_msg>Added first code for ftp server which manage clients<commit_after>#![feature(proc_macro, conservative_impl_trait, generators)]
extern crate bytes;
extern crate futures_await as futures;
extern crate tokio_core;
extern crate tokio_io;

mod cmd;
mod ftp;
mod error;

use std::io;
use futures::prelude::*;
use tokio_core::reactor::Core;
use std::net::{IpAddr, Ipv4Addr, SocketAddr};
use tokio_core::reactor::Handle;
use tokio_core::net::TcpListener;

use tokio_core::net::TcpStream;

#[async]
fn handle_client(stream: TcpStream) -> result::Result<(), ()> {
    await!(client(stream)).map_err(|error| println("Error handling client: {}", error))
}

#[async]
fn server(handle: Handle) -> io::Result<()> {
    let port = 1234;
    let addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127,0,0,1)), port);
    let listener = TcpListener::bind(&addr,&handle)?;
    println!("Waiting clients on port {}...",port);
    #[async]
    for (stream, addr) in listener.incoming() {
        let address = format!("[address : {}]",addr);
        println!("New client {}", address);
        handle.spawn(handle_client(stream));
        println!("Waiting another client...");
    }
    return Ok(());
}

fn main() {
    let mut core = Core::new().expect("Cannot create tokio Core");
    let handle = core.handle();
    if let Err(error) = core.run(server(handle)) {
        println!("Error running the server: {}", error);
    }

}
<|endoftext|>


<commit_before>// Copyright (c) 2017 Chef Software Inc. and/or applicable contributors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use clap::{App, Arg};
use std::result;

use export_docker as docker;

/// A Kubernetes-specific clap:App wrapper
#[derive(Clone)]
pub struct Cli<'a, 'b>
where
    'a: 'b,
{
    pub app: App<'a, 'b>,
}

impl<'a, 'b> Cli<'a, 'b> {
    pub fn new(name: &str, about: &'a str) -> Self {
        let app = docker::Cli::new(name, about).app;

        Cli { app: app }
    }

    pub fn add_all_args(self) -> Self {
        self.add_docker_args()
            .add_output_args()
            .add_runtime_args()
            .add_secret_names_args()
            .add_bind_args()
    }

    pub fn add_docker_args(self) -> Self {
        let cli = docker::Cli { app: self.app };
        let app = cli.add_base_packages_args()
            .add_builder_args()
            .add_tagging_args()
            .add_publishing_args()
            .add_pkg_ident_arg(docker::PkgIdentArgOptions { multiple: false })
            .app
            .arg(
                Arg::with_name("NO_DOCKER_IMAGE")
                    .long("no-docker-image")
                    .short("d")
                    .help(
                        "Disable creation of the Docker image and only create a Kubernetes \
                         manifest",
                    ),
            );

        Cli { app: app }
    }

    pub fn add_output_args(self) -> Self {
        Cli {
            app: self.app.arg(
                Arg::with_name("OUTPUT")
                    .value_name("OUTPUT")
                    .long("output")
                    .short("o")
                    .help(
                        "Name of manifest file to create. Pass '-' for stdout (default: -)",
                    ),
            ),
        }
    }

    pub fn add_runtime_args(self) -> Self {
        Cli {
            app: self.app
                .arg(
                    Arg::with_name("COUNT")
                        .value_name("COUNT")
                        .long("count")
                        .validator(valid_natural_number)
                        .help("Count is the number of desired instances"),
                )
                .arg(
                    Arg::with_name("TOPOLOGY")
                        .value_name("TOPOLOGY")
                        .long("topology")
                        .short("t")
                        .possible_values(&["standalone", "leader"])
                        .help(
                            "A topology describes the intended relationship between peers \
                         within a Habitat service group. Specify either standalone or leader \
                         topology (default: standalone)",
                        ),
                )
                .arg(
                    Arg::with_name("GROUP")
                        .value_name("GROUP")
                        .long("service-group")
                        .short("g")
                        .help(
                            "group is a logical grouping of services with the same package and \
                         topology type connected together in a ring (default: default)",
                        ),
                )
                .arg(
                    Arg::with_name("CONFIG")
                        .value_name("CONFIG")
                        .long("config")
                        .short("n")
                        .help(
                            "The path to Habitat configuration file in user.toml format. Habitat \
                            will use it for initial configuration of the service running in a \
                            Kubernetes cluster",
                        ),
                ),
        }
    }

    pub fn add_secret_names_args(self) -> Self {
        Cli {
            app: self.app.arg(
                Arg::with_name("RING_SECRET_NAME")
                    .value_name("RING_SECRET_NAME")
                    .long("ring-secret-name")
                    .short("r")
                    .help(
                        "name of the Kubernetes Secret that contains the ring key, which \
                         encrypts the communication between Habitat supervisors",
                    ),
            ),
        }
    }

    pub fn add_bind_args(self) -> Self {
        Cli {
            app: self.app.arg(
                Arg::with_name("BIND")
                    .value_name("BIND")
                    .long("bind")
                    .short("b")
                    .multiple(true)
                    .number_of_values(1)
                    .help(
                        "Bind to another service to form a producer/consumer relationship, \
                         specified as name:service:group",
                    ),
            ),
        }
    }
}

fn valid_natural_number(val: String) -> result::Result<(), String> {
    match val.parse::<u32>() {
        Ok(_) => Ok(()),
        Err(_) => Err(format!("{} is not a natural number", val)),
    }
}
<commit_msg>pkg-export-k8s: testcase for natural num validator<commit_after>// Copyright (c) 2017 Chef Software Inc. and/or applicable contributors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use clap::{App, Arg};
use std::result;

use export_docker as docker;

/// A Kubernetes-specific clap:App wrapper
#[derive(Clone)]
pub struct Cli<'a, 'b>
where
    'a: 'b,
{
    pub app: App<'a, 'b>,
}

impl<'a, 'b> Cli<'a, 'b> {
    pub fn new(name: &str, about: &'a str) -> Self {
        let app = docker::Cli::new(name, about).app;

        Cli { app: app }
    }

    pub fn add_all_args(self) -> Self {
        self.add_docker_args()
            .add_output_args()
            .add_runtime_args()
            .add_secret_names_args()
            .add_bind_args()
    }

    pub fn add_docker_args(self) -> Self {
        let cli = docker::Cli { app: self.app };
        let app = cli.add_base_packages_args()
            .add_builder_args()
            .add_tagging_args()
            .add_publishing_args()
            .add_pkg_ident_arg(docker::PkgIdentArgOptions { multiple: false })
            .app
            .arg(
                Arg::with_name("NO_DOCKER_IMAGE")
                    .long("no-docker-image")
                    .short("d")
                    .help(
                        "Disable creation of the Docker image and only create a Kubernetes \
                         manifest",
                    ),
            );

        Cli { app: app }
    }

    pub fn add_output_args(self) -> Self {
        Cli {
            app: self.app.arg(
                Arg::with_name("OUTPUT")
                    .value_name("OUTPUT")
                    .long("output")
                    .short("o")
                    .help(
                        "Name of manifest file to create. Pass '-' for stdout (default: -)",
                    ),
            ),
        }
    }

    pub fn add_runtime_args(self) -> Self {
        Cli {
            app: self.app
                .arg(
                    Arg::with_name("COUNT")
                        .value_name("COUNT")
                        .long("count")
                        .validator(valid_natural_number)
                        .help("Count is the number of desired instances"),
                )
                .arg(
                    Arg::with_name("TOPOLOGY")
                        .value_name("TOPOLOGY")
                        .long("topology")
                        .short("t")
                        .possible_values(&["standalone", "leader"])
                        .help(
                            "A topology describes the intended relationship between peers \
                         within a Habitat service group. Specify either standalone or leader \
                         topology (default: standalone)",
                        ),
                )
                .arg(
                    Arg::with_name("GROUP")
                        .value_name("GROUP")
                        .long("service-group")
                        .short("g")
                        .help(
                            "group is a logical grouping of services with the same package and \
                         topology type connected together in a ring (default: default)",
                        ),
                )
                .arg(
                    Arg::with_name("CONFIG")
                        .value_name("CONFIG")
                        .long("config")
                        .short("n")
                        .help(
                            "The path to Habitat configuration file in user.toml format. Habitat \
                            will use it for initial configuration of the service running in a \
                            Kubernetes cluster",
                        ),
                ),
        }
    }

    pub fn add_secret_names_args(self) -> Self {
        Cli {
            app: self.app.arg(
                Arg::with_name("RING_SECRET_NAME")
                    .value_name("RING_SECRET_NAME")
                    .long("ring-secret-name")
                    .short("r")
                    .help(
                        "name of the Kubernetes Secret that contains the ring key, which \
                         encrypts the communication between Habitat supervisors",
                    ),
            ),
        }
    }

    pub fn add_bind_args(self) -> Self {
        Cli {
            app: self.app.arg(
                Arg::with_name("BIND")
                    .value_name("BIND")
                    .long("bind")
                    .short("b")
                    .multiple(true)
                    .number_of_values(1)
                    .help(
                        "Bind to another service to form a producer/consumer relationship, \
                         specified as name:service:group",
                    ),
            ),
        }
    }
}

fn valid_natural_number(val: String) -> result::Result<(), String> {
    match val.parse::<u32>() {
        Ok(_) => Ok(()),
        Err(_) => Err(format!("{} is not a natural number", val)),
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_valid_natural_number() {
        valid_natural_number("99".to_owned()).unwrap();

        for &s in ["x", "", "#####", "0x11", "ab"].iter() {
            assert!(valid_natural_number(s.to_owned()).is_err());
        }
    }
}
<|endoftext|>


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

//! Global style data

use context::StyleSystemOptions;
use gecko_bindings::bindings::{Gecko_RegisterProfilerThread, Gecko_UnregisterProfilerThread};
use gecko_bindings::bindings::Gecko_SetJemallocThreadLocalArena;
use num_cpus;
use rayon;
use shared_lock::SharedRwLock;
use std::cmp;
use std::env;
use std::ffi::CString;

/// Global style data
pub struct GlobalStyleData {
    /// How many threads parallel styling can use.
    pub num_threads: usize,

    /// The parallel styling thread pool.
    pub style_thread_pool: Option<rayon::ThreadPool>,

    /// Shared RWLock for CSSOM objects
    pub shared_lock: SharedRwLock,

    /// Global style system options determined by env vars.
    pub options: StyleSystemOptions,
}

fn thread_name(index: usize) -> String {
    format!("StyleThread#{}", index)
}

fn thread_startup(index: usize) {
    unsafe {
        Gecko_SetJemallocThreadLocalArena(true);
    }
    let name = thread_name(index);
    let name = CString::new(name).unwrap();
    unsafe {
        // Gecko_RegisterProfilerThread copies the passed name here.
        Gecko_RegisterProfilerThread(name.as_ptr());
    }
}

fn thread_shutdown(_: usize) {
    unsafe {
        Gecko_UnregisterProfilerThread();
        Gecko_SetJemallocThreadLocalArena(false);
    }
}

lazy_static! {
    /// Global style data
    pub static ref GLOBAL_STYLE_DATA: GlobalStyleData = {
        let stylo_threads = env::var("STYLO_THREADS")
            .map(|s| s.parse::<usize>().expect("invalid STYLO_THREADS value"));
        let num_threads = match stylo_threads {
            Ok(num) => num,
            _ => cmp::max(num_cpus::get() * 3 / 4, 1),
        };

        let pool = if num_threads <= 1 {
            None
        } else {
            let configuration = rayon::Configuration::new()
                .num_threads(num_threads)
                .thread_name(thread_name)
                .start_handler(thread_startup)
                .exit_handler(thread_shutdown);
            let pool = rayon::ThreadPool::new(configuration).ok();
            pool
        };

        GlobalStyleData {
            num_threads: num_threads,
            style_thread_pool: pool,
            shared_lock: SharedRwLock::new(),
            options: StyleSystemOptions::default(),
        }
    };
}
<commit_msg>Allow forcing a style threadpool of size 1.<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

//! Global style data

use context::StyleSystemOptions;
use gecko_bindings::bindings::{Gecko_RegisterProfilerThread, Gecko_UnregisterProfilerThread};
use gecko_bindings::bindings::Gecko_SetJemallocThreadLocalArena;
use num_cpus;
use rayon;
use shared_lock::SharedRwLock;
use std::cmp;
use std::env;
use std::ffi::CString;

/// Global style data
pub struct GlobalStyleData {
    /// How many threads parallel styling can use.
    pub num_threads: usize,

    /// The parallel styling thread pool.
    pub style_thread_pool: Option<rayon::ThreadPool>,

    /// Shared RWLock for CSSOM objects
    pub shared_lock: SharedRwLock,

    /// Global style system options determined by env vars.
    pub options: StyleSystemOptions,
}

fn thread_name(index: usize) -> String {
    format!("StyleThread#{}", index)
}

fn thread_startup(index: usize) {
    unsafe {
        Gecko_SetJemallocThreadLocalArena(true);
    }
    let name = thread_name(index);
    let name = CString::new(name).unwrap();
    unsafe {
        // Gecko_RegisterProfilerThread copies the passed name here.
        Gecko_RegisterProfilerThread(name.as_ptr());
    }
}

fn thread_shutdown(_: usize) {
    unsafe {
        Gecko_UnregisterProfilerThread();
        Gecko_SetJemallocThreadLocalArena(false);
    }
}

lazy_static! {
    /// Global style data
    pub static ref GLOBAL_STYLE_DATA: GlobalStyleData = {
        let stylo_threads = env::var("STYLO_THREADS")
            .map(|s| s.parse::<usize>().expect("invalid STYLO_THREADS value"));
        let mut num_threads = match stylo_threads {
            Ok(num) => num,
            _ => cmp::max(num_cpus::get() * 3 / 4, 1),
        };

        // If num_threads is one, there's no point in creating a thread pool, so
        // force it to zero.
        //
        // We allow developers to force a one-thread pool for testing via a
        // special environmental variable.
        if num_threads == 1 {
            let force_pool = env::var("FORCE_STYLO_THREAD_POOL")
                .ok().map_or(false, |s| s.parse::<usize>().expect("invalid FORCE_STYLO_THREAD_POOL value") == 1);
            if !force_pool {
                num_threads = 0;
            }
        }

        let pool = if num_threads < 1 {
            None
        } else {
            let configuration = rayon::Configuration::new()
                .num_threads(num_threads)
                .thread_name(thread_name)
                .start_handler(thread_startup)
                .exit_handler(thread_shutdown);
            let pool = rayon::ThreadPool::new(configuration).ok();
            pool
        };

        GlobalStyleData {
            num_threads: num_threads,
            style_thread_pool: pool,
            shared_lock: SharedRwLock::new(),
            options: StyleSystemOptions::default(),
        }
    };
}
<|endoftext|>


<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

use geo::algorithm::bounding_rect::BoundingRect;
use geo::algorithm::euclidean_distance::EuclideanDistance;
use geo_types::{MultiPolygon, Point};
use mimir::Admin;
use rstar::{PointDistance, RTree, RTreeObject, AABB};
// use std::collections::BTreeMap;
use std::iter::FromIterator;
use std::sync::Arc;

pub struct BoundedId {
    pub boundary: MultiPolygon<f64>,
    pub admin: Arc<Admin>,
}

impl RTreeObject for BoundedId {
    type Envelope = AABB<Point<f64>>;

    fn envelope(&self) -> Self::Envelope {
        let bb = self.boundary.bounding_rect().unwrap();
        AABB::from_corners(
            Point::new(bb.min.x, bb.min.y),
            Point::new(bb.max.x, bb.max.y),
        )
    }
}

impl PointDistance for BoundedId {
    // This function computes the square of the distance from an Admin to a point.
    // We compute the distance from the boundary to a point.
    fn distance_2(&self, point: &Point<f64>) -> f64 {
        let d = self.boundary.euclidean_distance(point);
        d * d
    }
}

pub struct AdminGeoFinder {
    rtree: RTree<BoundedId>,
}

impl AdminGeoFinder {
    pub fn insert(&mut self, admin: Admin) {
        let mut admin = admin;
        let boundary = std::mem::replace(&mut admin.boundary, None);
        if let Some(boundary) = boundary {
            let bounded_id = BoundedId {
                boundary,
                admin: Arc::new(admin),
            };
            self.rtree.insert(bounded_id);
        }
    }

    // Get all Admins overlapping the given coordinates.
    pub fn get(&self, coord: &geo_types::Coordinate<f64>) -> Vec<Arc<Admin>> {
        let point: geo_types::Point<f64> = coord.clone().into();
        // Get a list of overlapping admins...
        let mut admins: Vec<Arc<Admin>> = self
            .rtree
            .locate_all_at_point(&point)
            .map(|bounded_id| bounded_id.admin.clone())
            .collect();
        // Then dedup by zone_type (provided the zone_type is not None)
        // Note that dedup requires a sorted vector.
        admins.sort_by_key(|adm| adm.zone_type);
        admins.dedup_by(|adm1, adm2| {
            if adm1.zone_type != adm2.zone_type {
                false
            } else {
                if adm1.zone_type == None {
                    false
                } else {
                    true
                }
            }
        });
        admins
    }

    /// Iterates on all the admins with a not None boundary.
    pub fn admins(&self) -> impl Iterator<Item = Arc<Admin>> + '_ {
        self.rtree.iter().map(|bounded_id| bounded_id.admin.clone())
    }
}

impl Default for AdminGeoFinder {
    fn default() -> Self {
        AdminGeoFinder {
            rtree: RTree::new(),
        }
    }
}

impl FromIterator<Admin> for AdminGeoFinder {
    fn from_iter<I: IntoIterator<Item = Admin>>(admins: I) -> Self {
        let mut geofinder = AdminGeoFinder::default();

        for admin in admins {
            geofinder.insert(admin);
        }

        geofinder
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use cosmogony::ZoneType;
    use geo::prelude::BoundingRect;

    // the goal is that f in [down(f as f32) as f64, up(f as f32) as f64]
    fn down(f: f32) -> f32 {
        f - (f * ::std::f32::EPSILON).abs()
    }
    fn up(f: f32) -> f32 {
        f + (f * ::std::f32::EPSILON).abs()
    }

    #[test]
    fn test_up_down() {
        for &f in [1.0f64, 0., -0., -1., 0.1, -0.1, 0.9, -0.9, 42., -42.].iter() {
            let small_f = f as f32;
            assert!(
                down(small_f) as f64 <= f,
                format!("{} <= {}", down(small_f) as f64, f)
            );
            assert!(
                f <= up(small_f) as f64,
                format!("{} <= {}", f, up(small_f) as f64)
            );
        }
    }

    fn p(x: f64, y: f64) -> geo_types::Point<f64> {
        geo_types::Point(geo_types::Coordinate { x: x, y: y })
    }

    fn make_admin(offset: f64, zt: Option<ZoneType>) -> ::mimir::Admin {
        make_complex_admin(&format!("admin:offset:{}", offset,), offset, zt, 1., None)
    }

    fn make_complex_admin(
        id: &str,
        offset: f64,
        zone_type: Option<ZoneType>,
        zone_size: f64,
        parent_offset: Option<&str>,
    ) -> ::mimir::Admin {
        // the boundary is a big octogon
        // the zone_size param is used to control the area of the zone
        let shape = geo_types::Polygon::new(
            geo_types::LineString(vec![
                (3. * zone_size + offset, 0. * zone_size + offset).into(), //     ^
                (6. * zone_size + offset, 0. * zone_size + offset).into(), //     |   x   x
                (9. * zone_size + offset, 3. * zone_size + offset).into(), //     |
                (9. * zone_size + offset, 6. * zone_size + offset).into(), //     x           x
                (6. * zone_size + offset, 9. * zone_size + offset).into(), //     |
                (3. * zone_size + offset, 9. * zone_size + offset).into(), //     x           x
                (0. * zone_size + offset, 6. * zone_size + offset).into(), //     |
                (0. * zone_size + offset, 3. * zone_size + offset).into(), //     +---x---x------->
                (3. * zone_size + offset, 0. * zone_size + offset).into(), //
            ]),
            vec![],
        );
        let boundary = geo_types::MultiPolygon(vec![shape]);

        let coord = ::mimir::Coord::new(4.0 + offset, 4.0 + offset);
        ::mimir::Admin {
            id: id.into(),
            level: 8,
            name: "city".to_string(),
            label: format!("city {}", offset),
            zip_codes: vec!["421337".to_string()],
            weight: 0f64,
            coord: coord.clone(),
            approx_coord: Some(coord.into()),
            bbox: boundary.bounding_rect(),
            boundary: Some(boundary),
            insee: "outlook".to_string(),
            zone_type: zone_type,
            parent_id: parent_offset.map(|id| id.into()),
            ..Default::default()
        }
    }

    #[test]
    fn test_two_fake_admins() {
        let mut finder = AdminGeoFinder::default();
        finder.insert(make_admin(40., Some(ZoneType::City)));
        finder.insert(make_admin(43., Some(ZoneType::State)));

        // outside
        for coord in [p(48., 41.), p(411., 41.), p(51., 54.), p(53., 53.)].iter() {
            assert!(finder.get(&coord.0).is_empty());
        }

        // inside one
        let admins = finder.get(&p(44., 44.).0);
        assert_eq!(admins.len(), 1);
        assert_eq!(admins[0].id, "admin:offset:40");
        let admins = finder.get(&p(48., 48.).0);
        assert_eq!(admins.len(), 1);
        assert_eq!(admins[0].id, "admin:offset:43");

        // inside two
        let mut admins = finder.get(&p(46., 46.).0);
        admins.sort_by(|a, b| a.id.cmp(&b.id));
        assert_eq!(admins.len(), 2);
        assert_eq!(admins[0].id, "admin:offset:40");
        assert_eq!(admins[1].id, "admin:offset:43");
    }

    #[test]
    fn test_two_admin_same_zone_type() {
        // a point can be associated to only 1 admin type
        // so a point is in 2 city, it is associated to only one
        let mut finder = AdminGeoFinder::default();
        finder.insert(make_admin(40., Some(ZoneType::City)));
        finder.insert(make_admin(43., Some(ZoneType::City)));
        let admins = finder.get(&p(46., 46.).0);
        assert_eq!(admins.len(), 1);
    }

    // #[test]
    // fn test_two_no_zone_type() {
    //     // a point can be associated to only 1 admin type
    //     // but a point can be associated to multiple admin without zone_type
    //     // (for retrocompatibility of the data imported without cosmogony)
    //     let mut finder = AdminGeoFinder::default();
    //     finder.insert(make_admin(40., None));
    //     finder.insert(make_admin(43., None));
    //     let admins = finder.get(&p(46., 46.).0);
    //     assert_eq!(admins.len(), 2);
    // }

    #[test]
    fn test_hierarchy() {
        // In this test we use 3 admin regions that include each other.
        let mut finder = AdminGeoFinder::default();
        finder.insert(make_complex_admin(
            "bob_city",
            40.,
            Some(ZoneType::City),
            1.,
            Some("bob_state"),
        ));
        finder.insert(make_complex_admin(
            "bob_state",
            40.,
            Some(ZoneType::StateDistrict),
            2.,
            Some("bob_country"),
        ));
        finder.insert(make_complex_admin(
            "bob_country",
            40.,
            Some(ZoneType::Country),
            3.,
            None,
        ));

        let admins = finder.get(&p(46., 46.).0);
        assert_eq!(admins.len(), 3);
        assert_eq!(admins[0].id, "bob_city");
        assert_eq!(admins[1].id, "bob_state");
        assert_eq!(admins[2].id, "bob_country");
    }

    #[test]
    fn test_hierarchy_orphan() {
        let mut finder = AdminGeoFinder::default();
        finder.insert(make_complex_admin(
            "bob_city",
            40.,
            Some(ZoneType::City),
            1.,
            Some("bob_state"),
        ));
        finder.insert(make_complex_admin(
            "bob_state",
            40.,
            Some(ZoneType::StateDistrict),
            2.,
            Some("bob_country"),
        ));
        finder.insert(make_complex_admin(
            "bob_country",
            40.,
            Some(ZoneType::Country),
            3.,
            None,
        ));

        // another_state also contains the point, but the geofinder look for only 1 admin by type (it needs only 1 state)
        // since bob_city has been tester first, it's hierarchy has been added automatically
        // so [46., 46.] will not be associated to another_state
        finder.insert(make_complex_admin(
            "another_state",
            40.,
            Some(ZoneType::StateDistrict),
            2.,
            Some("bob_country"),
        ));

        let admins = finder.get(&p(46., 46.).0);
        assert_eq!(admins.len(), 3);
        assert_eq!(admins[0].id, "bob_city");
        assert_eq!(admins[1].id, "another_state");
        assert_eq!(admins[2].id, "bob_country");
    }

    #[test]
    fn test_hierarchy_and_not_typed_zone() {
        let mut finder = AdminGeoFinder::default();
        finder.insert(make_complex_admin(
            "bob_city",
            40.,
            Some(ZoneType::City),
            1.,
            Some("bob_state"),
        ));
        finder.insert(make_complex_admin(
            "bob_state",
            40.,
            Some(ZoneType::StateDistrict),
            2.,
            Some("bob_country"),
        ));
        finder.insert(make_complex_admin(
            "bob_country",
            40.,
            Some(ZoneType::Country),
            3.,
            None,
        ));

        // not_typed zone is outside the hierarchy, but since it contains the point and it has no type it is added
        finder.insert(make_complex_admin("no_typed_zone", 40., None, 2., None));

        let admins = finder.get(&p(46., 46.).0);
        assert_eq!(admins.len(), 4);
        assert_eq!(admins[0].id, "no_typed_zone");
        assert_eq!(admins[1].id, "bob_city");
        assert_eq!(admins[2].id, "bob_state");
        assert_eq!(admins[3].id, "bob_country");
    }
}
<commit_msg>Changes per PR comments<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

use geo::algorithm::{
    bounding_rect::BoundingRect, contains::Contains, euclidean_distance::EuclideanDistance,
};
use geo_types::{MultiPolygon, Point};
use mimir::Admin;
use rstar::{PointDistance, RTree, RTreeObject, AABB};
// use std::collections::BTreeMap;
use std::iter::FromIterator;
use std::sync::Arc;

pub struct BoundedId {
    pub boundary: MultiPolygon<f64>,
    pub admin: Arc<Admin>,
}

impl RTreeObject for BoundedId {
    type Envelope = AABB<Point<f64>>;

    fn envelope(&self) -> Self::Envelope {
        let bb = self.boundary.bounding_rect().unwrap();
        AABB::from_corners(
            Point::new(bb.min.x, bb.min.y),
            Point::new(bb.max.x, bb.max.y),
        )
    }
}

impl PointDistance for BoundedId {
    // This function computes the square of the distance from an Admin to a point.
    // We compute the distance from the boundary to a point.
    fn distance_2(&self, point: &Point<f64>) -> f64 {
        let d = self.boundary.euclidean_distance(point);
        d * d
    }

    // contains_point is provided, but we override the default implementation using
    // the geo algorithms for performance, as suggested in rstar documentation.
    fn contains_point(&self, point: &Point<f64>) -> bool {
        self.boundary.contains(point)
    }
}

pub struct AdminGeoFinder {
    rtree: RTree<BoundedId>,
}

impl AdminGeoFinder {
    pub fn insert(&mut self, admin: Admin) {
        let mut admin = admin;
        let boundary = std::mem::replace(&mut admin.boundary, None);
        if let Some(boundary) = boundary {
            let bounded_id = BoundedId {
                boundary,
                admin: Arc::new(admin),
            };
            self.rtree.insert(bounded_id);
        }
    }

    // Get all Admins overlapping the given coordinates.
    pub fn get(&self, coord: &geo_types::Coordinate<f64>) -> Vec<Arc<Admin>> {
        let point: geo_types::Point<f64> = coord.clone().into();
        // Get a list of overlapping admins...
        let mut admins: Vec<Arc<Admin>> = self
            .rtree
            .locate_all_at_point(&point)
            .map(|bounded_id| bounded_id.admin.clone())
            .collect();
        // Then dedup by zone_type (provided the zone_type is not None)
        // Note that dedup requires a sorted vector.
        admins.sort_by_key(|adm| adm.zone_type);
        admins.dedup_by(|adm1, adm2| {
            if adm1.zone_type != adm2.zone_type {
                false
            } else {
                if adm1.zone_type == None {
                    false
                } else {
                    true
                }
            }
        });
        admins
    }

    /// Return an iterator over admins.
    /// Since we can't modify admins once they are stored in the RTree,
    /// and since this method requires Admins to have their boundary, we create
    /// new admins by cloning the ones in the RTree, and adding their boundary.
    /// Needless to say, this is probably an expensive method...
    pub fn admins(&self) -> impl Iterator<Item = Admin> + '_ {
        self.rtree.iter().map(|bounded_id| {
            let mut admin = Admin::clone(&bounded_id.admin);
            admin.boundary = Some(bounded_id.boundary.clone());
            admin
        })
    }
}

impl Default for AdminGeoFinder {
    fn default() -> Self {
        AdminGeoFinder {
            rtree: RTree::new(),
        }
    }
}

impl FromIterator<Admin> for AdminGeoFinder {
    fn from_iter<I: IntoIterator<Item = Admin>>(admins: I) -> Self {
        let mut geofinder = AdminGeoFinder::default();

        for admin in admins {
            geofinder.insert(admin);
        }

        geofinder
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use cosmogony::ZoneType;
    use geo::prelude::BoundingRect;

    // the goal is that f in [down(f as f32) as f64, up(f as f32) as f64]
    fn down(f: f32) -> f32 {
        f - (f * ::std::f32::EPSILON).abs()
    }
    fn up(f: f32) -> f32 {
        f + (f * ::std::f32::EPSILON).abs()
    }

    #[test]
    fn test_up_down() {
        for &f in [1.0f64, 0., -0., -1., 0.1, -0.1, 0.9, -0.9, 42., -42.].iter() {
            let small_f = f as f32;
            assert!(
                down(small_f) as f64 <= f,
                format!("{} <= {}", down(small_f) as f64, f)
            );
            assert!(
                f <= up(small_f) as f64,
                format!("{} <= {}", f, up(small_f) as f64)
            );
        }
    }

    fn p(x: f64, y: f64) -> geo_types::Point<f64> {
        geo_types::Point(geo_types::Coordinate { x: x, y: y })
    }

    fn make_admin(offset: f64, zt: Option<ZoneType>) -> ::mimir::Admin {
        make_complex_admin(&format!("admin:offset:{}", offset,), offset, zt, 1., None)
    }

    fn make_complex_admin(
        id: &str,
        offset: f64,
        zone_type: Option<ZoneType>,
        zone_size: f64,
        parent_offset: Option<&str>,
    ) -> ::mimir::Admin {
        // the boundary is a big octogon
        // the zone_size param is used to control the area of the zone
        let shape = geo_types::Polygon::new(
            geo_types::LineString(vec![
                (3. * zone_size + offset, 0. * zone_size + offset).into(), //     ^
                (6. * zone_size + offset, 0. * zone_size + offset).into(), //     |   x   x
                (9. * zone_size + offset, 3. * zone_size + offset).into(), //     |
                (9. * zone_size + offset, 6. * zone_size + offset).into(), //     x           x
                (6. * zone_size + offset, 9. * zone_size + offset).into(), //     |
                (3. * zone_size + offset, 9. * zone_size + offset).into(), //     x           x
                (0. * zone_size + offset, 6. * zone_size + offset).into(), //     |
                (0. * zone_size + offset, 3. * zone_size + offset).into(), //     +---x---x------->
                (3. * zone_size + offset, 0. * zone_size + offset).into(), //
            ]),
            vec![],
        );
        let boundary = geo_types::MultiPolygon(vec![shape]);

        let coord = ::mimir::Coord::new(4.0 + offset, 4.0 + offset);
        ::mimir::Admin {
            id: id.into(),
            level: 8,
            name: "city".to_string(),
            label: format!("city {}", offset),
            zip_codes: vec!["421337".to_string()],
            weight: 0f64,
            coord: coord.clone(),
            approx_coord: Some(coord.into()),
            bbox: boundary.bounding_rect(),
            boundary: Some(boundary),
            insee: "outlook".to_string(),
            zone_type: zone_type,
            parent_id: parent_offset.map(|id| id.into()),
            ..Default::default()
        }
    }

    #[test]
    fn test_two_fake_admins() {
        let mut finder = AdminGeoFinder::default();
        finder.insert(make_admin(40., Some(ZoneType::City)));
        finder.insert(make_admin(43., Some(ZoneType::State)));

        // outside
        for coord in [p(48., 41.), p(411., 41.), p(51., 54.), p(53., 53.)].iter() {
            assert!(finder.get(&coord.0).is_empty());
        }

        // inside one
        let admins = finder.get(&p(44., 44.).0);
        assert_eq!(admins.len(), 1);
        assert_eq!(admins[0].id, "admin:offset:40");
        let admins = finder.get(&p(48., 48.).0);
        assert_eq!(admins.len(), 1);
        assert_eq!(admins[0].id, "admin:offset:43");

        // inside two
        let mut admins = finder.get(&p(46., 46.).0);
        admins.sort_by(|a, b| a.id.cmp(&b.id));
        assert_eq!(admins.len(), 2);
        assert_eq!(admins[0].id, "admin:offset:40");
        assert_eq!(admins[1].id, "admin:offset:43");
    }

    #[test]
    fn test_two_admin_same_zone_type() {
        // a point can be associated to only 1 admin type
        // so a point is in 2 city, it is associated to only one
        let mut finder = AdminGeoFinder::default();
        finder.insert(make_admin(40., Some(ZoneType::City)));
        finder.insert(make_admin(43., Some(ZoneType::City)));
        let admins = finder.get(&p(46., 46.).0);
        assert_eq!(admins.len(), 1);
    }

    // #[test]
    // fn test_two_no_zone_type() {
    //     // a point can be associated to only 1 admin type
    //     // but a point can be associated to multiple admin without zone_type
    //     // (for retrocompatibility of the data imported without cosmogony)
    //     let mut finder = AdminGeoFinder::default();
    //     finder.insert(make_admin(40., None));
    //     finder.insert(make_admin(43., None));
    //     let admins = finder.get(&p(46., 46.).0);
    //     assert_eq!(admins.len(), 2);
    // }

    #[test]
    fn test_hierarchy() {
        // In this test we use 3 admin regions that include each other.
        let mut finder = AdminGeoFinder::default();
        finder.insert(make_complex_admin(
            "bob_city",
            40.,
            Some(ZoneType::City),
            1.,
            Some("bob_state"),
        ));
        finder.insert(make_complex_admin(
            "bob_state",
            40.,
            Some(ZoneType::StateDistrict),
            2.,
            Some("bob_country"),
        ));
        finder.insert(make_complex_admin(
            "bob_country",
            40.,
            Some(ZoneType::Country),
            3.,
            None,
        ));

        let admins = finder.get(&p(46., 46.).0);
        assert_eq!(admins.len(), 3);
        assert_eq!(admins[0].id, "bob_city");
        assert_eq!(admins[1].id, "bob_state");
        assert_eq!(admins[2].id, "bob_country");
    }

    #[test]
    fn test_hierarchy_orphan() {
        let mut finder = AdminGeoFinder::default();
        finder.insert(make_complex_admin(
            "bob_city",
            40.,
            Some(ZoneType::City),
            1.,
            Some("bob_state"),
        ));
        finder.insert(make_complex_admin(
            "bob_state",
            40.,
            Some(ZoneType::StateDistrict),
            2.,
            Some("bob_country"),
        ));
        finder.insert(make_complex_admin(
            "bob_country",
            40.,
            Some(ZoneType::Country),
            3.,
            None,
        ));

        // another_state also contains the point, but the geofinder look for only 1 admin by type (it needs only 1 state)
        // since bob_city has been tester first, it's hierarchy has been added automatically
        // so [46., 46.] will not be associated to another_state
        finder.insert(make_complex_admin(
            "another_state",
            40.,
            Some(ZoneType::StateDistrict),
            2.,
            Some("bob_country"),
        ));

        let admins = finder.get(&p(46., 46.).0);
        assert_eq!(admins.len(), 3);
        assert_eq!(admins[0].id, "bob_city");
        assert_eq!(admins[1].id, "another_state");
        assert_eq!(admins[2].id, "bob_country");
    }

    #[test]
    fn test_hierarchy_and_not_typed_zone() {
        let mut finder = AdminGeoFinder::default();
        finder.insert(make_complex_admin(
            "bob_city",
            40.,
            Some(ZoneType::City),
            1.,
            Some("bob_state"),
        ));
        finder.insert(make_complex_admin(
            "bob_state",
            40.,
            Some(ZoneType::StateDistrict),
            2.,
            Some("bob_country"),
        ));
        finder.insert(make_complex_admin(
            "bob_country",
            40.,
            Some(ZoneType::Country),
            3.,
            None,
        ));

        // not_typed zone is outside the hierarchy, but since it contains the point and it has no type it is added
        finder.insert(make_complex_admin("no_typed_zone", 40., None, 2., None));

        let admins = finder.get(&p(46., 46.).0);
        assert_eq!(admins.len(), 4);
        assert_eq!(admins[0].id, "no_typed_zone");
        assert_eq!(admins[1].id, "bob_city");
        assert_eq!(admins[2].id, "bob_state");
        assert_eq!(admins[3].id, "bob_country");
    }
}
<|endoftext|>


<commit_before>use state::editor::Editor;
use state::mode::{Mode, CommandMode};

#[derive(Clone)]
/// A cursor, i.e. a state defining a mode, and a position. The cursor does not define the content
/// of the current file.
pub struct Cursor {
    /// The x coordinate of the cursor
    pub x: usize,
    /// The y coordinate of the cursor
    pub y: usize,
    /// The mode of the cursor
    pub mode: Mode,
}

impl Cursor {
    /// Create a new default cursor
    pub fn new() -> Cursor {
        Cursor {
            x: 0,
            y: 0,
            mode: Mode::Command(CommandMode::Normal),
        }
    }
}

impl Editor {
    /// Get the character under the cursor
    #[inline]
    pub fn current(&self) -> Option<char> {
        let (x, y) = self.pos();
        match self.buffers.current_buffer()[y].chars().nth(x) {
            Some(c) => Some(c),
            None => None,
        }
    }

    /// Get the current cursor
    #[inline]
    pub fn cursor(&self) -> &Cursor {
        let buffer = self.buffers.current_buffer_info();
        buffer.cursors.get(buffer.current_cursor as usize).unwrap()
    }

    /// Get the current cursor mutably
    #[inline]
    pub fn cursor_mut(&mut self) -> &mut Cursor {
        let buffer = self.buffers.current_buffer_info_mut();
        buffer.cursors.get_mut(buffer.current_cursor as usize).unwrap()
    }

    /// Go to next cursor
    #[inline]
    pub fn next_cursor(&mut self) {
        let buffer = self.buffers.current_buffer_info_mut();
        buffer.current_cursor = (buffer.current_cursor.wrapping_add(1)) % (buffer.cursors.len() as u8);
    }

    /// Go to previous cursor
    #[inline]
    pub fn prev_cursor(&mut self) {
        let buffer = self.buffers.current_buffer_info_mut();
        if buffer.current_cursor != 0 {
            buffer.current_cursor -= 1;
        }
        else {
            buffer.current_cursor = buffer.cursors.len() as u8;
        }
    }
}
<commit_msg>Fix the crash when deleting a cursor<commit_after>use state::editor::Editor;
use state::mode::{Mode, CommandMode};

#[derive(Clone)]
/// A cursor, i.e. a state defining a mode, and a position. The cursor does not define the content
/// of the current file.
pub struct Cursor {
    /// The x coordinate of the cursor
    pub x: usize,
    /// The y coordinate of the cursor
    pub y: usize,
    /// The mode of the cursor
    pub mode: Mode,
}

impl Cursor {
    /// Create a new default cursor
    pub fn new() -> Cursor {
        Cursor {
            x: 0,
            y: 0,
            mode: Mode::Command(CommandMode::Normal),
        }
    }
}

impl Editor {
    /// Get the character under the cursor
    #[inline]
    pub fn current(&self) -> Option<char> {
        let (x, y) = self.pos();
        match self.buffers.current_buffer()[y].chars().nth(x) {
            Some(c) => Some(c),
            None => None,
        }
    }

    /// Get the current cursor
    #[inline]
    pub fn cursor(&self) -> &Cursor {
        let buffer = self.buffers.current_buffer_info();
        buffer.cursors.get(buffer.current_cursor as usize).unwrap()
    }

    /// Get the current cursor mutably
    #[inline]
    pub fn cursor_mut(&mut self) -> &mut Cursor {
        let buffer = self.buffers.current_buffer_info_mut();
        buffer.cursors.get_mut(buffer.current_cursor as usize).unwrap()
    }

    /// Go to next cursor
    #[inline]
    pub fn next_cursor(&mut self) {
        let buffer = self.buffers.current_buffer_info_mut();
        buffer.current_cursor = (buffer.current_cursor.wrapping_add(1)) %
                                (buffer.cursors.len() as u8);
    }

    /// Go to previous cursor
    #[inline]
    pub fn prev_cursor(&mut self) {
        let buffer = self.buffers.current_buffer_info_mut();
        if buffer.current_cursor != 0 {
            buffer.current_cursor -= 1;
        } else {
            buffer.current_cursor = (buffer.cursors.len() - 1) as u8;
        }
    }
}
<|endoftext|>


<commit_before>use std::env;
use std::error;
use std::fmt;
use std::fs::File;
use std::io;
use std::io::Read;
use std::path::{Path, PathBuf};
use std::slice;
use std::str;

pub mod cap;

pub struct Desc {
    pub names: Vec<String>,
    pub bools: Vec<bool>,
    pub nums: Vec<u16>,
    pub strings: Vec<String>,
}

impl Desc {
    pub fn file(term_name: &str) -> Option<File> {
        if term_name.is_empty() {
            return None;
        }
        match Path::new(term_name).file_name() {
            Some(fname) if fname == Path::new(term_name).as_os_str() => (),
            _ => return None,
        }

        let first_char = term_name.chars().next().unwrap();
        let first_hex = format!("{:x}", first_char as usize);
        let first_char = first_char.to_string();

        let d1 = to_path(env::var("TERMINFO").ok());
        let d2 = to_path(env::home_dir()).map(|d| d.join(".terminfo"));
        let d3 = to_paths(env::var("TERMINFO_DIRS").ok());
        let d3 = d3.into_iter().map(|d| if d.as_os_str().is_empty() {
                                        PathBuf::from("/usr/share/terminfo")
                                    } else {
                                        d
                                    });
        let d4 = vec![PathBuf::from("/etc/terminfo"),
                      PathBuf::from("/lib/terminfo"),
                      PathBuf::from("/usr/share/terminfo")];
        let ds = d1.into_iter()
            .chain(d2.into_iter())
            .chain(d3)
            .chain(d4.into_iter());

        for d in ds {
            if let Ok(f) = File::open(d.join(&first_char).join(term_name)) {
                return Some(f);
            }
            if let Ok(f) = File::open(d.join(&first_hex).join(term_name)) {
                return Some(f);
            }
        }
        return None;
    }

    pub fn parse(r: &mut Read) -> Result<Desc, ParseError> {
        let header = read_words(r, 6)?;
        if header[0] != 282 {
            return Err(parse_error("wrong magic number"));
        }

        let name_sz = header[1] as usize;
        if name_sz == 0 {
            return Err(parse_error("zero-length name section"));
        }
        let name_buf = read_bytes(r, name_sz)?;
        if name_buf[name_sz - 1] != 0 {
            return Err(parse_error("name section is not null-terminated"));
        }
        let names = str::from_utf8(&name_buf[0..name_sz - 1])?;
        let names: Vec<_> = names.split('|').map(str::to_owned).collect();
        if names.len() < 2 {
            return Err(parse_error("too few items in name section"));
        }

        let bools_num = header[2] as usize;
        if bools_num > cap::NUM_BOOLS {
            return Err(parse_error("too many boolean flags"));
        }
        let bool_buf = read_bytes(r, bools_num)?;
        let bools = bool_buf.into_iter()
            .map(|b| if b == 0 { false } else { true })
            .collect();

        if (name_sz + bools_num) % 2 != 0 {
            read_bytes(r, 1)?;
        }

        let ints_num = header[3] as usize;
        if ints_num > cap::NUM_INTS {
            return Err(parse_error("too many numbers"));
        }
        let nums = read_words(r, ints_num)?;

        let strings_num = header[4] as usize;
        let string_sz = header[5] as usize;
        if strings_num > cap::NUM_STRINGS {
            return Err(parse_error("too many strings"));
        }
        let offsets = read_words(r, strings_num)?;
        let str_table = read_bytes(r, string_sz)?;
        let mut strings = Vec::new();
        for pos in offsets {
            let pos = pos as usize;
            if pos == 0xffff {
                strings.push(String::new());
            } else if pos >= string_sz {
                return Err(parse_error("invalid string offset"));
            } else {
                match str_table[pos..].iter().position(|&b| b == 0) {
                    None => return Err(parse_error("unterminated string")),
                    Some(end) => {
                        let s = str::from_utf8(&str_table[pos..pos + end])?;
                        strings.push(s.to_owned());
                    }
                }
            }
        }

        Ok(Desc {
               names: names,
               bools: bools,
               nums: nums,
               strings: strings,
           })
    }
}

#[derive(Debug)]
pub struct ParseError {
    inner: ParseErrorImpl,
}

fn parse_error(msg: &str) -> ParseError {
    ParseError { inner: ParseErrorImpl::Other(msg.to_owned()) }
}

#[derive(Debug)]
enum ParseErrorImpl {
    Io(io::Error),
    Other(String),
}

impl fmt::Display for ParseError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self.inner {
            ParseErrorImpl::Io(ref err) => err.fmt(f),
            ParseErrorImpl::Other(ref msg) => write!(f, "{}", msg),
        }
    }
}

impl error::Error for ParseError {
    fn description(&self) -> &str {
        match self.inner {
            ParseErrorImpl::Io(ref err) => err.description(),
            _ => "invalid terminfo description",
        }
    }

    fn cause(&self) -> Option<&error::Error> {
        match self.inner {
            ParseErrorImpl::Io(ref err) => err.cause(),
            _ => None,
        }
    }
}

impl From<io::Error> for ParseError {
    fn from(err: io::Error) -> ParseError {
        ParseError { inner: ParseErrorImpl::Io(err) }
    }
}

impl From<str::Utf8Error> for ParseError {
    fn from(err: str::Utf8Error) -> ParseError {
        parse_error(&err.to_string())
    }
}

fn to_path<T: Into<PathBuf>>(var: Option<T>) -> Option<PathBuf> {
    match var {
        Some(d) => {
            let d = d.into();
            if d.as_os_str().is_empty() {
                None
            } else {
                Some(d)
            }
        }
        None => None,
    }
}

fn to_paths(var: Option<String>) -> Vec<PathBuf> {
    match var {
        None => Vec::new(),
        Some(ref d) if d.is_empty() => Vec::new(),
        Some(d) => env::split_paths(&d).collect(),
    }
}

fn read_bytes(r: &mut Read, n: usize) -> io::Result<Vec<u8>> {
    let mut buf = Vec::with_capacity(n);
    if r.take(n as u64).read_to_end(&mut buf)? < n {
        return Err(io::Error::new(io::ErrorKind::UnexpectedEof,
                                  "failed to fill whole buffer"));
    }
    Ok(buf)
}

fn read_words(r: &mut Read, n: usize) -> io::Result<Vec<u16>> {
    let mut buf_16: Vec<u16> = vec![0; n];
    let mut buf_8 = unsafe {
        slice::from_raw_parts_mut(buf_16.as_mut_ptr() as *mut u8, n * 2)
    };
    r.read_exact(&mut buf_8)?;
    if cfg!(target_endian = "big") {
        for w in &mut buf_16 {
            *w = w.swap_bytes();
        }
    }
    Ok(buf_16)
}
<commit_msg>Desc::file returns Result instead of Option<commit_after>use std::env;
use std::error;
use std::fmt;
use std::fs::File;
use std::io;
use std::io::Read;
use std::path::{Path, PathBuf};
use std::slice;
use std::str;

pub mod cap;

pub struct Desc {
    pub names: Vec<String>,
    pub bools: Vec<bool>,
    pub nums: Vec<u16>,
    pub strings: Vec<String>,
}

impl Desc {
    pub fn file(term_name: &str) -> Result<File, DescError> {
        if term_name.is_empty() {
            return Err(name_error(term_name));
        }
        match Path::new(term_name).file_name() {
            Some(fname) if fname == Path::new(term_name).as_os_str() => (),
            _ => return Err(name_error(term_name)),
        }

        let first_char = term_name.chars().next().unwrap();
        let first_hex = format!("{:x}", first_char as usize);
        let first_char = first_char.to_string();

        let d1 = to_path(env::var("TERMINFO").ok());
        let d2 = to_path(env::home_dir()).map(|d| d.join(".terminfo"));
        let d3 = to_paths(env::var("TERMINFO_DIRS").ok());
        let d3 = d3.into_iter().map(|d| if d.as_os_str().is_empty() {
                                        PathBuf::from("/usr/share/terminfo")
                                    } else {
                                        d
                                    });
        let d4 = vec![PathBuf::from("/etc/terminfo"),
                      PathBuf::from("/lib/terminfo"),
                      PathBuf::from("/usr/share/terminfo")];
        let ds = d1.into_iter()
            .chain(d2.into_iter())
            .chain(d3)
            .chain(d4.into_iter());

        for d in ds {
            if let Ok(f) = File::open(d.join(&first_char).join(term_name)) {
                return Ok(f);
            }
            if let Ok(f) = File::open(d.join(&first_hex).join(term_name)) {
                return Ok(f);
            }
        }
        return Err(absent_error(term_name));
    }

    pub fn parse(r: &mut Read) -> Result<Desc, DescError> {
        let header = read_words(r, 6)?;
        if header[0] != 282 {
            return Err(parse_error("wrong magic number"));
        }

        let name_sz = header[1] as usize;
        if name_sz == 0 {
            return Err(parse_error("zero-length name section"));
        }
        let name_buf = read_bytes(r, name_sz)?;
        if name_buf[name_sz - 1] != 0 {
            return Err(parse_error("name section is not null-terminated"));
        }
        let names = str::from_utf8(&name_buf[0..name_sz - 1])?;
        let names: Vec<_> = names.split('|').map(str::to_owned).collect();
        if names.len() < 2 {
            return Err(parse_error("too few items in name section"));
        }

        let bools_num = header[2] as usize;
        if bools_num > cap::NUM_BOOLS {
            return Err(parse_error("too many boolean flags"));
        }
        let bool_buf = read_bytes(r, bools_num)?;
        let bools = bool_buf.into_iter()
            .map(|b| if b == 0 { false } else { true })
            .collect();

        if (name_sz + bools_num) % 2 != 0 {
            read_bytes(r, 1)?;
        }

        let ints_num = header[3] as usize;
        if ints_num > cap::NUM_INTS {
            return Err(parse_error("too many numbers"));
        }
        let nums = read_words(r, ints_num)?;

        let strings_num = header[4] as usize;
        let string_sz = header[5] as usize;
        if strings_num > cap::NUM_STRINGS {
            return Err(parse_error("too many strings"));
        }
        let offsets = read_words(r, strings_num)?;
        let str_table = read_bytes(r, string_sz)?;
        let mut strings = Vec::new();
        for pos in offsets {
            let pos = pos as usize;
            if pos == 0xffff {
                strings.push(String::new());
            } else if pos >= string_sz {
                return Err(parse_error("invalid string offset"));
            } else {
                match str_table[pos..].iter().position(|&b| b == 0) {
                    None => return Err(parse_error("unterminated string")),
                    Some(end) => {
                        let s = str::from_utf8(&str_table[pos..pos + end])?;
                        strings.push(s.to_owned());
                    }
                }
            }
        }

        Ok(Desc {
               names: names,
               bools: bools,
               nums: nums,
               strings: strings,
           })
    }
}

#[derive(Debug)]
pub struct DescError {
    inner: DescErrorImpl,
}

fn parse_error(msg: &str) -> DescError {
    DescError { inner: DescErrorImpl::Parse(msg.to_owned()) }
}

fn absent_error(name: &str) -> DescError {
    DescError { inner: DescErrorImpl::Absent(name.to_owned()) }
}

fn name_error(name: &str) -> DescError {
    DescError { inner: DescErrorImpl::Name(name.to_owned()) }
}

#[derive(Debug)]
enum DescErrorImpl {
    Io(io::Error),
    Parse(String),
    Absent(String),
    Name(String),
}

impl fmt::Display for DescError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self.inner {
            DescErrorImpl::Io(ref err) => err.fmt(f),
            DescErrorImpl::Parse(ref msg) => write!(f, "{}", msg),
            DescErrorImpl::Absent(ref name) => {
                write!(f, "no description found for {}", name)
            }
            DescErrorImpl::Name(ref name) => {
                write!(f, "invalid terminal name '{}'", name)
            }
        }
    }
}

impl error::Error for DescError {
    fn description(&self) -> &str {
        match self.inner {
            DescErrorImpl::Io(ref err) => err.description(),
            DescErrorImpl::Parse(..) => "invalid terminfo description",
            DescErrorImpl::Absent(..) => "missing terminfo description",
            DescErrorImpl::Name(..) => "invalid terminal name",
        }
    }

    fn cause(&self) -> Option<&error::Error> {
        match self.inner {
            DescErrorImpl::Io(ref err) => err.cause(),
            _ => None,
        }
    }
}

impl From<io::Error> for DescError {
    fn from(err: io::Error) -> DescError {
        DescError { inner: DescErrorImpl::Io(err) }
    }
}

impl From<str::Utf8Error> for DescError {
    fn from(err: str::Utf8Error) -> DescError {
        parse_error(&err.to_string())
    }
}

fn to_path<T: Into<PathBuf>>(var: Option<T>) -> Option<PathBuf> {
    match var {
        Some(d) => {
            let d = d.into();
            if d.as_os_str().is_empty() {
                None
            } else {
                Some(d)
            }
        }
        None => None,
    }
}

fn to_paths(var: Option<String>) -> Vec<PathBuf> {
    match var {
        None => Vec::new(),
        Some(ref d) if d.is_empty() => Vec::new(),
        Some(d) => env::split_paths(&d).collect(),
    }
}

fn read_bytes(r: &mut Read, n: usize) -> io::Result<Vec<u8>> {
    let mut buf = Vec::with_capacity(n);
    if r.take(n as u64).read_to_end(&mut buf)? < n {
        return Err(io::Error::new(io::ErrorKind::UnexpectedEof,
                                  "failed to fill whole buffer"));
    }
    Ok(buf)
}

fn read_words(r: &mut Read, n: usize) -> io::Result<Vec<u16>> {
    let mut buf_16: Vec<u16> = vec![0; n];
    let mut buf_8 = unsafe {
        slice::from_raw_parts_mut(buf_16.as_mut_ptr() as *mut u8, n * 2)
    };
    r.read_exact(&mut buf_8)?;
    if cfg!(target_endian = "big") {
        for w in &mut buf_16 {
            *w = w.swap_bytes();
        }
    }
    Ok(buf_16)
}
<|endoftext|>


<commit_before>use std::collections::hash_map::HashMap;
use std::collections::hash_set::HashSet;
use std::fmt::{Display, Formatter, Error};
use std::string::String;
use std::vec::Vec;

use alloc_box::AllocBox;
use super::binding::UniqueBinding;
use super::js_var::{JsVar, JsKey, JsType, JsPtrEnum};

macro_rules! ptr_type_mismatch {
    ($tag:expr, $ptr:expr) => {
        panic!("Pointer type mismatch: expected {:?} but received {:?}", $tag, $ptr);
    }
}

#[derive(Clone, Debug)]
pub struct JsObjStruct {
    pub proto: JsProto,
    pub name: String,
    pub dict: HashMap<JsKey, JsVar>,
}

impl JsObjStruct {
    #[allow(unused_variables)]
    pub fn new(proto: JsProto, name: &str, kv_tuples: Vec<(JsKey, JsVar, Option<JsPtrEnum>)>,
               allocator: &mut AllocBox) -> JsObjStruct {
        JsObjStruct {
            proto: None,
            name: String::from(name),
            dict: kv_tuples.into_iter().map(|(k, v, ptr)| {
                match v.t {
                    JsType::JsPtr(ref tag) => match ptr {
                        Some(ptr) => {
                            if tag.eq_ptr_type(&ptr) {
                                allocator.alloc(v.unique.clone(), ptr).expect("Unable to allocate!"); // TODO better error handling
                            } else {
                                ptr_type_mismatch!(tag, ptr);
                            }
                        },
                        None => ptr_type_mismatch!(tag, None::<JsPtrEnum>),
                    },
                    _ => match ptr {
                        Some(ptr) => ptr_type_mismatch!(None::<JsPtrEnum>, ptr),
                        None => {},
                    },
                }
                (k, v)
            }).collect()
        }
    }

    pub fn add_key(&mut self, k: JsKey, v: JsVar, ptr: Option<JsPtrEnum>, allocator: &mut AllocBox) {
        println!("{:#?}", self);
        // If the key already exists, potentially condemn its pointer, which is being overwritten.
        if let Some(var) = self.dict.get(&k) {
            println!("VAR");
            match var.t {
                JsType::JsPtr(_) => { println!("CONDEMN"); allocator.condemn(var.unique.clone()).expect("Unable to whiten!") },
                _ => {}
            }
        }
        // Then, allocate the new pointer if necessary...
        if let Some(ptr) = ptr {
            println!("POINTER");
            allocator.alloc(v.unique.clone(), ptr).expect("Unable to allocate!"); // TODO better error handling
        }
        // ...and insert the key & value into the dictionary blindly.
        self.dict.insert(k, v);
        println!("DONE");
        println!("{:#?}", self);
    }

    pub fn remove_key(&mut self, k: &JsKey, allocate: &mut AllocBox) -> Option<(JsVar, Option<JsPtrEnum>)>{
        if let Some(var) = self.dict.remove(k) {
            let ptr = allocator.borrow_mut().remove_binding(var.unique.clone());
            Some((var, ptr))
        } else {
            None
        }
    }

    pub fn get_children(&self) -> HashSet<UniqueBinding> {
        let mut bindings = HashSet::new();
        for v in self.dict.values() {
            match v.t {
                JsType::JsPtr(_) => { bindings.insert(v.unique.clone()); },
                _ => (),
            }
        }
        bindings
    }
}

impl Display for JsObjStruct {
    fn fmt(&self, mut fmt: &mut Formatter) -> Result<(), Error> {
        try!(write!(fmt, "{{ "));

        for (i, (ref key, ref val)) in self.dict.iter().enumerate() {
            if i != 0 {
                try!(write!(fmt, ", "));
            }

            try!(write!(fmt, "{}: {}", key, val));
        }

        write!(fmt, " }}")
    }
}

pub type JsProto = Option<Box<JsObjStruct>>;

// TODO nice JS object creation macro
//macro_rules! js_obj {
//    ( $kt:ty : $ke:expr => $vt:ty : $ve:expr ),* {
//        {
//
//        }
//    };
//}
<commit_msg>Fix remove_key method<commit_after>use std::collections::hash_map::HashMap;
use std::collections::hash_set::HashSet;
use std::fmt::{Display, Formatter, Error};
use std::string::String;
use std::vec::Vec;

use alloc_box::AllocBox;
use super::binding::UniqueBinding;
use super::js_var::{JsVar, JsKey, JsType, JsPtrEnum};

macro_rules! ptr_type_mismatch {
    ($tag:expr, $ptr:expr) => {
        panic!("Pointer type mismatch: expected {:?} but received {:?}", $tag, $ptr);
    }
}

#[derive(Clone, Debug)]
pub struct JsObjStruct {
    pub proto: JsProto,
    pub name: String,
    pub dict: HashMap<JsKey, JsVar>,
}

impl JsObjStruct {
    #[allow(unused_variables)]
    pub fn new(proto: JsProto, name: &str, kv_tuples: Vec<(JsKey, JsVar, Option<JsPtrEnum>)>,
               allocator: &mut AllocBox) -> JsObjStruct {
        JsObjStruct {
            proto: None,
            name: String::from(name),
            dict: kv_tuples.into_iter().map(|(k, v, ptr)| {
                match v.t {
                    JsType::JsPtr(ref tag) => match ptr {
                        Some(ptr) => {
                            if tag.eq_ptr_type(&ptr) {
                                allocator.alloc(v.unique.clone(), ptr).expect("Unable to allocate!"); // TODO better error handling
                            } else {
                                ptr_type_mismatch!(tag, ptr);
                            }
                        },
                        None => ptr_type_mismatch!(tag, None::<JsPtrEnum>),
                    },
                    _ => match ptr {
                        Some(ptr) => ptr_type_mismatch!(None::<JsPtrEnum>, ptr),
                        None => {},
                    },
                }
                (k, v)
            }).collect()
        }
    }

    pub fn add_key(&mut self, k: JsKey, v: JsVar, ptr: Option<JsPtrEnum>, allocator: &mut AllocBox) {
        println!("{:#?}", self);
        // If the key already exists, potentially condemn its pointer, which is being overwritten.
        if let Some(var) = self.dict.get(&k) {
            println!("VAR");
            match var.t {
                JsType::JsPtr(_) => { println!("CONDEMN"); allocator.condemn(var.unique.clone()).expect("Unable to whiten!") },
                _ => {}
            }
        }
        // Then, allocate the new pointer if necessary...
        if let Some(ptr) = ptr {
            println!("POINTER");
            allocator.alloc(v.unique.clone(), ptr).expect("Unable to allocate!"); // TODO better error handling
        }
        // ...and insert the key & value into the dictionary blindly.
        self.dict.insert(k, v);
        println!("DONE");
        println!("{:#?}", self);
    }

    pub fn remove_key(&mut self, k: &JsKey, allocator: &mut AllocBox) -> Option<(JsVar, Option<JsPtrEnum>)>{
        if let Some(var) = self.dict.remove(k) {
            let ptr = allocator.find_id(&var.unique).map(|s| s.borrow().clone());
            allocator.condemn(var.unique.clone()).expect("Unable to whiten!");
            Some((var, ptr))
        } else {
            None
        }
    }

    pub fn get_children(&self) -> HashSet<UniqueBinding> {
        let mut bindings = HashSet::new();
        for v in self.dict.values() {
            match v.t {
                JsType::JsPtr(_) => { bindings.insert(v.unique.clone()); },
                _ => (),
            }
        }
        bindings
    }
}

impl Display for JsObjStruct {
    fn fmt(&self, mut fmt: &mut Formatter) -> Result<(), Error> {
        try!(write!(fmt, "{{ "));

        for (i, (ref key, ref val)) in self.dict.iter().enumerate() {
            if i != 0 {
                try!(write!(fmt, ", "));
            }

            try!(write!(fmt, "{}: {}", key, val));
        }

        write!(fmt, " }}")
    }
}

pub type JsProto = Option<Box<JsObjStruct>>;

// TODO nice JS object creation macro
//macro_rules! js_obj {
//    ( $kt:ty : $ke:expr => $vt:ty : $ve:expr ),* {
//        {
//
//        }
//    };
//}
<|endoftext|>


<commit_before>use camera::Camera;
use event::{Action, Key, MouseButton, WindowEvent};
use na::{self, Isometry3, Matrix4, Perspective3, Point3, Vector2, Vector3};
use resource::ShaderUniform;
use std::f32;
use window::Canvas;

/// Arc-ball camera mode.
///
/// An arc-ball camera is a camera rotating around a fixed point (the focus point) and always
/// looking at it. The following inputs are handled:
///
/// * Left button press + drag - rotates the camera around the focus point
/// * Right button press + drag - translates the focus point on the plane orthogonal to the view
/// direction
/// * Scroll in/out - zoom in/out
/// * Enter key - set the focus point to the origin
#[derive(Clone, Debug)]
pub struct ArcBall {
    /// The focus point.
    at: Point3<f32>,
    /// Yaw of the camera (rotation along the y axis).
    yaw: f32,
    /// Pitch of the camera (rotation along the x axis).
    pitch: f32,
    /// Distance from the camera to the `at` focus point.
    dist: f32,

    /// Increment of the yaw per unit mouse movement. The default value is 0.005.
    yaw_step: f32,
    /// Increment of the pitch per unit mouse movement. The default value is 0.005.
    pitch_step: f32,
    /// Increment of the distance per unit scrolling. The default value is 40.0.
    dist_step: f32,
    rotate_button: Option<MouseButton>,
    drag_button: Option<MouseButton>,
    reset_key: Option<Key>,

    projection: Perspective3<f32>,
    view: Matrix4<f32>,
    proj: Matrix4<f32>,
    proj_view: Matrix4<f32>,
    inverse_proj_view: Matrix4<f32>,
    last_cursor_pos: Vector2<f32>,
    up_axis: Vector3<f32>,
}

impl ArcBall {
    /// Create a new arc-ball camera.
    pub fn new(eye: Point3<f32>, at: Point3<f32>) -> ArcBall {
        ArcBall::new_with_frustrum(f32::consts::PI / 4.0, 0.1, 1024.0, eye, at)
    }

    /// Creates a new arc ball camera with default sensitivity values.
    pub fn new_with_frustrum(
        fov: f32,
        znear: f32,
        zfar: f32,
        eye: Point3<f32>,
        at: Point3<f32>,
    ) -> ArcBall {
        let mut res = ArcBall {
            at: Point3::new(0.0, 0.0, 0.0),
            yaw: 0.0,
            pitch: 0.0,
            dist: 0.0,
            yaw_step: 0.005,
            pitch_step: 0.005,
            dist_step: 40.0,
            rotate_button: Some(MouseButton::Button1),
            drag_button: Some(MouseButton::Button2),
            reset_key: Some(Key::Return),
            projection: Perspective3::new(800.0 / 600.0, fov, znear, zfar),
            view: na::zero(),
            proj: na::zero(),
            proj_view: na::zero(),
            inverse_proj_view: na::zero(),
            last_cursor_pos: na::zero(),
            up_axis: Vector3::y(),
        };

        res.look_at(eye, at);

        res
    }

    /// The point the arc-ball is looking at.
    pub fn at(&self) -> Point3<f32> {
        self.at
    }

    /// Get a mutable reference to the point the camera is looking at.
    pub fn set_at(&mut self, at: Point3<f32>) {
        self.at = at;
        self.update_projviews();
    }

    /// The arc-ball camera `yaw`.
    pub fn yaw(&self) -> f32 {
        self.yaw
    }

    /// Sets the camera `yaw`. Change this to modify the rotation along the `up` axis.
    pub fn set_yaw(&mut self, yaw: f32) {
        self.yaw = yaw;

        self.update_restrictions();
        self.update_projviews();
    }

    /// The arc-ball camera `pitch`.
    pub fn pitch(&self) -> f32 {
        self.pitch
    }

    /// Sets the camera `pitch`.
    pub fn set_pitch(&mut self, pitch: f32) {
        self.pitch = pitch;

        self.update_restrictions();
        self.update_projviews();
    }

    /// The distance from the camera position to its view point.
    pub fn dist(&self) -> f32 {
        self.dist
    }

    /// Move the camera such that it is at a given distance from the view point.
    pub fn set_dist(&mut self, dist: f32) {
        self.dist = dist;

        self.update_restrictions();
        self.update_projviews();
    }

    /// Move and orient the camera such that it looks at a specific point.
    pub fn look_at(&mut self, eye: Point3<f32>, at: Point3<f32>) {
        let dist = na::norm(&(eye - at));
        let pitch = ((eye.y - at.y) / dist).acos();
        let yaw = (eye.z - at.z).atan2(eye.x - at.x);

        self.at = at;
        self.dist = dist;
        self.yaw = yaw;
        self.pitch = pitch;

        self.update_restrictions();
        self.update_projviews();
    }

    /// Transformation applied by the camera without perspective.
    fn update_restrictions(&mut self) {
        if self.dist < 0.00001 {
            self.dist = 0.00001
        }

        if self.pitch <= 0.01 {
            self.pitch = 0.01
        }

        let _pi: f32 = f32::consts::PI;
        if self.pitch > _pi - 0.01 {
            self.pitch = _pi - 0.01
        }
    }

    /// The button used to rotate the ArcBall camera.
    pub fn rotate_button(&self) -> Option<MouseButton> {
        self.rotate_button
    }

    /// Set the button used to rotate the ArcBall camera.
    /// Use None to disable rotation.
    pub fn rebind_rotate_button(&mut self, new_button: Option<MouseButton>) {
        self.rotate_button = new_button;
    }

    /// The button used to drag the ArcBall camera.
    pub fn drag_button(&self) -> Option<MouseButton> {
        self.drag_button
    }

    /// Set the button used to drag the ArcBall camera.
    /// Use None to disable dragging.
    pub fn rebind_drag_button(&mut self, new_button: Option<MouseButton>) {
        self.drag_button = new_button;
    }

    /// The key used to reset the ArcBall camera.
    pub fn reset_key(&self) -> Option<Key> {
        self.reset_key
    }

    /// Set the key used to reset the ArcBall camera.
    /// Use None to disable reset.
    pub fn rebind_reset_key(&mut self, new_key: Option<Key>) {
        self.reset_key = new_key;
    }

    fn handle_left_button_displacement(&mut self, dpos: &Vector2<f32>) {
        self.yaw = self.yaw + dpos.x * self.yaw_step;
        self.pitch = self.pitch - dpos.y * self.pitch_step;

        self.update_restrictions();
        self.update_projviews();
    }

    fn handle_right_button_displacement(&mut self, dpos: &Vector2<f32>) {
        let eye = self.eye();
        let dir = na::normalize(&(self.at - eye));
        let tangent = na::normalize(&Vector3::y().cross(&dir));
        let bitangent = dir.cross(&tangent);
        let mult = self.dist / 1000.0;

        self.at = self.at + tangent * (dpos.x * mult) + bitangent * (dpos.y * mult);
        self.update_projviews();
    }

    fn handle_scroll(&mut self, off: f32) {
        self.dist = self.dist + self.dist_step * (off) / 120.0;
        self.update_restrictions();
        self.update_projviews();
    }

    fn update_projviews(&mut self) {
        self.proj = *self.projection.as_matrix();
        self.view = self.view_transform().to_homogeneous();
        self.proj_view = self.proj * self.view;
        self.inverse_proj_view = self.proj_view.try_inverse().unwrap();
    }

    #[inline]
    pub fn set_up_axis(&mut self, up_axis: Vector3<f32>) {
        self.up_axis = up_axis;
    }

}

impl Camera for ArcBall {
    fn clip_planes(&self) -> (f32, f32) {
        (self.projection.znear(), self.projection.zfar())
    }

    fn view_transform(&self) -> Isometry3<f32> {
        Isometry3::look_at_rh(&self.eye(), &self.at,  &self.up_axis)
    }

    fn eye(&self) -> Point3<f32> {
        let px = self.at.x + self.dist * self.yaw.cos() * self.pitch.sin();
        let py = self.at.y + self.dist * self.pitch.cos();
        let pz = self.at.z + self.dist * self.yaw.sin() * self.pitch.sin();

        Point3::new(px, py, pz)
    }

    fn handle_event(&mut self, canvas: &Canvas, event: &WindowEvent) {
        match *event {
            WindowEvent::CursorPos(x, y, _) => {
                let curr_pos = Vector2::new(x as f32, y as f32);

                if let Some(rotate_button) = self.rotate_button {
                    if canvas.get_mouse_button(rotate_button) == Action::Press {
                        let dpos = curr_pos - self.last_cursor_pos;
                        self.handle_left_button_displacement(&dpos)
                    }
                }

                if let Some(drag_button) = self.drag_button {
                    if canvas.get_mouse_button(drag_button) == Action::Press {
                        let dpos = curr_pos - self.last_cursor_pos;
                        self.handle_right_button_displacement(&dpos)
                    }
                }

                self.last_cursor_pos = curr_pos;
            }
            WindowEvent::Key(key, Action::Press, _) if Some(key) == self.reset_key => {
                self.at = Point3::origin();
                self.update_projviews();
            }
            WindowEvent::Scroll(_, off, _) => self.handle_scroll(off as f32),
            WindowEvent::FramebufferSize(w, h) => {
                self.projection.set_aspect(w as f32 / h as f32);
                self.update_projviews();
            }
            _ => {}
        }
    }

    #[inline]
    fn upload(
        &self,
        _: usize,
        proj: &mut ShaderUniform<Matrix4<f32>>,
        view: &mut ShaderUniform<Matrix4<f32>>,
    ) {
        proj.upload(&self.proj);
        view.upload(&self.view);
    }

    fn transformation(&self) -> Matrix4<f32> {
        self.proj_view
    }

    fn inverse_transformation(&self) -> Matrix4<f32> {
        self.inverse_proj_view
    }

    fn update(&mut self, _: &Canvas) {}
}
<commit_msg>Add min/max distance settings to arcball camera<commit_after>use camera::Camera;
use event::{Action, Key, MouseButton, WindowEvent};
use na::{self, Isometry3, Matrix4, Perspective3, Point3, Vector2, Vector3};
use resource::ShaderUniform;
use std::f32;
use window::Canvas;

/// Arc-ball camera mode.
///
/// An arc-ball camera is a camera rotating around a fixed point (the focus point) and always
/// looking at it. The following inputs are handled:
///
/// * Left button press + drag - rotates the camera around the focus point
/// * Right button press + drag - translates the focus point on the plane orthogonal to the view
/// direction
/// * Scroll in/out - zoom in/out
/// * Enter key - set the focus point to the origin
#[derive(Clone, Debug)]
pub struct ArcBall {
    /// The focus point.
    at: Point3<f32>,
    /// Yaw of the camera (rotation along the y axis).
    yaw: f32,
    /// Pitch of the camera (rotation along the x axis).
    pitch: f32,
    /// Distance from the camera to the `at` focus point.
    dist: f32,
    /// Minimum distance from the camera to the `at` focus point.
    min_dist: f32,
    /// Maximum distance from the camera to the `at` focus point.
    max_dist: f32,

    /// Increment of the yaw per unit mouse movement. The default value is 0.005.
    yaw_step: f32,
    /// Increment of the pitch per unit mouse movement. The default value is 0.005.
    pitch_step: f32,
    /// Increment of the distance per unit scrolling. The default value is 40.0.
    dist_step: f32,
    rotate_button: Option<MouseButton>,
    drag_button: Option<MouseButton>,
    reset_key: Option<Key>,

    projection: Perspective3<f32>,
    view: Matrix4<f32>,
    proj: Matrix4<f32>,
    proj_view: Matrix4<f32>,
    inverse_proj_view: Matrix4<f32>,
    last_cursor_pos: Vector2<f32>,
    up_axis: Vector3<f32>,
}

impl ArcBall {
    /// Create a new arc-ball camera.
    pub fn new(eye: Point3<f32>, at: Point3<f32>) -> ArcBall {
        ArcBall::new_with_frustrum(f32::consts::PI / 4.0, 0.1, 1024.0, eye, at)
    }

    /// Creates a new arc ball camera with default sensitivity values.
    pub fn new_with_frustrum(
        fov: f32,
        znear: f32,
        zfar: f32,
        eye: Point3<f32>,
        at: Point3<f32>,
    ) -> ArcBall {
        let mut res = ArcBall {
            at: Point3::new(0.0, 0.0, 0.0),
            yaw: 0.0,
            pitch: 0.0,
            dist: 0.0,
            min_dist: 0.00001,
            max_dist: std::f32::MAX,
            yaw_step: 0.005,
            pitch_step: 0.005,
            dist_step: 40.0,
            rotate_button: Some(MouseButton::Button1),
            drag_button: Some(MouseButton::Button2),
            reset_key: Some(Key::Return),
            projection: Perspective3::new(800.0 / 600.0, fov, znear, zfar),
            view: na::zero(),
            proj: na::zero(),
            proj_view: na::zero(),
            inverse_proj_view: na::zero(),
            last_cursor_pos: na::zero(),
            up_axis: Vector3::y(),
        };

        res.look_at(eye, at);

        res
    }

    /// The point the arc-ball is looking at.
    pub fn at(&self) -> Point3<f32> {
        self.at
    }

    /// Get a mutable reference to the point the camera is looking at.
    pub fn set_at(&mut self, at: Point3<f32>) {
        self.at = at;
        self.update_projviews();
    }

    /// The arc-ball camera `yaw`.
    pub fn yaw(&self) -> f32 {
        self.yaw
    }

    /// Sets the camera `yaw`. Change this to modify the rotation along the `up` axis.
    pub fn set_yaw(&mut self, yaw: f32) {
        self.yaw = yaw;

        self.update_restrictions();
        self.update_projviews();
    }

    /// The arc-ball camera `pitch`.
    pub fn pitch(&self) -> f32 {
        self.pitch
    }

    /// Sets the camera `pitch`.
    pub fn set_pitch(&mut self, pitch: f32) {
        self.pitch = pitch;

        self.update_restrictions();
        self.update_projviews();
    }

    /// The distance from the camera position to its view point.
    pub fn dist(&self) -> f32 {
        self.dist
    }

    /// Move the camera such that it is at a given distance from the view point.
    pub fn set_dist(&mut self, dist: f32) {
        self.dist = dist;

        self.update_restrictions();
        self.update_projviews();
    }

    /// The minimum distance from the camera position to its view point.
    pub fn min_dist(&self) -> f32 {
        self.min_dist
    }

    /// Set the minimum distance from the camera position to its view point.
    pub fn set_min_dist(&mut self, min_dist: f32) {
        self.min_dist = min_dist;
    }

    /// The maximum distance from the camera position to its view point.
    pub fn max_dist(&self) -> f32 {
        self.max_dist
    }

    /// Set the maximum distance from the camera position to its view point.
    pub fn set_max_dist(&mut self, max_dist: f32) {
        self.max_dist = max_dist;
    }

    /// Move and orient the camera such that it looks at a specific point.
    pub fn look_at(&mut self, eye: Point3<f32>, at: Point3<f32>) {
        let dist = na::norm(&(eye - at));
        let pitch = ((eye.y - at.y) / dist).acos();
        let yaw = (eye.z - at.z).atan2(eye.x - at.x);

        self.at = at;
        self.dist = dist;
        self.yaw = yaw;
        self.pitch = pitch;

        self.update_restrictions();
        self.update_projviews();
    }

    /// Transformation applied by the camera without perspective.
    fn update_restrictions(&mut self) {
        if self.dist < self.min_dist {
            self.dist = self.min_dist
        }

        if self.dist > self.max_dist {
            self.dist = self.max_dist
        }

        if self.pitch <= 0.01 {
            self.pitch = 0.01
        }

        let _pi: f32 = f32::consts::PI;
        if self.pitch > _pi - 0.01 {
            self.pitch = _pi - 0.01
        }
    }

    /// The button used to rotate the ArcBall camera.
    pub fn rotate_button(&self) -> Option<MouseButton> {
        self.rotate_button
    }

    /// Set the button used to rotate the ArcBall camera.
    /// Use None to disable rotation.
    pub fn rebind_rotate_button(&mut self, new_button: Option<MouseButton>) {
        self.rotate_button = new_button;
    }

    /// The button used to drag the ArcBall camera.
    pub fn drag_button(&self) -> Option<MouseButton> {
        self.drag_button
    }

    /// Set the button used to drag the ArcBall camera.
    /// Use None to disable dragging.
    pub fn rebind_drag_button(&mut self, new_button: Option<MouseButton>) {
        self.drag_button = new_button;
    }

    /// The key used to reset the ArcBall camera.
    pub fn reset_key(&self) -> Option<Key> {
        self.reset_key
    }

    /// Set the key used to reset the ArcBall camera.
    /// Use None to disable reset.
    pub fn rebind_reset_key(&mut self, new_key: Option<Key>) {
        self.reset_key = new_key;
    }

    fn handle_left_button_displacement(&mut self, dpos: &Vector2<f32>) {
        self.yaw = self.yaw + dpos.x * self.yaw_step;
        self.pitch = self.pitch - dpos.y * self.pitch_step;

        self.update_restrictions();
        self.update_projviews();
    }

    fn handle_right_button_displacement(&mut self, dpos: &Vector2<f32>) {
        let eye = self.eye();
        let dir = na::normalize(&(self.at - eye));
        let tangent = na::normalize(&Vector3::y().cross(&dir));
        let bitangent = dir.cross(&tangent);
        let mult = self.dist / 1000.0;

        self.at = self.at + tangent * (dpos.x * mult) + bitangent * (dpos.y * mult);
        self.update_projviews();
    }

    fn handle_scroll(&mut self, off: f32) {
        self.dist = self.dist + self.dist_step * (off) / 120.0;
        self.update_restrictions();
        self.update_projviews();
    }

    fn update_projviews(&mut self) {
        self.proj = *self.projection.as_matrix();
        self.view = self.view_transform().to_homogeneous();
        self.proj_view = self.proj * self.view;
        self.inverse_proj_view = self.proj_view.try_inverse().unwrap();
    }

    #[inline]
    pub fn set_up_axis(&mut self, up_axis: Vector3<f32>) {
        self.up_axis = up_axis;
    }

}

impl Camera for ArcBall {
    fn clip_planes(&self) -> (f32, f32) {
        (self.projection.znear(), self.projection.zfar())
    }

    fn view_transform(&self) -> Isometry3<f32> {
        Isometry3::look_at_rh(&self.eye(), &self.at,  &self.up_axis)
    }

    fn eye(&self) -> Point3<f32> {
        let px = self.at.x + self.dist * self.yaw.cos() * self.pitch.sin();
        let py = self.at.y + self.dist * self.pitch.cos();
        let pz = self.at.z + self.dist * self.yaw.sin() * self.pitch.sin();

        Point3::new(px, py, pz)
    }

    fn handle_event(&mut self, canvas: &Canvas, event: &WindowEvent) {
        match *event {
            WindowEvent::CursorPos(x, y, _) => {
                let curr_pos = Vector2::new(x as f32, y as f32);

                if let Some(rotate_button) = self.rotate_button {
                    if canvas.get_mouse_button(rotate_button) == Action::Press {
                        let dpos = curr_pos - self.last_cursor_pos;
                        self.handle_left_button_displacement(&dpos)
                    }
                }

                if let Some(drag_button) = self.drag_button {
                    if canvas.get_mouse_button(drag_button) == Action::Press {
                        let dpos = curr_pos - self.last_cursor_pos;
                        self.handle_right_button_displacement(&dpos)
                    }
                }

                self.last_cursor_pos = curr_pos;
            }
            WindowEvent::Key(key, Action::Press, _) if Some(key) == self.reset_key => {
                self.at = Point3::origin();
                self.update_projviews();
            }
            WindowEvent::Scroll(_, off, _) => self.handle_scroll(off as f32),
            WindowEvent::FramebufferSize(w, h) => {
                self.projection.set_aspect(w as f32 / h as f32);
                self.update_projviews();
            }
            _ => {}
        }
    }

    #[inline]
    fn upload(
        &self,
        _: usize,
        proj: &mut ShaderUniform<Matrix4<f32>>,
        view: &mut ShaderUniform<Matrix4<f32>>,
    ) {
        proj.upload(&self.proj);
        view.upload(&self.view);
    }

    fn transformation(&self) -> Matrix4<f32> {
        self.proj_view
    }

    fn inverse_transformation(&self) -> Matrix4<f32> {
        self.inverse_proj_view
    }

    fn update(&mut self, _: &Canvas) {}
}
<|endoftext|>


<commit_before>use parser::{Identifier, Expression};

use super::{Error};
use super::{OperationsResult, expression};
use super::scope::{ScopeStack, ScopeItem};

pub fn into_operations(
    scope: &mut ScopeStack,
    lhs: Identifier,
    expr: Expression,
) -> OperationsResult {
    scope.lookup(&lhs).first().ok_or_else(|| {
        Error::UnresolvedName(lhs.clone())
    }).and_then(|item| match **item {
        ScopeItem::TypedBlock {type_id, memory} => Ok((type_id, memory)),
        _ => Err(Error::InvalidLeftHandSide(lhs)),
    }).and_then(|(type_id, memory)| {
        expression::into_operations(scope, expr, type_id, memory)
    })
}
<commit_msg>Making sure assignment zeros memory before assigning<commit_after>use parser::{Identifier, Expression};

use super::{Error};
use super::{Operation, OperationsResult, expression};
use super::scope::{ScopeStack, ScopeItem};

pub fn into_operations(
    scope: &mut ScopeStack,
    lhs: Identifier,
    expr: Expression,
) -> OperationsResult {
    scope.lookup(&lhs).first().ok_or_else(|| {
        Error::UnresolvedName(lhs.clone())
    }).and_then(|item| match **item {
        ScopeItem::TypedBlock {type_id, memory} => Ok((type_id, memory)),
        _ => Err(Error::InvalidLeftHandSide(lhs)),
    }).and_then(|(type_id, memory)| {
        //TODO: Figure out if it is necessary to zero by whether the memory
        //TODO: has been initialized yet or not
        let mut ops = vec![Operation::Zero {
            target: memory,
        }];

        ops.extend(expression::into_operations(scope, expr, type_id, memory)?);

        Ok(ops)
    })
}
<|endoftext|>