<commit_before>use brotli;
use chrono::Local;
use env_logger::LogBuilder;
use log::{LogRecord, LogLevelFilter};
use rocket::http::{ContentType, Status};
use rocket::response::{self, Responder};
use rocket::{Request, Response};
use serde_json;

use std::thread;
use std::io;

pub fn setup_logger(log_thread: bool, rust_log: Option<&str>, date_format: &str) {
    let date_format = date_format.to_owned();
    let output_format = move |record: &LogRecord| {
        let thread_name = if log_thread {
            format!("({}) ", thread::current().name().unwrap_or("unknown"))
        } else {
            "".to_string()
        };
        let date = Local::now().format(&date_format).to_string();
        format!("{}: {}{} - {} - {}", date, thread_name, record.level(), record.target(), record.args())
    };

    let mut builder = LogBuilder::new();
    builder.format(output_format).filter(None, LogLevelFilter::Info);

    rust_log.map(|conf| builder.parse(conf));

    builder.init().unwrap();
}

macro_rules! format_error_chain {
    ($err: expr) => {{
        error ! ("error: {}", $err);
        for e in $err.iter().skip(1) {
            error ! ("caused by: {}", e);
        }
        if let Some(backtrace) = $err.backtrace() {
            error ! ("backtrace: {:?}", backtrace);
        }
    }}
}

macro_rules! time {
    ($title:expr, $msg:expr) => {{
        use chrono;
        let start_time = chrono::Utc::now();
        let ret = $msg;
        let elapsed_micros = chrono::Utc::now().signed_duration_since(start_time).num_microseconds().unwrap() as f32;
        debug!("Elapsed time while {}: {:.3}ms", $title, elapsed_micros / 1000f32);
        ret
    }};
}

/// Given a vector, will insert `value` at the desired position `pos`, filling the items
/// with `default`s if needed.
pub fn insert_at<T: Copy>(vector: &mut Vec<T>, pos: usize, value: T, default: T) {
    for _ in vector.len()..(pos+1) {
        vector.push(default);
    }
    vector[pos] = value;
}

/// Wraps a JSON value and implements a responder for it, with support for brotli compression.
pub struct CompressedJSON(pub serde_json::Value);

impl Responder<'static> for CompressedJSON {
    fn respond_to(self, req: &Request) -> response::Result<'static> {
        let json = serde_json::to_vec(&self.0).unwrap();
        let reader = io::Cursor::new(json);
        let headers = req.headers();
        if headers.contains("Accept") && headers.get("Accept-Encoding").any(|e| e.contains("br")) {
            Ok(Response::build()
                .status(Status::Ok)
                .header(ContentType::JSON)
                .raw_header("Content-Encoding", "br")
                .streamed_body(brotli::CompressorReader::new(reader, 4096, 3, 20))
                .finalize())
        } else {
            Ok(Response::build()
                .status(Status::Ok)
                .header(ContentType::JSON)
                .streamed_body(reader)
                .finalize())
        }
    }
}
<commit_msg>Improve time macro<commit_after>use brotli;
use chrono::Local;
use env_logger::LogBuilder;
use log::{LogRecord, LogLevelFilter};
use rocket::http::{ContentType, Status};
use rocket::response::{self, Responder};
use rocket::{Request, Response};
use serde_json;

use std::thread;
use std::io;

pub fn setup_logger(log_thread: bool, rust_log: Option<&str>, date_format: &str) {
    let date_format = date_format.to_owned();
    let output_format = move |record: &LogRecord| {
        let thread_name = if log_thread {
            format!("({}) ", thread::current().name().unwrap_or("unknown"))
        } else {
            "".to_string()
        };
        let date = Local::now().format(&date_format).to_string();
        format!("{}: {}{} - {} - {}", date, thread_name, record.level(), record.target(), record.args())
    };

    let mut builder = LogBuilder::new();
    builder.format(output_format).filter(None, LogLevelFilter::Info);

    rust_log.map(|conf| builder.parse(conf));

    builder.init().unwrap();
}

macro_rules! format_error_chain {
    ($err: expr) => {{
        error!("error: {}", $err);
        for e in $err.iter().skip(1) {
            error!("caused by: {}", e);
        }
        if let Some(backtrace) = $err.backtrace() {
            error!("backtrace: {:?}", backtrace);
        }
    }}
}

macro_rules! time {
    ($title:expr, $msg:expr) => {{
        use chrono;
        let start_time = chrono::Utc::now();
        let ret = $msg;
        let elapsed_micros = chrono::Utc::now().signed_duration_since(start_time).num_microseconds().unwrap() as f32;
        debug!("Elapsed time while {}: {:.3}ms", $title, elapsed_micros / 1000f32);
        ret
    }};
}

/// Given a vector, will insert `value` at the desired position `pos`, filling the items
/// with `default`s if needed.
pub fn insert_at<T: Copy>(vector: &mut Vec<T>, pos: usize, value: T, default: T) {
    for _ in vector.len()..(pos+1) {
        vector.push(default);
    }
    vector[pos] = value;
}

/// Wraps a JSON value and implements a responder for it, with support for brotli compression.
pub struct CompressedJSON(pub serde_json::Value);

impl Responder<'static> for CompressedJSON {
    fn respond_to(self, req: &Request) -> response::Result<'static> {
        let json = serde_json::to_vec(&self.0).unwrap();
        let reader = io::Cursor::new(json);
        let headers = req.headers();
        if headers.contains("Accept") && headers.get("Accept-Encoding").any(|e| e.contains("br")) {
            Ok(Response::build()
                .status(Status::Ok)
                .header(ContentType::JSON)
                .raw_header("Content-Encoding", "br")
                .streamed_body(brotli::CompressorReader::new(reader, 4096, 3, 20))
                .finalize())
        } else {
            Ok(Response::build()
                .status(Status::Ok)
                .header(ContentType::JSON)
                .streamed_body(reader)
                .finalize())
        }
    }
}
<|endoftext|>


<commit_before>
use std::f32;
use std::num::Float;

use math::{LineSeg, Vec2, V2_ORIGIN};

pub struct World {
    pub walls: Vec<LineSeg>
}

pub fn temp() -> World {
    World {
        walls: vec![
            LineSeg::new(-40.0, -40.0,  40.0, -40.0),
            LineSeg::new( 40.0, -40.0,  40.0,  40.0),
            LineSeg::new( 40.0,  40.0, -40.0,  40.0),
            LineSeg::new(-40.0,  40.0, -40.0, -40.0),
            LineSeg::new(-15.0, -15.0, -10.0, -15.0),
            LineSeg::new(-10.0, -15.0, -10.0, -10.0),
            LineSeg::new(-10.0, -10.0, -15.0, -10.0),
            LineSeg::new(-15.0, -10.0, -15.0, -15.0),
            LineSeg::new( 15.0,  15.0,  10.0,  15.0),
            LineSeg::new( 10.0,  15.0,  10.0,  10.0),
            LineSeg::new( 10.0,  10.0,  15.0,  10.0),
            LineSeg::new( 15.0,  10.0,  15.0,  15.0)
        ]
    }
}

impl World {
    pub fn cast_ray(&self, pos: Vec2, angle: f32) -> Option<(f32, Vec2)> {
        let ray = LineSeg::new(
            pos.x, pos.y,
            pos.x + 1000.0*Float::sin(angle),
            pos.y - 1000.0*Float::cos(angle)
        );

        let (dist, pos) = self.walls.iter()
            .filter_map(|&wall| ray.intersects_at(wall).map(|t| wall.at(t)))
            .map(|int| ((int - pos).get_length(), int))
            .fold((f32::MAX, V2_ORIGIN), |(shortest, _), (dist, pos)| {
                (if dist < shortest { dist } else { shortest }, pos)
            });

        if dist < f32::MAX { Some((dist, pos)) } else { None }
    }
}
<commit_msg>Fixed ray position returned from cast_ray<commit_after>
use std::f32;
use std::num::Float;

use math::{LineSeg, Vec2, V2_ORIGIN};

pub struct World {
    pub walls: Vec<LineSeg>
}

pub fn temp() -> World {
    World {
        walls: vec![
            LineSeg::new(-40.0, -40.0,  40.0, -40.0),
            LineSeg::new( 40.0, -40.0,  40.0,  40.0),
            LineSeg::new( 40.0,  40.0, -40.0,  40.0),
            LineSeg::new(-40.0,  40.0, -40.0, -40.0),
            LineSeg::new(-15.0, -15.0, -10.0, -15.0),
            LineSeg::new(-10.0, -15.0, -10.0, -10.0),
            LineSeg::new(-10.0, -10.0, -15.0, -10.0),
            LineSeg::new(-15.0, -10.0, -15.0, -15.0),
            LineSeg::new( 15.0,  15.0,  10.0,  15.0),
            LineSeg::new( 10.0,  15.0,  10.0,  10.0),
            LineSeg::new( 10.0,  10.0,  15.0,  10.0),
            LineSeg::new( 15.0,  10.0,  15.0,  15.0)
        ]
    }
}

impl World {
    pub fn cast_ray(&self, pos: Vec2, angle: f32) -> Option<(f32, Vec2)> {
        let ray = LineSeg::new(
            pos.x, pos.y,
            pos.x + 1000.0*Float::sin(angle),
            pos.y - 1000.0*Float::cos(angle)
        );

        let (dist, pos) = self.walls.iter()
            .filter_map(|&wall| ray.intersects_at(wall).map(|t| wall.at(t)))
            .map(|int| ((int - pos).get_length(), int))
            .fold((f32::MAX, V2_ORIGIN), |(short_dist, short_pos), (dist, pos)| {
                if dist < short_dist { (dist, pos) } else { (short_dist, short_pos) }
            });

        if dist < f32::MAX { Some((dist, pos)) } else { None }
    }
}
<|endoftext|>


<commit_before>use ndarray::*;
use ndarray_linalg::*;

#[test]
fn inv_random() {
    let a: Array2<f64> = random((3, 3));
    let ai: Array2<_> = (&a).inv().unwrap();
    let id = Array::eye(3);
    assert_close_l2!(&ai.dot(&a), &id, 1e-7);
}

#[test]
fn inv_random_t() {
    let a: Array2<f64> = random((3, 3).f());
    let ai: Array2<_> = (&a).inv().unwrap();
    let id = Array::eye(3);
    assert_close_l2!(&ai.dot(&a), &id, 1e-7);
}

#[test]
#[should_panic]
fn inv_error() {
    // do not have inverse
    let a = Array::<f64, _>::zeros(9).into_shape((3, 3)).unwrap();
    let a_inv = a.inv().unwrap();
    println!("{:?}", a_inv);
}
<commit_msg>test for 2x2 inverse (related to #123)<commit_after>use ndarray::*;
use ndarray_linalg::*;

#[test]
fn inv_random() {
    let a: Array2<f64> = random((3, 3));
    let ai: Array2<_> = (&a).inv().unwrap();
    let id = Array::eye(3);
    assert_close_l2!(&ai.dot(&a), &id, 1e-7);
}

#[test]
fn inv_random_t() {
    let a: Array2<f64> = random((3, 3).f());
    let ai: Array2<_> = (&a).inv().unwrap();
    let id = Array::eye(3);
    assert_close_l2!(&ai.dot(&a), &id, 1e-7);
}

#[test]
#[should_panic]
fn inv_error() {
    // do not have inverse
    let a = Array::<f64, _>::zeros(9).into_shape((3, 3)).unwrap();
    let a_inv = a.inv().unwrap();
    println!("{:?}", a_inv);
}

#[test]
fn inv_2x2() {
    // Related to issue #123 where this problem led to a wrongly computed inverse when using the
    // `openblas` backend.
    let a: Array2<f64> = array!([1.0, 2.0], [3.0, 4.0]);
    let a_inv = a.inv().unwrap();
    assert_close_l2!(&a_inv, &array!([-2.0, 1.0], [1.5, -0.5]), 1e-7);
}
<|endoftext|>


<commit_before>// Copyright 2018 Google LLC
//
// 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.

#[macro_use]
extern crate serde_derive;
#[macro_use]
extern crate log;
#[macro_use]
extern crate lalrpop_util;

use std::fs;
use std::fs::File;
use std::io::{BufReader, ErrorKind};
use std::path::{Path, PathBuf};

use gravity::{
    GravitationalConstant,
    GravitySource,
    GravitySystem,
    GravityTarget,
};
use circle_collision::{
    BruteForceCollisionDetector,
    ClearCollisionsInvolvingSceneEntities,
    CircleCollider,
    CollisionMatrix,
    LastUpdateCollisions,
};

#[cfg(feature = "graphical")]
use xsecurelock_saver::engine::EngineBuilder;

use physics::systems::{SympleticEulerForceStep, SympleticEulerVelocityStep};

use crate::{
    collision::{
        DeleteCollidedPlanets,
        MergeCollidedPlanets,
        MergedInto,
    },
    config::{
        GeneticOrbitsConfig,
        generator::GeneratorConfig,
        scoring::ScoringConfig,
    },
    statustracker::{ActiveWorld, ScoreKeeper},
    storage::{
        Storage,
        sqlite::SqliteStorage,
    },
    worldgenerator::WorldGenerator,
};

mod collision;
mod config;
mod model;
mod pruner;
mod storage;
mod statustracker;
mod timer;
mod worldgenerator;

fn main() {
    simple_logger::init().unwrap();

    let config = get_config();

    let GeneticOrbitsConfig { database, generator, scoring } = config;

    let stop_pruning = if let Some(max_scenarios_to_keep) = database.max_scenarios_to_keep {
        let storage = open_storage(database.database_path.as_ref().map(|s| &**s));
        let prune_interval = ::std::time::Duration::from_secs(database.prune_interval_seconds);
        Some(pruner::prune_scenarios(prune_interval, max_scenarios_to_keep, storage))
    } else {
        None
    };

    let storage = open_storage(database.database_path.as_ref().map(|s| &**s));

    use clap::{App, Arg};
    let args = App::new("saver_genetic_orbits")
        .arg(Arg::with_name("headless")
            .long("headless")
            .help(
                "run in headless mode with no grpahics (no effect if not compiled with graphics \
                enabled)"))
        .get_matches();

    run_saver(args.is_present("headless"), scoring, generator, storage);

    if let Some(stop_pruning) = stop_pruning {
        stop_pruning.shutdown();
    }
}

/// internal saver-runner.
fn run_saver<S: Storage + Default + Send + Sync + 'static>(
    headless: bool, scoring: ScoringConfig, generator: GeneratorConfig, storage: S,
) {
    if !headless {
        #[cfg(feature = "graphical")] {
            return run_saver_graphical(scoring, generator, storage);
        }
    } else if cfg!(not(feature = "graphical")) {
        warn!("Headless flag has no effect if not compiled with graphics support");
    }
    run_saver_headless(scoring, generator, storage);
}

#[cfg(feature = "graphical")]
fn run_saver_graphical<S: Storage + Default + Send + Sync + 'static>(
    scoring: ScoringConfig, generator: GeneratorConfig, storage: S,
) {
    info!("Running in graphical mode");
    EngineBuilder::new()
        .with_initial_sceneloader(WorldGenerator::<S>::default())
        .with_resource(GravitationalConstant(1000.))
        .with_resource(LastUpdateCollisions::default())
        .with_resource({
            let mut matrix = CollisionMatrix::default();
            matrix.enable_collision(collision::planet(), collision::planet());
            matrix
        })
        .with_resource(scoring)
        .with_resource(generator)
        .with_resource(storage)
        .with_resource(ActiveWorld::default())
        .with_component::<CircleCollider>()
        .with_component::<GravitySource>()
        .with_component::<GravityTarget>()
        .with_component::<MergedInto>()
        .with_scene_change_sys(ClearCollisionsInvolvingSceneEntities, "", &[])
        // Run the real merge just before scoring.
        .with_physics_update_sys(MergeCollidedPlanets, "merge-collided", &[])
        .with_physics_update_sys(DeleteCollidedPlanets, "delete-collided", &["merge-collided"])
        .with_physics_update_barrier()
        // Run scorekeeping before integrating.
        .with_physics_update_sys(ScoreKeeper::<S>::default(), "score-keeper", &[])
        .with_physics_update_sys(GravitySystem, "apply-gravity", &[])
        // Barrier between adding forces and adding integration.
        .with_physics_update_barrier()
        .with_physics_update_sys(SympleticEulerForceStep, "integrate-forces", &[])
        .with_physics_update_sys(
            BruteForceCollisionDetector, "detect-collisions", &["integrate-forces"])
        .with_physics_update_sys(
            SympleticEulerVelocityStep, "integrate-velocities", &["detect-collisions"])
        .build()
        .run();
}

fn run_saver_headless<S: Storage + Default + Send + Sync + 'static>(
    scoring: ScoringConfig, generator: GeneratorConfig, storage: S,
) {
    info!("Running in headless mode");
    use sigint;
    use specs::{World, DispatcherBuilder};
    use scene_management::resources::SceneChange;

    sigint::init();

    let mut world = World::new();
    physics::register(&mut world);
    scene_management::register(&mut world);
    world.register::<CircleCollider>();
    world.register::<GravitySource>();
    world.register::<GravityTarget>();
    world.register::<MergedInto>();
    world.add_resource(GravitationalConstant(1000.));
    world.add_resource(LastUpdateCollisions::default());
    world.add_resource({
        let mut matrix = CollisionMatrix::default();
        matrix.enable_collision(collision::planet(), collision::planet());
        matrix
    });
    world.add_resource(scoring);
    world.add_resource(generator);
    world.add_resource(storage);
    world.add_resource(ActiveWorld::default());
    world.write_resource::<SceneChange>().change_scene(WorldGenerator::<S>::default());

    use physics::systems::{SetupNextPhysicsPosition, ClearForceAccumulators};
    use scene_management::{
        SceneChangeHandlerBuilder,
        systems::DeleteSystem,
    };
    use std::sync::Arc;
    let threadpool = Arc::new(rayon::ThreadPoolBuilder::new().build().unwrap());

    let mut dispatcher = DispatcherBuilder::new()
        .with_pool(Arc::clone(&threadpool))
        .with(SetupNextPhysicsPosition, "", &[])
        .with(ClearForceAccumulators, "", &[])
        .with_barrier()
        // Run the real merge just before scoring.
        .with(MergeCollidedPlanets, "merge-collided", &[])
        .with(DeleteCollidedPlanets, "delete-collided", &["merge-collided"])
        .with_barrier()
        // Run scorekeeping before integrating.
        .with(ScoreKeeper::<S>::default(), "score-keeper", &[])
        .with(GravitySystem, "apply-gravity", &[])
        // Barrier between adding forces and adding integration.
        .with_barrier()
        .with(SympleticEulerForceStep, "integrate-forces", &[])
        .with(
            BruteForceCollisionDetector, "detect-collisions", &["integrate-forces"])
        .with(
            SympleticEulerVelocityStep, "integrate-velocities", &["detect-collisions"])
        .with_barrier()
        .with(DeleteSystem, "", &[])
        .build();

    let mut change_handler = SceneChangeHandlerBuilder::new()
        .with_threadpool(threadpool)
        .with_pre_load_sys(ClearCollisionsInvolvingSceneEntities, "", &[])
        .build();

    dispatcher.setup(&mut world.res);
    change_handler.setup(&mut world);

    while !sigint::received_sigint() {
        dispatcher.dispatch(&mut world.res);
        world.maintain();
        change_handler.handle_scene_change(&mut world);
    }
}

/// The screensaver folder name, used both for saving the database in the user data directory and
/// for looking for configs in the
const SAVER_DIR: &'static str = "xsecurelock-saver-genetic-orbits";

/// Checks for the config path and either tries to open it or opens the default location.
fn open_storage(config_path: Option<&str>) -> SqliteStorage {
    match config_path {
        Some(path) => {
            info!("using database {}", path);
            SqliteStorage::open(path).unwrap()
        },
        None => open_default_storage(),
    }
}

/// Open SqliteStorage somewhere, either in the user data dir or in memory.
fn open_default_storage() -> SqliteStorage {
    if let Some(mut data_dir) = dirs::data_dir() {
        data_dir.push(SAVER_DIR);
        let create_res = fs::create_dir(&data_dir)
            .or_else(|err| if err.kind() == ErrorKind::AlreadyExists {
                Ok(())
            } else {
                Err(err)
            });
        match create_res {
            Ok(()) => {
                data_dir.push("scenario-db.sqlite3");
                info!("using database {:?}", data_dir);
                return SqliteStorage::open(data_dir).unwrap();
            },
            Err(err) => error!("Unable to create storage directory ({}), opening in memory", err),
        }
    }
    info!("using in-memory database");
    SqliteStorage::open_in_memory_named("default").unwrap()
}

/// Load the config from the user config directory.
fn get_config() -> GeneticOrbitsConfig {
    match find_config_file() {
        Some(config_file) => {
            match serde_yaml::from_reader::<_, GeneticOrbitsConfig>(config_file) {
                Ok(mut config) => {
                    info!("Successfully loaded config");
                    config.fix_invalid();
                    config
                },
                Err(err) => {
                    error!("Error loading config: {}", err);
                    Default::default()
                },
            }
        },
        None => {
            info!("No config file found, using default config");
            Default::default()
        },
    }
}

fn find_config_file() -> Option<BufReader<File>> {
    let config_file = dirs::home_dir()
        .and_then(|mut home| {
            home.push(".xsecurelock-saver-genetic-orbits.yaml");
            try_open_config_file(home)
        })
        .or_else(|| {
            dirs::config_dir()
                .and_then(|mut config| {
                    config.push(SAVER_DIR);
                    config.push("config.yaml");
                    try_open_config_file(config)
                })
        });
    let config_file = if cfg!(target_family = "unix") {
        config_file.or_else(|| try_open_config_file(
                PathBuf::from(r"/etc/xsecurelock-saver-genetic-orbits/config.yaml")))
    } else {
        config_file
    };
    config_file.map(BufReader::new)
}

fn try_open_config_file<P: AsRef<Path>>(b: P) -> Option<File> {
    let config_load = File::open(b.as_ref())
        .or_else(|err| if err.kind() == ErrorKind::NotFound {
            Err(())
        } else {
            error!("Unable to read config file {:?}: {}", b.as_ref(), err);
            Err(())
        });
    match config_load {
        Err(()) => None,
        Ok(config) => {
            info!("Using config file {:?}", b.as_ref());
            Some(config)
        },
    }
}
<commit_msg>add hack for unused argument<commit_after>// Copyright 2018 Google LLC
//
// 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.

#[macro_use]
extern crate serde_derive;
#[macro_use]
extern crate log;
#[macro_use]
extern crate lalrpop_util;

use std::fs;
use std::fs::File;
use std::io::{BufReader, ErrorKind};
use std::path::{Path, PathBuf};

use gravity::{
    GravitationalConstant,
    GravitySource,
    GravitySystem,
    GravityTarget,
};
use circle_collision::{
    BruteForceCollisionDetector,
    ClearCollisionsInvolvingSceneEntities,
    CircleCollider,
    CollisionMatrix,
    LastUpdateCollisions,
};

#[cfg(feature = "graphical")]
use xsecurelock_saver::engine::EngineBuilder;

use physics::systems::{SympleticEulerForceStep, SympleticEulerVelocityStep};

use crate::{
    collision::{
        DeleteCollidedPlanets,
        MergeCollidedPlanets,
        MergedInto,
    },
    config::{
        GeneticOrbitsConfig,
        generator::GeneratorConfig,
        scoring::ScoringConfig,
    },
    statustracker::{ActiveWorld, ScoreKeeper},
    storage::{
        Storage,
        sqlite::SqliteStorage,
    },
    worldgenerator::WorldGenerator,
};

mod collision;
mod config;
mod model;
mod pruner;
mod storage;
mod statustracker;
mod timer;
mod worldgenerator;

fn main() {
    simple_logger::init().unwrap();

    let config = get_config();

    let GeneticOrbitsConfig { database, generator, scoring } = config;

    let stop_pruning = if let Some(max_scenarios_to_keep) = database.max_scenarios_to_keep {
        let storage = open_storage(database.database_path.as_ref().map(|s| &**s));
        let prune_interval = ::std::time::Duration::from_secs(database.prune_interval_seconds);
        Some(pruner::prune_scenarios(prune_interval, max_scenarios_to_keep, storage))
    } else {
        None
    };

    let storage = open_storage(database.database_path.as_ref().map(|s| &**s));

    use clap::{App, Arg};
    let args = App::new("saver_genetic_orbits")
        .arg(Arg::with_name("headless")
            .long("headless")
            .help(
                "run in headless mode with no grpahics (no effect if not compiled with graphics \
                enabled)"))
        .get_matches_from(
            // XSecureLock runs with "-root" for XScreenSaver compatibility, and we don't need it,
            // so skip it.
            ::std::env::args_os()
                .filter(|arg| arg != "-root"));

    run_saver(args.is_present("headless"), scoring, generator, storage);

    if let Some(stop_pruning) = stop_pruning {
        stop_pruning.shutdown();
    }
}

/// internal saver-runner.
fn run_saver<S: Storage + Default + Send + Sync + 'static>(
    headless: bool, scoring: ScoringConfig, generator: GeneratorConfig, storage: S,
) {
    if !headless {
        #[cfg(feature = "graphical")] {
            return run_saver_graphical(scoring, generator, storage);
        }
    } else if cfg!(not(feature = "graphical")) {
        warn!("Headless flag has no effect if not compiled with graphics support");
    }
    run_saver_headless(scoring, generator, storage);
}

#[cfg(feature = "graphical")]
fn run_saver_graphical<S: Storage + Default + Send + Sync + 'static>(
    scoring: ScoringConfig, generator: GeneratorConfig, storage: S,
) {
    info!("Running in graphical mode");
    EngineBuilder::new()
        .with_initial_sceneloader(WorldGenerator::<S>::default())
        .with_resource(GravitationalConstant(1000.))
        .with_resource(LastUpdateCollisions::default())
        .with_resource({
            let mut matrix = CollisionMatrix::default();
            matrix.enable_collision(collision::planet(), collision::planet());
            matrix
        })
        .with_resource(scoring)
        .with_resource(generator)
        .with_resource(storage)
        .with_resource(ActiveWorld::default())
        .with_component::<CircleCollider>()
        .with_component::<GravitySource>()
        .with_component::<GravityTarget>()
        .with_component::<MergedInto>()
        .with_scene_change_sys(ClearCollisionsInvolvingSceneEntities, "", &[])
        // Run the real merge just before scoring.
        .with_physics_update_sys(MergeCollidedPlanets, "merge-collided", &[])
        .with_physics_update_sys(DeleteCollidedPlanets, "delete-collided", &["merge-collided"])
        .with_physics_update_barrier()
        // Run scorekeeping before integrating.
        .with_physics_update_sys(ScoreKeeper::<S>::default(), "score-keeper", &[])
        .with_physics_update_sys(GravitySystem, "apply-gravity", &[])
        // Barrier between adding forces and adding integration.
        .with_physics_update_barrier()
        .with_physics_update_sys(SympleticEulerForceStep, "integrate-forces", &[])
        .with_physics_update_sys(
            BruteForceCollisionDetector, "detect-collisions", &["integrate-forces"])
        .with_physics_update_sys(
            SympleticEulerVelocityStep, "integrate-velocities", &["detect-collisions"])
        .build()
        .run();
}

fn run_saver_headless<S: Storage + Default + Send + Sync + 'static>(
    scoring: ScoringConfig, generator: GeneratorConfig, storage: S,
) {
    info!("Running in headless mode");
    use sigint;
    use specs::{World, DispatcherBuilder};
    use scene_management::resources::SceneChange;

    sigint::init();

    let mut world = World::new();
    physics::register(&mut world);
    scene_management::register(&mut world);
    world.register::<CircleCollider>();
    world.register::<GravitySource>();
    world.register::<GravityTarget>();
    world.register::<MergedInto>();
    world.add_resource(GravitationalConstant(1000.));
    world.add_resource(LastUpdateCollisions::default());
    world.add_resource({
        let mut matrix = CollisionMatrix::default();
        matrix.enable_collision(collision::planet(), collision::planet());
        matrix
    });
    world.add_resource(scoring);
    world.add_resource(generator);
    world.add_resource(storage);
    world.add_resource(ActiveWorld::default());
    world.write_resource::<SceneChange>().change_scene(WorldGenerator::<S>::default());

    use physics::systems::{SetupNextPhysicsPosition, ClearForceAccumulators};
    use scene_management::{
        SceneChangeHandlerBuilder,
        systems::DeleteSystem,
    };
    use std::sync::Arc;
    let threadpool = Arc::new(rayon::ThreadPoolBuilder::new().build().unwrap());

    let mut dispatcher = DispatcherBuilder::new()
        .with_pool(Arc::clone(&threadpool))
        .with(SetupNextPhysicsPosition, "", &[])
        .with(ClearForceAccumulators, "", &[])
        .with_barrier()
        // Run the real merge just before scoring.
        .with(MergeCollidedPlanets, "merge-collided", &[])
        .with(DeleteCollidedPlanets, "delete-collided", &["merge-collided"])
        .with_barrier()
        // Run scorekeeping before integrating.
        .with(ScoreKeeper::<S>::default(), "score-keeper", &[])
        .with(GravitySystem, "apply-gravity", &[])
        // Barrier between adding forces and adding integration.
        .with_barrier()
        .with(SympleticEulerForceStep, "integrate-forces", &[])
        .with(
            BruteForceCollisionDetector, "detect-collisions", &["integrate-forces"])
        .with(
            SympleticEulerVelocityStep, "integrate-velocities", &["detect-collisions"])
        .with_barrier()
        .with(DeleteSystem, "", &[])
        .build();

    let mut change_handler = SceneChangeHandlerBuilder::new()
        .with_threadpool(threadpool)
        .with_pre_load_sys(ClearCollisionsInvolvingSceneEntities, "", &[])
        .build();

    dispatcher.setup(&mut world.res);
    change_handler.setup(&mut world);

    while !sigint::received_sigint() {
        dispatcher.dispatch(&mut world.res);
        world.maintain();
        change_handler.handle_scene_change(&mut world);
    }
}

/// The screensaver folder name, used both for saving the database in the user data directory and
/// for looking for configs in the
const SAVER_DIR: &'static str = "xsecurelock-saver-genetic-orbits";

/// Checks for the config path and either tries to open it or opens the default location.
fn open_storage(config_path: Option<&str>) -> SqliteStorage {
    match config_path {
        Some(path) => {
            info!("using database {}", path);
            SqliteStorage::open(path).unwrap()
        },
        None => open_default_storage(),
    }
}

/// Open SqliteStorage somewhere, either in the user data dir or in memory.
fn open_default_storage() -> SqliteStorage {
    if let Some(mut data_dir) = dirs::data_dir() {
        data_dir.push(SAVER_DIR);
        let create_res = fs::create_dir(&data_dir)
            .or_else(|err| if err.kind() == ErrorKind::AlreadyExists {
                Ok(())
            } else {
                Err(err)
            });
        match create_res {
            Ok(()) => {
                data_dir.push("scenario-db.sqlite3");
                info!("using database {:?}", data_dir);
                return SqliteStorage::open(data_dir).unwrap();
            },
            Err(err) => error!("Unable to create storage directory ({}), opening in memory", err),
        }
    }
    info!("using in-memory database");
    SqliteStorage::open_in_memory_named("default").unwrap()
}

/// Load the config from the user config directory.
fn get_config() -> GeneticOrbitsConfig {
    match find_config_file() {
        Some(config_file) => {
            match serde_yaml::from_reader::<_, GeneticOrbitsConfig>(config_file) {
                Ok(mut config) => {
                    info!("Successfully loaded config");
                    config.fix_invalid();
                    config
                },
                Err(err) => {
                    error!("Error loading config: {}", err);
                    Default::default()
                },
            }
        },
        None => {
            info!("No config file found, using default config");
            Default::default()
        },
    }
}

fn find_config_file() -> Option<BufReader<File>> {
    let config_file = dirs::home_dir()
        .and_then(|mut home| {
            home.push(".xsecurelock-saver-genetic-orbits.yaml");
            try_open_config_file(home)
        })
        .or_else(|| {
            dirs::config_dir()
                .and_then(|mut config| {
                    config.push(SAVER_DIR);
                    config.push("config.yaml");
                    try_open_config_file(config)
                })
        });
    let config_file = if cfg!(target_family = "unix") {
        config_file.or_else(|| try_open_config_file(
                PathBuf::from(r"/etc/xsecurelock-saver-genetic-orbits/config.yaml")))
    } else {
        config_file
    };
    config_file.map(BufReader::new)
}

fn try_open_config_file<P: AsRef<Path>>(b: P) -> Option<File> {
    let config_load = File::open(b.as_ref())
        .or_else(|err| if err.kind() == ErrorKind::NotFound {
            Err(())
        } else {
            error!("Unable to read config file {:?}: {}", b.as_ref(), err);
            Err(())
        });
    match config_load {
        Err(()) => None,
        Ok(config) => {
            info!("Using config file {:?}", b.as_ref());
            Some(config)
        },
    }
}
<|endoftext|>


<commit_before>// Copyright 2018 Google Inc.
//
// 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
//
//     https://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.

pub trait Display {
    /// Implementation should emit a representation of itself in one or mime
    /// types  using the functions below.
    fn evcxr_display(&self);
}

/// Represents a mime type for some content that is yet to be emitted.
pub struct ContentMimeType {
    mime_type: String,
}

/// Prepares to output some content with the specified mime type.
/// ```
/// evcxr_runtime::mime_type("text/plain").text("Hello world");
/// ```
pub fn mime_type(mime_type: &str) -> ContentMimeType {
    ContentMimeType {
        mime_type: mime_type.to_owned(),
    }
}

impl ContentMimeType {
    /// Emits the supplied content, which should be of the mime type already
    /// specified. If the type is a binary format (e.g. image/png), the content
    /// should have already been base64 encoded.
    /// ```
    /// evcxr_runtime::mime_type("text/html")
    ///     .text("<span style=\"color: red\">>Hello world</span>");
    /// ```
    pub fn text(self, text: &str) {
        println!(
            "EVCXR_BEGIN_CONTENT {}\n{}\nEVCXR_END_CONTENT",
            self.mime_type, text
        );
    }
}

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

    #[test]
    fn test_emit_data() {
        mime_type("text/plain").text("Hello world");
    }
}
<commit_msg>evcxr_runtime: accept more types as input of mime_type and text (String, &str,…)<commit_after>// Copyright 2018 Google Inc.
//
// 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
//
//     https://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.

pub trait Display {
    /// Implementation should emit a representation of itself in one or mime
    /// types  using the functions below.
    fn evcxr_display(&self);
}

/// Represents a mime type for some content that is yet to be emitted.
pub struct ContentMimeType {
    mime_type: String,
}

/// Prepares to output some content with the specified mime type.
/// ```
/// evcxr_runtime::mime_type("text/plain").text("Hello world");
/// ```
pub fn mime_type<S: Into<String>>(mime_type: S) -> ContentMimeType {
    ContentMimeType {
        mime_type: mime_type.into(),
    }
}

impl ContentMimeType {
    /// Emits the supplied content, which should be of the mime type already
    /// specified. If the type is a binary format (e.g. image/png), the content
    /// should have already been base64 encoded.
    /// ```
    /// evcxr_runtime::mime_type("text/html")
    ///     .text("<span style=\"color: red\">>Hello world</span>");
    /// ```
    pub fn text<S: AsRef<str>>(self, text: S) {
        println!(
            "EVCXR_BEGIN_CONTENT {}\n{}\nEVCXR_END_CONTENT",
            self.mime_type,
            text.as_ref()
        );
    }
}

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

    #[test]
    fn test_emit_data() {
        mime_type("text/plain").text("Hello world");
    }

    #[test]
    fn test_mime_type_accept_string() {
        mime_type("text/plain".to_owned()).text("Hello world");
    }
}
<|endoftext|>


<commit_before>use types::*;
use types::flags::*;
use types::generation::*;
use types::parsing::*;

use cookie_factory::GenError;

pub const NAME:          &'static str   = "{{protocol.name}}";
pub const MAJOR_VERSION: ShortShortUInt = {{protocol.major_version}};
pub const MINOR_VERSION: ShortShortUInt = {{protocol.minor_version}};
pub const REVISION:      ShortShortUInt = {{protocol.revision}};
pub const PORT:          LongUInt       = {{protocol.port}};
pub const COPYRIGHT:     &'static str   = r#"{{copyright}}"#;

{{#each protocol.constants as |constant| ~}}
pub const {{sanitize_name constant.name}}: {{constant.type}} = {{constant.value}};
{{/each ~}}

pub enum AMQPError {
    Soft(AMQPSoftError),
    Hard(AMQPHardError),
}

impl AMQPError {
    pub fn get_id(&self) -> ShortUInt {
        match *self {
            AMQPError::Soft(ref s) => s.get_id(),
            AMQPError::Hard(ref h) => h.get_id(),
        }
    }

    pub fn from_id(id: ShortUInt) -> Option<AMQPError> {
        AMQPSoftError::from_id(id).map(|e| AMQPError::Soft(e)).or_else(|| AMQPHardError::from_id(id).map(|e| AMQPError::Hard(e)))
    }
}

pub enum AMQPSoftError {
    {{#each protocol.soft_errors as |constant| ~}}
    {{camel constant.name}},
    {{/each ~}}
}

impl AMQPSoftError {
    pub fn get_id(&self) -> ShortUInt {
        match *self {
            {{#each protocol.soft_errors as |constant| ~}}
            AMQPSoftError::{{camel constant.name}} => {{constant.value}},
            {{/each ~}}
        }
    }

    pub fn from_id(id: ShortUInt) -> Option<AMQPSoftError> {
        match id {
            {{#each protocol.soft_errors as |constant| ~}}
            {{constant.value}} => Some(AMQPSoftError::{{camel constant.name}}),
            {{/each ~}}
            _                  => None,
        }
    }
}

pub enum AMQPHardError {
    {{#each protocol.hard_errors as |constant| ~}}
    {{camel constant.name}},
    {{/each ~}}
}

impl AMQPHardError {
    pub fn get_id(&self) -> ShortUInt {
        match *self {
            {{#each protocol.hard_errors as |constant| ~}}
            AMQPHardError::{{camel constant.name}} => {{constant.value}},
            {{/each ~}}
        }
    }

    pub fn from_id(id: ShortUInt) -> Option<AMQPHardError> {
        match id {
            {{#each protocol.hard_errors as |constant| ~}}
            {{constant.value}} => Some(AMQPHardError::{{camel constant.name}}),
            {{/each ~}}
            _                  => None,
        }
    }
}

pub fn gen_class<'a>(input: (&'a mut [u8], usize), class: &AMQPClass) -> Result<(&'a mut [u8], usize), GenError> {
    match *class {
        {{#each protocol.classes as |class| ~}}
        AMQPClass::{{camel class.name}}(ref {{snake class.name}}) => {{snake class.name}}::gen_{{snake class.name}}(input, {{snake class.name}}),
        {{/each ~}}
    }
}

#[derive(Clone, Debug, PartialEq)]
pub enum AMQPClass {
    {{#each protocol.classes as |class| ~}}
    {{camel class.name}}({{snake class.name}}::Method),
    {{/each ~}}
}

{{#each protocol.classes as |class|}}
pub mod {{snake class.name}} {
    use super::*;

    /* FIXME: simplify and get rid of the Option/Some when nom supports trailing | */
    named!(pub parse_{{snake class.name}}<{{snake class.name}}::Method>, map!(switch!(map!(parse_short_uint, Some),
        {{#each class.methods as |method| ~}}
        Some({{method.id}}) => map!(call!(parse_{{snake method.name}}), |m| Some(Method::{{camel method.name}}(m))) |
        {{/each ~}}
        None                => value!(None)
    ), |c: Option<{{snake class.name}}::Method>| c.expect("We can't get there as we mapped to Some, only there to get a parser after the trailing |")));

    pub fn gen_{{snake class.name}}<'a>(input: (&'a mut [u8], usize), method: &Method) -> Result<(&'a mut [u8], usize), GenError> {
        match *method {
            {{#each class.methods as |method| ~}}
            Method::{{camel method.name}}(ref {{snake method.name}}) => {
                do_gen!(input,
                    gen_short_uint(&{{class.id}}) >>
                    gen_{{snake method.name}}({{snake method.name}})
                )
            },
            {{/each ~}}
        }
    }

    #[derive(Clone, Debug, PartialEq)]
    pub enum Method {
        {{#each class.methods as |method| ~}}
        {{camel method.name}}({{camel method.name}}),
        {{/each ~}}
    }

    {{#each class.methods as |method|}}
    #[derive(Clone, Debug, PartialEq)]
    pub struct {{camel method.name}} {
        {{#each_argument method.arguments as |argument| ~}}
        {{#if argument_is_value ~}}
        pub {{snake argument.name}}: {{argument.type}},
        {{else}}
        {{#each_flag argument as |flag| ~}}
        pub {{snake flag.name}}: Boolean,
        {{/each_flag ~}}
        {{/if ~}}
        {{/each_argument ~}}
    }

    named!(pub parse_{{snake method.name}}<{{camel method.name}}>, do_parse!(
        {{#each_argument method.arguments as |argument| ~}}
        {{#if argument_is_value ~}}
        {{snake argument.name}}: parse_{{snake_type argument.type}} >>
        {{else}}
        /* FIXME: support multiple flags structs? */
        flags: apply!(parse_flags, &vec![
            {{#each_flag argument as |flag| ~}}
            "{{flag.name}}",
            {{/each_flag ~}}
        ]) >>
        {{/if ~}}
        {{/each_argument ~}}
        ({{camel method.name}} {
            {{#each_argument method.arguments as |argument| ~}}
            {{#if argument_is_value ~}}
            {{snake argument.name}}: {{snake argument.name}},
            {{else}}
            {{#each_flag argument as |flag| ~}}
            {{snake flag.name}}: flags.get_flag("{{snake flag.name}}").unwrap_or({{flag.default_value}}),
            {{/each_flag ~}}
            {{/if ~}}
            {{/each_argument ~}}
        })
    ));

    pub fn gen_{{snake method.name}}<'a>(input: (&'a mut [u8], usize), {{#if method.has_arguments ~}}method{{else}}_{{/if ~}}: &{{camel method.name}}) -> Result<(&'a mut [u8],usize), GenError> {
        {{#if method.has_flags ~}}
        /* FIXME: support multiple flags structs? */
        let mut flags = AMQPFlags::new();
        {{#each_argument method.arguments as |argument| ~}}
        {{#unless argument_is_value ~}}
        {{#each_flag argument as |flag| ~}}
        flags.add_flag("{{snake flag.name}}".to_string(), method.{{snake flag.name}});
        {{/each_flag ~}}
        {{/unless ~}}
        {{/each_argument ~}}
        {{/if ~}}
        do_gen!(input,
            gen_short_uint(&{{method.id}})
            {{#each_argument method.arguments as |argument| ~}}
            {{#if argument_is_value ~}}
            >> gen_{{snake_type argument.type}}(&method.{{snake argument.name}})
            {{else}}
            >> gen_flags(&flags)
            {{/if ~}}
            {{/each_argument ~}}
        )
    }
    {{/each ~}}
}
{{/each ~}}
<commit_msg>protocol: implement class parsing<commit_after>use types::*;
use types::flags::*;
use types::generation::*;
use types::parsing::*;

use cookie_factory::GenError;

pub const NAME:          &'static str   = "{{protocol.name}}";
pub const MAJOR_VERSION: ShortShortUInt = {{protocol.major_version}};
pub const MINOR_VERSION: ShortShortUInt = {{protocol.minor_version}};
pub const REVISION:      ShortShortUInt = {{protocol.revision}};
pub const PORT:          LongUInt       = {{protocol.port}};
pub const COPYRIGHT:     &'static str   = r#"{{copyright}}"#;

{{#each protocol.constants as |constant| ~}}
pub const {{sanitize_name constant.name}}: {{constant.type}} = {{constant.value}};
{{/each ~}}

pub enum AMQPError {
    Soft(AMQPSoftError),
    Hard(AMQPHardError),
}

impl AMQPError {
    pub fn get_id(&self) -> ShortUInt {
        match *self {
            AMQPError::Soft(ref s) => s.get_id(),
            AMQPError::Hard(ref h) => h.get_id(),
        }
    }

    pub fn from_id(id: ShortUInt) -> Option<AMQPError> {
        AMQPSoftError::from_id(id).map(|e| AMQPError::Soft(e)).or_else(|| AMQPHardError::from_id(id).map(|e| AMQPError::Hard(e)))
    }
}

pub enum AMQPSoftError {
    {{#each protocol.soft_errors as |constant| ~}}
    {{camel constant.name}},
    {{/each ~}}
}

impl AMQPSoftError {
    pub fn get_id(&self) -> ShortUInt {
        match *self {
            {{#each protocol.soft_errors as |constant| ~}}
            AMQPSoftError::{{camel constant.name}} => {{constant.value}},
            {{/each ~}}
        }
    }

    pub fn from_id(id: ShortUInt) -> Option<AMQPSoftError> {
        match id {
            {{#each protocol.soft_errors as |constant| ~}}
            {{constant.value}} => Some(AMQPSoftError::{{camel constant.name}}),
            {{/each ~}}
            _                  => None,
        }
    }
}

pub enum AMQPHardError {
    {{#each protocol.hard_errors as |constant| ~}}
    {{camel constant.name}},
    {{/each ~}}
}

impl AMQPHardError {
    pub fn get_id(&self) -> ShortUInt {
        match *self {
            {{#each protocol.hard_errors as |constant| ~}}
            AMQPHardError::{{camel constant.name}} => {{constant.value}},
            {{/each ~}}
        }
    }

    pub fn from_id(id: ShortUInt) -> Option<AMQPHardError> {
        match id {
            {{#each protocol.hard_errors as |constant| ~}}
            {{constant.value}} => Some(AMQPHardError::{{camel constant.name}}),
            {{/each ~}}
            _                  => None,
        }
    }
}

{{#each protocol.classes as |class| ~}}
use self::{{snake class.name}}::parse_{{snake class.name}};
{{/each ~}}

/* FIXME: simplify and get rid of the Option/Some when nom supports trailing | */
named!(pub parse_class<AMQPClass>, map!(switch!(map!(parse_short_uint, Some),
    {{#each protocol.classes as |class| ~}}
    Some({{class.id}}) => map!(call!(parse_{{snake class.name}}), |c| Some(AMQPClass::{{camel class.name}}(c))) |
    {{/each ~}}
    None               => value!(None)
), |c: Option<AMQPClass>| c.expect("We can't get there as we mapped to Some, only there to get a parser after the trailing |")));

pub fn gen_class<'a>(input: (&'a mut [u8], usize), class: &AMQPClass) -> Result<(&'a mut [u8], usize), GenError> {
    match *class {
        {{#each protocol.classes as |class| ~}}
        AMQPClass::{{camel class.name}}(ref {{snake class.name}}) => {{snake class.name}}::gen_{{snake class.name}}(input, {{snake class.name}}),
        {{/each ~}}
    }
}

#[derive(Clone, Debug, PartialEq)]
pub enum AMQPClass {
    {{#each protocol.classes as |class| ~}}
    {{camel class.name}}({{snake class.name}}::Method),
    {{/each ~}}
}

{{#each protocol.classes as |class|}}
pub mod {{snake class.name}} {
    use super::*;

    /* FIXME: simplify and get rid of the Option/Some when nom supports trailing | */
    named!(pub parse_{{snake class.name}}<{{snake class.name}}::Method>, map!(switch!(map!(parse_short_uint, Some),
        {{#each class.methods as |method| ~}}
        Some({{method.id}}) => map!(call!(parse_{{snake method.name}}), |m| Some(Method::{{camel method.name}}(m))) |
        {{/each ~}}
        None                => value!(None)
    ), |c: Option<{{snake class.name}}::Method>| c.expect("We can't get there as we mapped to Some, only there to get a parser after the trailing |")));

    pub fn gen_{{snake class.name}}<'a>(input: (&'a mut [u8], usize), method: &Method) -> Result<(&'a mut [u8], usize), GenError> {
        match *method {
            {{#each class.methods as |method| ~}}
            Method::{{camel method.name}}(ref {{snake method.name}}) => {
                do_gen!(input,
                    gen_short_uint(&{{class.id}}) >>
                    gen_{{snake method.name}}({{snake method.name}})
                )
            },
            {{/each ~}}
        }
    }

    #[derive(Clone, Debug, PartialEq)]
    pub enum Method {
        {{#each class.methods as |method| ~}}
        {{camel method.name}}({{camel method.name}}),
        {{/each ~}}
    }

    {{#each class.methods as |method|}}
    #[derive(Clone, Debug, PartialEq)]
    pub struct {{camel method.name}} {
        {{#each_argument method.arguments as |argument| ~}}
        {{#if argument_is_value ~}}
        pub {{snake argument.name}}: {{argument.type}},
        {{else}}
        {{#each_flag argument as |flag| ~}}
        pub {{snake flag.name}}: Boolean,
        {{/each_flag ~}}
        {{/if ~}}
        {{/each_argument ~}}
    }

    named!(pub parse_{{snake method.name}}<{{camel method.name}}>, do_parse!(
        {{#each_argument method.arguments as |argument| ~}}
        {{#if argument_is_value ~}}
        {{snake argument.name}}: parse_{{snake_type argument.type}} >>
        {{else}}
        /* FIXME: support multiple flags structs? */
        flags: apply!(parse_flags, &vec![
            {{#each_flag argument as |flag| ~}}
            "{{flag.name}}",
            {{/each_flag ~}}
        ]) >>
        {{/if ~}}
        {{/each_argument ~}}
        ({{camel method.name}} {
            {{#each_argument method.arguments as |argument| ~}}
            {{#if argument_is_value ~}}
            {{snake argument.name}}: {{snake argument.name}},
            {{else}}
            {{#each_flag argument as |flag| ~}}
            {{snake flag.name}}: flags.get_flag("{{snake flag.name}}").unwrap_or({{flag.default_value}}),
            {{/each_flag ~}}
            {{/if ~}}
            {{/each_argument ~}}
        })
    ));

    pub fn gen_{{snake method.name}}<'a>(input: (&'a mut [u8], usize), {{#if method.has_arguments ~}}method{{else}}_{{/if ~}}: &{{camel method.name}}) -> Result<(&'a mut [u8],usize), GenError> {
        {{#if method.has_flags ~}}
        /* FIXME: support multiple flags structs? */
        let mut flags = AMQPFlags::new();
        {{#each_argument method.arguments as |argument| ~}}
        {{#unless argument_is_value ~}}
        {{#each_flag argument as |flag| ~}}
        flags.add_flag("{{snake flag.name}}".to_string(), method.{{snake flag.name}});
        {{/each_flag ~}}
        {{/unless ~}}
        {{/each_argument ~}}
        {{/if ~}}
        do_gen!(input,
            gen_short_uint(&{{method.id}})
            {{#each_argument method.arguments as |argument| ~}}
            {{#if argument_is_value ~}}
            >> gen_{{snake_type argument.type}}(&method.{{snake argument.name}})
            {{else}}
            >> gen_flags(&flags)
            {{/if ~}}
            {{/each_argument ~}}
        )
    }
    {{/each ~}}
}
{{/each ~}}
<|endoftext|>


<commit_before>use byteorder::{ByteOrder, LE};
use std::marker::PhantomData;
use std::{iter, mem};

use crate::{accessor, buffer};

fn buffer_view_slice<'a, 's>(
    view: buffer::View<'a>,
    get_buffer_data: &dyn Fn(buffer::Buffer<'a>) -> Option<&'s [u8]>,
) -> Option<&'s [u8]> {
    let start = view.offset();
    let end = start + view.length();
    get_buffer_data(view.buffer())
        .map(|slice| slice.get(start..end))
        .flatten()
}

/// General iterator for an accessor.
#[derive(Clone, Debug)]
pub enum Iter<'a, T: Item> {
    /// Standard accessor iterator.
    Standard(ItemIter<'a, T>),

    /// Iterator for accessor with sparse values.
    Sparse(SparseIter<'a, T>),
}

impl<'a, T: Item> Iterator for Iter<'a, T> {
    type Item = T;

    fn next(&mut self) -> Option<Self::Item> {
        match self {
            Iter::Standard(ref mut iter) => iter.next(),
            Iter::Sparse(ref mut iter) => iter.next(),
        }
    }

    fn nth(&mut self, nth: usize) -> Option<Self::Item> {
        match self {
            Iter::Standard(ref mut iter) => iter.nth(nth),
            Iter::Sparse(ref mut iter) => iter.nth(nth),
        }
    }

    fn last(self) -> Option<Self::Item> {
        match self {
            Iter::Standard(iter) => iter.last(),
            Iter::Sparse(iter) => iter.last(),
        }
    }

    fn count(self) -> usize {
        match self {
            Iter::Standard(iter) => iter.count(),
            Iter::Sparse(iter) => iter.count(),
        }
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        match self {
            Iter::Standard(ref iter) => iter.size_hint(),
            Iter::Sparse(ref iter) => iter.size_hint(),
        }
    }
}

impl<'a, T: Item> ExactSizeIterator for Iter<'a, T> {}

/// Iterator over indices of sparse accessor.
#[derive(Clone, Debug)]
pub enum SparseIndicesIter<'a> {
    /// 8-bit indices.
    U8(ItemIter<'a, u8>),
    /// 16-bit indices.
    U16(ItemIter<'a, u16>),
    /// 32-bit indices.
    U32(ItemIter<'a, u32>),
}

impl<'a> Iterator for SparseIndicesIter<'a> {
    type Item = u32;
    fn next(&mut self) -> Option<Self::Item> {
        match *self {
            SparseIndicesIter::U8(ref mut iter) => iter.next().map(|x| x as u32),
            SparseIndicesIter::U16(ref mut iter) => iter.next().map(|x| x as u32),
            SparseIndicesIter::U32(ref mut iter) => iter.next(),
        }
    }
}

/// Iterates over a sparse accessor.
#[derive(Clone, Debug)]
pub struct SparseIter<'a, T: Item> {
    /// Base value iterator.
    ///
    /// This can be `None` if the base buffer view is not set. In this case the base values are all zero.
    base: Option<ItemIter<'a, T>>,

    /// Sparse indices iterator.
    indices: iter::Peekable<SparseIndicesIter<'a>>,

    /// Sparse values iterator.
    values: ItemIter<'a, T>,

    /// Iterator counter.
    counter: u32,
}

impl<'a, T: Item> SparseIter<'a, T> {
    /// Constructor.
    ///
    /// Here `base` is allowed to be `None` when the base buffer view is not explicitly specified.
    pub fn new(
        base: Option<ItemIter<'a, T>>,
        indices: SparseIndicesIter<'a>,
        values: ItemIter<'a, T>,
    ) -> Self {
        SparseIter {
            base,
            indices: indices.peekable(),
            values,
            counter: 0,
        }
    }
}

impl<'a, T: Item> Iterator for SparseIter<'a, T> {
    type Item = T;
    fn next(&mut self) -> Option<Self::Item> {
        let mut next_value = self
            .base
            .as_mut()
            .map(|iter| iter.next())
            .unwrap_or_else(|| Some(T::zero()))?;

        let next_sparse_index = self.indices.peek();
        if let Some(index) = next_sparse_index {
            if *index == self.counter {
                self.indices.next(); // advance
                next_value = self.values.next().unwrap();
            }
        }

        self.counter += 1;

        Some(next_value)
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        let hint = self.values.len() - self.counter as usize;
        (hint, Some(hint))
    }
}

impl<'a, T: Item> ExactSizeIterator for SparseIter<'a, T> {}

/// Represents items that can be read by an [`Accessor`].
///
/// [`Accessor`]: struct.Accessor.html
pub trait Item {
    /// Create an object of this type from a byte slice.
    fn from_slice(slice: &[u8]) -> Self;
    /// Create an object of this type that represents a zero value.
    fn zero() -> Self;
}

/// Visits the items in an [`Accessor`].
///
/// [`Accessor`]: struct.Accessor.html
#[derive(Copy, Clone, Debug)]
pub struct ItemIter<'a, T: Item> {
    stride: usize,
    data: &'a [u8],
    _phantom: PhantomData<T>,
}

impl Item for i8 {
    fn from_slice(slice: &[u8]) -> Self {
        slice[0] as i8
    }
    fn zero() -> Self {
        0
    }
}

impl Item for i16 {
    fn from_slice(slice: &[u8]) -> Self {
        LE::read_i16(slice)
    }
    fn zero() -> Self {
        0
    }
}

impl Item for u8 {
    fn from_slice(slice: &[u8]) -> Self {
        slice[0]
    }
    fn zero() -> Self {
        0
    }
}

impl Item for u16 {
    fn from_slice(slice: &[u8]) -> Self {
        LE::read_u16(slice)
    }
    fn zero() -> Self {
        0
    }
}

impl Item for u32 {
    fn from_slice(slice: &[u8]) -> Self {
        LE::read_u32(slice)
    }
    fn zero() -> Self {
        0
    }
}

impl Item for f32 {
    fn from_slice(slice: &[u8]) -> Self {
        LE::read_f32(slice)
    }
    fn zero() -> Self {
        0.0
    }
}

impl<T: Item + Copy> Item for [T; 2] {
    fn from_slice(slice: &[u8]) -> Self {
        assert!(slice.len() >= 2 * mem::size_of::<T>());
        [
            T::from_slice(slice),
            T::from_slice(&slice[mem::size_of::<T>()..]),
        ]
    }
    fn zero() -> Self {
        [T::zero(); 2]
    }
}

impl<T: Item + Copy> Item for [T; 3] {
    fn from_slice(slice: &[u8]) -> Self {
        assert!(slice.len() >= 3 * mem::size_of::<T>());
        [
            T::from_slice(slice),
            T::from_slice(&slice[mem::size_of::<T>()..]),
            T::from_slice(&slice[2 * mem::size_of::<T>()..]),
        ]
    }
    fn zero() -> Self {
        [T::zero(); 3]
    }
}

impl<T: Item + Copy> Item for [T; 4] {
    fn from_slice(slice: &[u8]) -> Self {
        assert!(slice.len() >= 4 * mem::size_of::<T>());
        [
            T::from_slice(slice),
            T::from_slice(&slice[mem::size_of::<T>()..]),
            T::from_slice(&slice[2 * mem::size_of::<T>()..]),
            T::from_slice(&slice[3 * mem::size_of::<T>()..]),
        ]
    }
    fn zero() -> Self {
        [T::zero(); 4]
    }
}

impl<'a, T: Item> ItemIter<'a, T> {
    /// Constructor.
    pub fn new(slice: &'a [u8], stride: usize) -> Self {
        ItemIter {
            data: slice,
            stride,
            _phantom: PhantomData,
        }
    }
}

impl<'a, 's, T: Item> Iter<'s, T> {
    /// Constructor.
    pub fn new<F>(accessor: super::Accessor<'a>, get_buffer_data: F) -> Option<Iter<'s, T>>
    where
        F: Clone + Fn(buffer::Buffer<'a>) -> Option<&'s [u8]>,
    {
        let is_sparse = accessor.sparse().is_some();
        if is_sparse {
            let sparse = accessor.sparse();
            let indices = sparse.as_ref().unwrap().indices();
            let values = sparse.as_ref().unwrap().values();
            let base_iter = {
                // Using `if let` here instead of map to preserve the early return behavior.
                if let Some(view) = accessor.view() {
                    let stride = view.stride().unwrap_or(mem::size_of::<T>());
                    let start = accessor.offset();
                    let end = start + stride * (accessor.count() - 1) + mem::size_of::<T>();
                    let subslice = if let Some(slice) = buffer_view_slice(view, &get_buffer_data) {
                        slice.get(start..end)?
                    } else {
                        return None;
                    };
                    Some(ItemIter::new(subslice, stride))
                } else {
                    None
                }
            };
            let sparse_count = sparse.as_ref().unwrap().count() as usize;
            let index_iter = {
                let view = indices.view();
                let index_size = indices.index_type().size();
                let stride = view.stride().unwrap_or(index_size);
                let subslice = if let Some(slice) = buffer_view_slice(view, &get_buffer_data) {
                    let start = indices.offset() as usize;
                    let end = start + stride * (sparse_count - 1) + index_size;
                    slice.get(start..end)?
                } else {
                    return None;
                };
                match indices.index_type() {
                    accessor::sparse::IndexType::U8 => {
                        SparseIndicesIter::U8(ItemIter::new(subslice, stride))
                    }
                    accessor::sparse::IndexType::U16 => {
                        SparseIndicesIter::U16(ItemIter::new(subslice, stride))
                    }
                    accessor::sparse::IndexType::U32 => {
                        SparseIndicesIter::U32(ItemIter::new(subslice, stride))
                    }
                }
            };
            let value_iter = {
                let view = values.view();
                let stride = view.stride().unwrap_or(mem::size_of::<T>());
                let subslice = if let Some(slice) = buffer_view_slice(view, &get_buffer_data) {
                    let start = values.offset() as usize;
                    let end = start + stride * (sparse_count - 1) + mem::size_of::<T>();
                    slice.get(start..end)?
                } else {
                    return None;
                };
                ItemIter::new(subslice, stride)
            };
            Some(Iter::Sparse(SparseIter::new(
                base_iter, index_iter, value_iter,
            )))
        } else {
            debug_assert_eq!(mem::size_of::<T>(), accessor.size());
            debug_assert!(mem::size_of::<T>() > 0);
            if let Some(view) = accessor.view() {
                let stride = view.stride().unwrap_or(mem::size_of::<T>());
                debug_assert!(
                    stride >= mem::size_of::<T>(),
                    "Mismatch in stride, expected at least {} stride but found {}",
                    mem::size_of::<T>(),
                    stride
                );
                let start = accessor.offset();
                let end = start + stride * (accessor.count() - 1) + mem::size_of::<T>();
                let subslice = if let Some(slice) = buffer_view_slice(view, &get_buffer_data) {
                    slice.get(start..end)?
                } else {
                    return None;
                };
                Some(Iter::Standard(ItemIter {
                    stride,
                    data: subslice,
                    _phantom: PhantomData,
                }))
            } else {
                None
            }
        }
    }
}

impl<'a, T: Item> ExactSizeIterator for ItemIter<'a, T> {}
impl<'a, T: Item> Iterator for ItemIter<'a, T> {
    type Item = T;

    fn next(&mut self) -> Option<Self::Item> {
        let stride = if self.data.len() >= self.stride {
            Some(self.stride)
        } else if self.data.len() >= mem::size_of::<T>() {
            Some(mem::size_of::<T>())
        } else {
            None
        };
        if let Some(stride) = stride {
            let (val, data) = self.data.split_at(stride);
            let val = T::from_slice(val);
            self.data = data;
            Some(val)
        } else {
            None
        }
    }

    fn nth(&mut self, nth: usize) -> Option<Self::Item> {
        if let Some(val_data) = self.data.get(nth * self.stride..) {
            if val_data.len() >= mem::size_of::<T>() {
                let val = T::from_slice(val_data);
                self.data = &val_data[self.stride.min(val_data.len())..];
                Some(val)
            } else {
                None
            }
        } else {
            None
        }
    }

    fn last(self) -> Option<Self::Item> {
        if self.data.len() >= mem::size_of::<T>() {
            self.data
                .get((self.data.len() - 1) / self.stride * self.stride..)
                .map(T::from_slice)
        } else {
            None
        }
    }

    fn count(self) -> usize {
        self.size_hint().0
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        let hint = self.data.len() / self.stride
            + (self.data.len() % self.stride >= mem::size_of::<T>()) as usize;
        (hint, Some(hint))
    }
}
<commit_msg>Refactoring Iter constructor<commit_after>use byteorder::{ByteOrder, LE};
use std::marker::PhantomData;
use std::{iter, mem};

use crate::{accessor, buffer};

fn buffer_view_slice<'a, 's>(
    view: buffer::View<'a>,
    get_buffer_data: &dyn Fn(buffer::Buffer<'a>) -> Option<&'s [u8]>,
) -> Option<&'s [u8]> {
    let start = view.offset();
    let end = start + view.length();
    get_buffer_data(view.buffer())
        .map(|slice| slice.get(start..end))
        .flatten()
}

/// General iterator for an accessor.
#[derive(Clone, Debug)]
pub enum Iter<'a, T: Item> {
    /// Standard accessor iterator.
    Standard(ItemIter<'a, T>),

    /// Iterator for accessor with sparse values.
    Sparse(SparseIter<'a, T>),
}

impl<'a, T: Item> Iterator for Iter<'a, T> {
    type Item = T;

    fn next(&mut self) -> Option<Self::Item> {
        match self {
            Iter::Standard(ref mut iter) => iter.next(),
            Iter::Sparse(ref mut iter) => iter.next(),
        }
    }

    fn nth(&mut self, nth: usize) -> Option<Self::Item> {
        match self {
            Iter::Standard(ref mut iter) => iter.nth(nth),
            Iter::Sparse(ref mut iter) => iter.nth(nth),
        }
    }

    fn last(self) -> Option<Self::Item> {
        match self {
            Iter::Standard(iter) => iter.last(),
            Iter::Sparse(iter) => iter.last(),
        }
    }

    fn count(self) -> usize {
        match self {
            Iter::Standard(iter) => iter.count(),
            Iter::Sparse(iter) => iter.count(),
        }
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        match self {
            Iter::Standard(ref iter) => iter.size_hint(),
            Iter::Sparse(ref iter) => iter.size_hint(),
        }
    }
}

impl<'a, T: Item> ExactSizeIterator for Iter<'a, T> {}

/// Iterator over indices of sparse accessor.
#[derive(Clone, Debug)]
pub enum SparseIndicesIter<'a> {
    /// 8-bit indices.
    U8(ItemIter<'a, u8>),
    /// 16-bit indices.
    U16(ItemIter<'a, u16>),
    /// 32-bit indices.
    U32(ItemIter<'a, u32>),
}

impl<'a> Iterator for SparseIndicesIter<'a> {
    type Item = u32;
    fn next(&mut self) -> Option<Self::Item> {
        match *self {
            SparseIndicesIter::U8(ref mut iter) => iter.next().map(|x| x as u32),
            SparseIndicesIter::U16(ref mut iter) => iter.next().map(|x| x as u32),
            SparseIndicesIter::U32(ref mut iter) => iter.next(),
        }
    }
}

/// Iterates over a sparse accessor.
#[derive(Clone, Debug)]
pub struct SparseIter<'a, T: Item> {
    /// Base value iterator.
    ///
    /// This can be `None` if the base buffer view is not set. In this case the base values are all zero.
    base: Option<ItemIter<'a, T>>,

    /// Sparse indices iterator.
    indices: iter::Peekable<SparseIndicesIter<'a>>,

    /// Sparse values iterator.
    values: ItemIter<'a, T>,

    /// Iterator counter.
    counter: u32,
}

impl<'a, T: Item> SparseIter<'a, T> {
    /// Constructor.
    ///
    /// Here `base` is allowed to be `None` when the base buffer view is not explicitly specified.
    pub fn new(
        base: Option<ItemIter<'a, T>>,
        indices: SparseIndicesIter<'a>,
        values: ItemIter<'a, T>,
    ) -> Self {
        SparseIter {
            base,
            indices: indices.peekable(),
            values,
            counter: 0,
        }
    }
}

impl<'a, T: Item> Iterator for SparseIter<'a, T> {
    type Item = T;
    fn next(&mut self) -> Option<Self::Item> {
        let mut next_value = self
            .base
            .as_mut()
            .map(|iter| iter.next())
            .unwrap_or_else(|| Some(T::zero()))?;

        let next_sparse_index = self.indices.peek();
        if let Some(index) = next_sparse_index {
            if *index == self.counter {
                self.indices.next(); // advance
                next_value = self.values.next().unwrap();
            }
        }

        self.counter += 1;

        Some(next_value)
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        let hint = self.values.len() - self.counter as usize;
        (hint, Some(hint))
    }
}

impl<'a, T: Item> ExactSizeIterator for SparseIter<'a, T> {}

/// Represents items that can be read by an [`Accessor`].
///
/// [`Accessor`]: struct.Accessor.html
pub trait Item {
    /// Create an object of this type from a byte slice.
    fn from_slice(slice: &[u8]) -> Self;
    /// Create an object of this type that represents a zero value.
    fn zero() -> Self;
}

/// Visits the items in an [`Accessor`].
///
/// [`Accessor`]: struct.Accessor.html
#[derive(Copy, Clone, Debug)]
pub struct ItemIter<'a, T: Item> {
    stride: usize,
    data: &'a [u8],
    _phantom: PhantomData<T>,
}

impl Item for i8 {
    fn from_slice(slice: &[u8]) -> Self {
        slice[0] as i8
    }
    fn zero() -> Self {
        0
    }
}

impl Item for i16 {
    fn from_slice(slice: &[u8]) -> Self {
        LE::read_i16(slice)
    }
    fn zero() -> Self {
        0
    }
}

impl Item for u8 {
    fn from_slice(slice: &[u8]) -> Self {
        slice[0]
    }
    fn zero() -> Self {
        0
    }
}

impl Item for u16 {
    fn from_slice(slice: &[u8]) -> Self {
        LE::read_u16(slice)
    }
    fn zero() -> Self {
        0
    }
}

impl Item for u32 {
    fn from_slice(slice: &[u8]) -> Self {
        LE::read_u32(slice)
    }
    fn zero() -> Self {
        0
    }
}

impl Item for f32 {
    fn from_slice(slice: &[u8]) -> Self {
        LE::read_f32(slice)
    }
    fn zero() -> Self {
        0.0
    }
}

impl<T: Item + Copy> Item for [T; 2] {
    fn from_slice(slice: &[u8]) -> Self {
        assert!(slice.len() >= 2 * mem::size_of::<T>());
        [
            T::from_slice(slice),
            T::from_slice(&slice[mem::size_of::<T>()..]),
        ]
    }
    fn zero() -> Self {
        [T::zero(); 2]
    }
}

impl<T: Item + Copy> Item for [T; 3] {
    fn from_slice(slice: &[u8]) -> Self {
        assert!(slice.len() >= 3 * mem::size_of::<T>());
        [
            T::from_slice(slice),
            T::from_slice(&slice[mem::size_of::<T>()..]),
            T::from_slice(&slice[2 * mem::size_of::<T>()..]),
        ]
    }
    fn zero() -> Self {
        [T::zero(); 3]
    }
}

impl<T: Item + Copy> Item for [T; 4] {
    fn from_slice(slice: &[u8]) -> Self {
        assert!(slice.len() >= 4 * mem::size_of::<T>());
        [
            T::from_slice(slice),
            T::from_slice(&slice[mem::size_of::<T>()..]),
            T::from_slice(&slice[2 * mem::size_of::<T>()..]),
            T::from_slice(&slice[3 * mem::size_of::<T>()..]),
        ]
    }
    fn zero() -> Self {
        [T::zero(); 4]
    }
}

impl<'a, T: Item> ItemIter<'a, T> {
    /// Constructor.
    pub fn new(slice: &'a [u8], stride: usize) -> Self {
        ItemIter {
            data: slice,
            stride,
            _phantom: PhantomData,
        }
    }
}

impl<'a, 's, T: Item> Iter<'s, T> {
    /// Constructor.
    pub fn new<F>(accessor: super::Accessor<'a>, get_buffer_data: F) -> Option<Iter<'s, T>>
    where
        F: Clone + Fn(buffer::Buffer<'a>) -> Option<&'s [u8]>,
    {
        match accessor.sparse() {
            Some(sparse) => {
                // Using `if let` here instead of map to preserve the early return behavior.
                let base_iter = if let Some(view) = accessor.view() {
                    let stride = view.stride().unwrap_or(mem::size_of::<T>());

                    let start = accessor.offset();
                    let end = start + stride * (accessor.count() - 1) + mem::size_of::<T>();
                    let subslice = buffer_view_slice(view, &get_buffer_data)
                        .and_then(|slice| slice.get(start..end))?;

                    Some(ItemIter::new(subslice, stride))
                } else {
                    None
                };

                let indices = sparse.indices();
                let values = sparse.values();
                let sparse_count = sparse.count() as usize;

                let index_iter = {
                    let view = indices.view();
                    let index_size = indices.index_type().size();
                    let stride = view.stride().unwrap_or(index_size);

                    let start = indices.offset() as usize;
                    let end = start + stride * (sparse_count - 1) + index_size;
                    let subslice = buffer_view_slice(view, &get_buffer_data)
                        .and_then(|slice| slice.get(start..end))?;

                    match indices.index_type() {
                        accessor::sparse::IndexType::U8 => {
                            SparseIndicesIter::U8(ItemIter::new(subslice, stride))
                        }
                        accessor::sparse::IndexType::U16 => {
                            SparseIndicesIter::U16(ItemIter::new(subslice, stride))
                        }
                        accessor::sparse::IndexType::U32 => {
                            SparseIndicesIter::U32(ItemIter::new(subslice, stride))
                        }
                    }
                };

                let value_iter = {
                    let view = values.view();
                    let stride = view.stride().unwrap_or(mem::size_of::<T>());

                    let start = values.offset() as usize;
                    let end = start + stride * (sparse_count - 1) + mem::size_of::<T>();
                    let subslice = buffer_view_slice(view, &get_buffer_data)
                        .and_then(|slice| slice.get(start..end))?;

                    ItemIter::new(subslice, stride)
                };

                Some(Iter::Sparse(SparseIter::new(
                    base_iter, index_iter, value_iter,
                )))
            }
            None => {
                debug_assert_eq!(mem::size_of::<T>(), accessor.size());
                debug_assert!(mem::size_of::<T>() > 0);

                accessor.view().and_then(|view| {
                    let stride = view.stride().unwrap_or(mem::size_of::<T>());
                    debug_assert!(
                        stride >= mem::size_of::<T>(),
                        "Mismatch in stride, expected at least {} stride but found {}",
                        mem::size_of::<T>(),
                        stride
                    );

                    let start = accessor.offset();
                    let end = start + stride * (accessor.count() - 1) + mem::size_of::<T>();
                    let subslice = buffer_view_slice(view, &get_buffer_data)
                        .and_then(|slice| slice.get(start..end))?;

                    Some(Iter::Standard(ItemIter {
                        stride,
                        data: subslice,
                        _phantom: PhantomData,
                    }))
                })
            }
        }
    }
}

impl<'a, T: Item> ExactSizeIterator for ItemIter<'a, T> {}
impl<'a, T: Item> Iterator for ItemIter<'a, T> {
    type Item = T;

    fn next(&mut self) -> Option<Self::Item> {
        let stride = if self.data.len() >= self.stride {
            Some(self.stride)
        } else if self.data.len() >= mem::size_of::<T>() {
            Some(mem::size_of::<T>())
        } else {
            None
        };
        if let Some(stride) = stride {
            let (val, data) = self.data.split_at(stride);
            let val = T::from_slice(val);
            self.data = data;
            Some(val)
        } else {
            None
        }
    }

    fn nth(&mut self, nth: usize) -> Option<Self::Item> {
        if let Some(val_data) = self.data.get(nth * self.stride..) {
            if val_data.len() >= mem::size_of::<T>() {
                let val = T::from_slice(val_data);
                self.data = &val_data[self.stride.min(val_data.len())..];
                Some(val)
            } else {
                None
            }
        } else {
            None
        }
    }

    fn last(self) -> Option<Self::Item> {
        if self.data.len() >= mem::size_of::<T>() {
            self.data
                .get((self.data.len() - 1) / self.stride * self.stride..)
                .map(T::from_slice)
        } else {
            None
        }
    }

    fn count(self) -> usize {
        self.size_hint().0
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        let hint = self.data.len() / self.stride
            + (self.data.len() % self.stride >= mem::size_of::<T>()) as usize;
        (hint, Some(hint))
    }
}
<|endoftext|>


<commit_before>use std::any::{ Any, AnyMutRefExt };
use std::boxed::BoxAny;
use typedef::TypeDef;
use factory::{ Factory, Getter };

/// Proxy for configuring factory list without caring about the type used.
///
/// ```
/// # extern crate metafactory;
/// use std::any::Any;
/// use metafactory::{ metafactory, argless_as_factory, AsFactoryExt };
/// use metafactory::aggregate::Aggregate;
///
/// fn main() {
///     // Let's say we know that we will have bunch of `bool` factories.
///     // In that case we create a new aggregate for them:
///     let mut aggregate = Aggregate::new::<bool>();
///
///     // Once we actually have our factories, we can inject them into aggregate
///     // without dealing with types. Of course, we should make sure that types
///     // actually match before doing that in the code that is using this
///     // implementation.
///     aggregate.push_items(vec![
///         argless_as_factory(|| true),
///         argless_as_factory(true),
///         argless_as_factory(|| 4i == 8),
///     ]);
///
///     // Once we are ready to use the aggregate as factory, we can call `new_factory` to
///     // convert all dynamic stuff to statically constructed call hierarchy:
///     let anyed_bool_array_factory = aggregate.new_factory();
///
///     // Of course, that returns it anyed (`Box<Any>`), but we can easily get un-anyed version
///     // by downcasting to `Factory<Vec<bool>>` or using a convenience extension
///     // method for that:
///     let bool_array_factory = anyed_bool_array_factory
///         .as_factory_of::<Vec<bool>>().unwrap();
///
///     // Calling it should produce expected boolean vector:
///     assert_eq!(bool_array_factory.take(), vec![true, true, false]);
///
///     // Of course, the aggregate itself should be usable as argument
///     // for other factories:
///     let metafactory_all_true = metafactory(|values: Vec<bool>| {
///         values.iter().fold(true, |a, &i| a & i)
///     });
///
///     // We can pass it when constructing a factory for this lambda metafactory:
///     let factory_all_true = metafactory_all_true.new(vec![
///         box bool_array_factory.clone() as Box<Any>
///     ])
///         .ok().unwrap() // check for errors here
///         .as_factory_of::<bool>().unwrap() // same story with downcasting
///     ;
///
///     assert_eq!(factory_all_true.take(), false); // not all values are true
/// }
/// ```
pub struct Aggregate<'a> {
    typedef: TypeDef,
    any_getter: Box<Any>,
    do_push_items: |&mut Box<Any>, Vec<Box<Any>>|:'a -> (),
    do_new_factory: |&mut Box<Any>|:'a -> Box<Any>, // Don't worry, it's like Javascript ;)
}

impl<'a> Aggregate<'a> {
    /// Create new aggregate instance for specified type.
    pub fn new<T: 'static>() -> Aggregate<'a> {
        Aggregate {
            typedef: TypeDef::of::<T>(),
            any_getter: box AggregateGetter::<T>::new(),
            do_push_items: |any_getter, items| {
                let getter: &mut AggregateGetter<T> = any_getter
                    .downcast_mut::<AggregateGetter<T>>().unwrap();

                let len = items.len();
                let items_iter = items.into_iter()
                    .map(|i| *i.downcast::<Factory<T>>().ok().unwrap());

                getter.factories.reserve_exact(len);
                getter.factories.extend(items_iter);
            },
            do_new_factory: |any_getter| {
                let getter: &mut AggregateGetter<T> = any_getter
                    .downcast_mut::<AggregateGetter<T>>().unwrap();

                box Factory::<Vec<T>>::new(getter.boxed_clone())
            }
        }
    }

    /// Return aggregated type.
    pub fn get_arg_type(&self) -> TypeDef {
        self.typedef.clone()
    }

    /// Push factory items into aggregate.
    ///
    /// Note that all items should already match contained aggregate type:
    /// if aggregate was created for `int`, all pushed factories should
    /// produce int. Otherwise this method will panic your app.
    pub fn push_items(&mut self, items: Vec<Box<Any>>) {
        (self.do_push_items)(&mut self.any_getter, items);
    }

    /// Produces factory usable as argument for other factories.
    ///
    /// If inner factories make `int` values, this method will make factory
    /// that makes `Vec<int>` values.
    pub fn new_factory(&mut self) -> Box<Any> {
        (self.do_new_factory)(&mut self.any_getter)
    }

    /// Returns type which is used as aggregate result.
    pub fn container_of<T: 'static>() -> TypeDef {
        TypeDef::of::<&[T]>()
    }
}

struct AggregateGetter<T: 'static> {
    factories: Vec<Factory<T>>,
}

impl<T> Clone for AggregateGetter<T> {
    fn clone(&self) -> AggregateGetter<T> {
        AggregateGetter::<T> {
            factories: self.factories.clone()
        }
    }
}

impl<T> AggregateGetter<T> {
    pub fn new() -> AggregateGetter<T> {
        AggregateGetter::<T> {
            factories: Vec::with_capacity(0)
        }
    }
}

impl<T> Getter<Vec<T>> for AggregateGetter<T> {
    fn take(&self) -> Vec<T> {

        // Reserve exact result size.
        let mut items = Vec::<T>::with_capacity(self.factories.len());

        // Construct results from factory results.
        items.extend(
            self.factories.iter()
                .map(|f| f.take())
        );

        items
    }

    fn boxed_clone(&self) -> Box<Getter<Vec<T>> + 'static> {
        box self.clone()
    }
}

#[cfg(test)]
mod test {
    use { argless_as_factory, metafactory, AsFactoryExt };
    use super::{ Aggregate };

    #[test]
    fn should_be_usable_as_vec_of_types() {
        let mut container = Aggregate::new::<int>();
        container.push_items(vec![
            argless_as_factory(5i),
            argless_as_factory(13i)
        ]);

        let parent_metafactory = metafactory(
            |items: Vec<int>|
                items.into_iter()
                    .map(|i| format!("{}", i))
                    .collect::<Vec<String>>()
                    .connect(", ")
        );

        let parent_getter = parent_metafactory
            .new(vec![
                container.new_factory()
            ]).ok().unwrap()
            .as_factory_of::<String>().unwrap()
        ;

        assert_eq!(parent_getter.take(), "5, 13");
    }
}
<commit_msg>Fix wrong return type.<commit_after>use std::any::{ Any, AnyMutRefExt };
use std::boxed::BoxAny;
use typedef::TypeDef;
use factory::{ Factory, Getter };

/// Proxy for configuring factory list without caring about the type used.
///
/// ```
/// # extern crate metafactory;
/// use std::any::Any;
/// use metafactory::{ metafactory, argless_as_factory, AsFactoryExt };
/// use metafactory::aggregate::Aggregate;
///
/// fn main() {
///     // Let's say we know that we will have bunch of `bool` factories.
///     // In that case we create a new aggregate for them:
///     let mut aggregate = Aggregate::new::<bool>();
///
///     // Once we actually have our factories, we can inject them into aggregate
///     // without dealing with types. Of course, we should make sure that types
///     // actually match before doing that in the code that is using this
///     // implementation.
///     aggregate.push_items(vec![
///         argless_as_factory(|| true),
///         argless_as_factory(true),
///         argless_as_factory(|| 4i == 8),
///     ]);
///
///     // Once we are ready to use the aggregate as factory, we can call `new_factory` to
///     // convert all dynamic stuff to statically constructed call hierarchy:
///     let anyed_bool_array_factory = aggregate.new_factory();
///
///     // Of course, that returns it anyed (`Box<Any>`), but we can easily get un-anyed version
///     // by downcasting to `Factory<Vec<bool>>` or using a convenience extension
///     // method for that:
///     let bool_array_factory = anyed_bool_array_factory
///         .as_factory_of::<Vec<bool>>().unwrap();
///
///     // Calling it should produce expected boolean vector:
///     assert_eq!(bool_array_factory.take(), vec![true, true, false]);
///
///     // Of course, the aggregate itself should be usable as argument
///     // for other factories:
///     let metafactory_all_true = metafactory(|values: Vec<bool>| {
///         values.iter().fold(true, |a, &i| a & i)
///     });
///
///     // We can pass it when constructing a factory for this lambda metafactory:
///     let factory_all_true = metafactory_all_true.new(vec![
///         box bool_array_factory.clone() as Box<Any>
///     ])
///         .ok().unwrap() // check for errors here
///         .as_factory_of::<bool>().unwrap() // same story with downcasting
///     ;
///
///     assert_eq!(factory_all_true.take(), false); // not all values are true
/// }
/// ```
pub struct Aggregate<'a> {
    typedef: TypeDef,
    any_getter: Box<Any>,
    do_push_items: |&mut Box<Any>, Vec<Box<Any>>|:'a -> (),
    do_new_factory: |&mut Box<Any>|:'a -> Box<Any>, // Don't worry, it's like Javascript ;)
}

impl<'a> Aggregate<'a> {
    /// Create new aggregate instance for specified type.
    pub fn new<T: 'static>() -> Aggregate<'a> {
        Aggregate {
            typedef: TypeDef::of::<T>(),
            any_getter: box AggregateGetter::<T>::new(),
            do_push_items: |any_getter, items| {
                let getter: &mut AggregateGetter<T> = any_getter
                    .downcast_mut::<AggregateGetter<T>>().unwrap();

                let len = items.len();
                let items_iter = items.into_iter()
                    .map(|i| *i.downcast::<Factory<T>>().ok().unwrap());

                getter.factories.reserve_exact(len);
                getter.factories.extend(items_iter);
            },
            do_new_factory: |any_getter| {
                let getter: &mut AggregateGetter<T> = any_getter
                    .downcast_mut::<AggregateGetter<T>>().unwrap();

                box Factory::<Vec<T>>::new(getter.boxed_clone())
            }
        }
    }

    /// Return aggregated type.
    pub fn get_arg_type(&self) -> TypeDef {
        self.typedef.clone()
    }

    /// Push factory items into aggregate.
    ///
    /// Note that all items should already match contained aggregate type:
    /// if aggregate was created for `int`, all pushed factories should
    /// produce int. Otherwise this method will panic your app.
    pub fn push_items(&mut self, items: Vec<Box<Any>>) {
        (self.do_push_items)(&mut self.any_getter, items);
    }

    /// Produces factory usable as argument for other factories.
    ///
    /// If inner factories make `int` values, this method will make factory
    /// that makes `Vec<int>` values.
    pub fn new_factory(&mut self) -> Box<Any> {
        (self.do_new_factory)(&mut self.any_getter)
    }

    /// Returns type which is used as aggregate result.
    pub fn container_of<T: 'static>() -> TypeDef {
        TypeDef::of::<Vec<T>>()
    }
}

struct AggregateGetter<T: 'static> {
    factories: Vec<Factory<T>>,
}

impl<T> Clone for AggregateGetter<T> {
    fn clone(&self) -> AggregateGetter<T> {
        AggregateGetter::<T> {
            factories: self.factories.clone()
        }
    }
}

impl<T> AggregateGetter<T> {
    pub fn new() -> AggregateGetter<T> {
        AggregateGetter::<T> {
            factories: Vec::with_capacity(0)
        }
    }
}

impl<T> Getter<Vec<T>> for AggregateGetter<T> {
    fn take(&self) -> Vec<T> {

        // Reserve exact result size.
        let mut items = Vec::<T>::with_capacity(self.factories.len());

        // Construct results from factory results.
        items.extend(
            self.factories.iter()
                .map(|f| f.take())
        );

        items
    }

    fn boxed_clone(&self) -> Box<Getter<Vec<T>> + 'static> {
        box self.clone()
    }
}

#[cfg(test)]
mod test {
    use { argless_as_factory, metafactory, AsFactoryExt };
    use super::{ Aggregate };

    #[test]
    fn should_be_usable_as_vec_of_types() {
        let mut container = Aggregate::new::<int>();
        container.push_items(vec![
            argless_as_factory(5i),
            argless_as_factory(13i)
        ]);

        let parent_metafactory = metafactory(
            |items: Vec<int>|
                items.into_iter()
                    .map(|i| format!("{}", i))
                    .collect::<Vec<String>>()
                    .connect(", ")
        );

        let parent_getter = parent_metafactory
            .new(vec![
                container.new_factory()
            ]).ok().unwrap()
            .as_factory_of::<String>().unwrap()
        ;

        assert_eq!(parent_getter.take(), "5, 13");
    }
}
<|endoftext|>