<commit_before>// Copyright (c) 2015-2019 William (B.J.) Snow Orvis
//
// 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.

//! Data structures describing each fractal or curve that the program can draw.
//!
//! The data structures also provide a closure to process configuration for each curve and
//! configure a `WindowHandler` to handle callbacks from the event loop.

use super::pistonrendering;
use fractal_lib::chaosgame::barnsleyfern;
use fractal_lib::chaosgame::sierpinski::SierpinskiChaosGame;
use fractal_lib::chaosgame::ChaosGameMoveIterator;
use fractal_lib::curves::cesaro::CesaroFractal;
use fractal_lib::curves::cesarotri::CesaroTriFractal;
use fractal_lib::curves::dragon::DragonFractal;
use fractal_lib::curves::kochcurve::KochCurve;
use fractal_lib::curves::levyccurve::LevyCCurve;
use fractal_lib::curves::terdragon::TerdragonFractal;
use fractal_lib::escapetime::burningship::*;
use fractal_lib::escapetime::mandelbrot::Mandelbrot;
use fractal_lib::escapetime::EscapeTime;
use fractal_lib::lindenmayer::LindenmayerSystemTurtleProgram;
use fractal_lib::turtle::TurtleProgram;
use fractal_lib::SelectedFractal;
use std::str::FromStr;
use std::sync::Arc;
use strum::IntoEnumIterator;

/// Helper to get the size of a list of expressions
#[allow(unused_macros)]
macro_rules! count_exprs {
    () => (0);
    ($head:expr) => (1);
    ($head:expr, $($tail:expr),*) => (1 + count_exprs!($($tail),*));
}

/// Helper to extract and parse a value from a command line argument.
macro_rules! extract {
    ($matches:expr, $name:expr) => {
        $matches
            .value_of($name)
            .map(|s| parse_arg($name, s))
            .unwrap_or_else(|| Err(format!("Missing {}", $name)))
    };
}

/// Method to help with parsing a command line argument into some other type.
pub fn parse_arg<T>(opt_name: &str, opt_val: &str) -> Result<T, String>
where
    T: std::str::FromStr,
    <T as std::str::FromStr>::Err: std::fmt::Display,
{
    match opt_val.parse::<T>() {
        Err(e) => Err(format!("Error parsing {}: {}", opt_name, e)),
        Ok(v) => Ok(v),
    }
}

/// A subcommand that can configure and run a particular fractal renderer.
pub trait FractalSubcommand {
    /// Returns a clap::App definition of this subcommand. The command line arguments it
    /// specifies
    /// should then be handled by the `run()` method.
    fn command(&self, name: &'static str, description: &'static str)
        -> clap::App<'static, 'static>;

    /// Runs the command with the given command line arguments and the provided callback.
    fn run(&self, matches: &clap::ArgMatches) -> Result<(), String>;
}

pub struct ChaosGameCommand<E>
where
    E: ChaosGameMoveIterator,
{
    ctor: Box<dyn Fn() -> E>,
}

impl<E> ChaosGameCommand<E>
where
    E: ChaosGameMoveIterator,
{
    pub fn new(ctor: Box<dyn Fn() -> E>) -> ChaosGameCommand<E> {
        ChaosGameCommand { ctor }
    }
}

impl<E> FractalSubcommand for ChaosGameCommand<E>
where
    E: ChaosGameMoveIterator + 'static,
{
    fn command(
        &self,
        name: &'static str,
        description: &'static str,
    ) -> clap::App<'static, 'static> {
        clap::SubCommand::with_name(name).about(description).arg(
            clap::Arg::with_name("drawrate")
                .takes_value(true)
                .help("The number of points to draw per frame")
                .long("drawrate")
                .value_name("MPF")
                .default_value("1"),
        )
    }

    fn run(&self, matches: &clap::ArgMatches) -> Result<(), String> {
        let drawrate = extract!(matches, "drawrate")?;

        let game = Box::new((self.ctor)());
        let mut handler = pistonrendering::chaosgame::ChaosGameWindowHandler::new(game, drawrate);
        pistonrendering::run(&mut handler);

        Ok(())
    }
}

pub struct EscapeTimeCommand<E>
where
    E: EscapeTime + Send + Sync,
{
    ctor: Box<dyn Fn(u64, u64) -> E>,
}

impl<E> EscapeTimeCommand<E>
where
    E: EscapeTime + Send + Sync,
{
    pub fn new(ctor: Box<dyn Fn(u64, u64) -> E>) -> EscapeTimeCommand<E> {
        EscapeTimeCommand { ctor }
    }
}

impl<E> FractalSubcommand for EscapeTimeCommand<E>
where
    E: EscapeTime + Send + Sync + 'static,
{
    fn command(
        &self,
        name: &'static str,
        description: &'static str,
    ) -> clap::App<'static, 'static> {
        clap::SubCommand::with_name(name)
            .about(description)
            .arg(
                clap::Arg::with_name("MAX_ITERATIONS")
                    .required(true)
                    .index(1)
                    .help(
                        "The maximum number of iterations of the escape time function before \
                         deciding the fracal has escaped",
                    ),
            )
            .arg(
                clap::Arg::with_name("POWER")
                    .required(true)
                    .index(2)
                    .help("The exponent used in the escape time function (positive integer)"),
            )
    }

    fn run(&self, matches: &clap::ArgMatches) -> Result<(), String> {
        let max_iterations = (extract!(matches, "MAX_ITERATIONS"))?;
        // .unwrap_or_else(|| return Err("Must specify a MAX_ITERATIONS of 1 or greater!"));
        let power = (extract!(matches, "POWER"))?;
        // .unwrap_or_else(|| return Err("Must specify a POWER of 1 or greater!"));

        // The ctor callback can return a raw object that implements EscapeTime because this method
        // is templated to E instead of handling a boxed object that implements EscapeTime.
        //
        // We could alternately avoid using templating, in which case the callback would have to
        // return an Arc<EscapeTime> in order to abstract away the implementation of the trait.
        let et = Arc::new((self.ctor)(max_iterations, power));
        // TODO: `et` when passed in here wants E to be constraint by `'static`. Why?
        let mut handler = pistonrendering::escapetime::EscapeTimeWindowHandler::new(et);
        pistonrendering::run(&mut handler);

        Ok(())
    }
}

pub struct TurtleCommand<E>
where
    E: TurtleProgram,
{
    ctor: Box<dyn Fn(u64) -> E>,
}

impl<E> TurtleCommand<E>
where
    E: TurtleProgram,
{
    pub fn new(ctor: Box<dyn Fn(u64) -> E>) -> TurtleCommand<E> {
        TurtleCommand { ctor }
    }
}

impl<E> FractalSubcommand for TurtleCommand<E>
where
    E: TurtleProgram + 'static,
{
    fn command(
        &self,
        name: &'static str,
        description: &'static str,
    ) -> clap::App<'static, 'static> {
        clap::SubCommand::with_name(name)
            .about(description)
            .arg(
                clap::Arg::with_name("drawrate")
                    .takes_value(true)
                    .help("The number of points to draw per frame")
                    .long("drawrate")
                    .value_name("MPF")
                    .default_value("1"),
            )
            .arg(clap::Arg::with_name("ITERATION").required(true).index(1))
    }

    fn run(&self, matches: &clap::ArgMatches) -> Result<(), String> {
        let drawrate = (extract!(matches, "drawrate"))?;
        let iteration = (extract!(matches, "ITERATION"))?;
        // .unwrap_or_else(|| Err("Must specify an ITERATION of 1 or greater!"));

        let program = (self.ctor)(iteration);
        let mut handler =
            pistonrendering::turtle::construct_turtle_window_handler(&program, drawrate);
        pistonrendering::run(&mut *handler);

        Ok(())
    }
}

pub trait SelectedFractalExt {
    fn subcommand(&self) -> Box<dyn FractalSubcommand>;
}

impl SelectedFractalExt for SelectedFractal {
    fn subcommand(&self) -> Box<dyn FractalSubcommand> {
        match self {
            SelectedFractal::BarnsleyFern => Box::new(ChaosGameCommand::new(Box::new(|| {
                barnsleyfern::BarnsleyFern::new(
                    &barnsleyfern::REFERENCE_TRANSFORMS,
                    &barnsleyfern::REFERENCE_WEIGHTS,
                )
            }))),
            SelectedFractal::BurningMandel => {
                Box::new(EscapeTimeCommand::new(Box::new(|max_iterations, power| {
                    BurningMandel::new(max_iterations, power)
                })))
            }
            SelectedFractal::BurningShip => {
                Box::new(EscapeTimeCommand::new(Box::new(|max_iterations, power| {
                    BurningShip::new(max_iterations, power)
                })))
            }
            SelectedFractal::Cesaro => Box::new(TurtleCommand::new(Box::new(|iteration| {
                LindenmayerSystemTurtleProgram::new(CesaroFractal::new(iteration))
            }))),
            SelectedFractal::CesaroTri => Box::new(TurtleCommand::new(Box::new(|iteration| {
                LindenmayerSystemTurtleProgram::new(CesaroTriFractal::new(iteration))
            }))),
            SelectedFractal::Dragon => Box::new(TurtleCommand::new(Box::new(DragonFractal::new))),
            SelectedFractal::KochCurve => Box::new(TurtleCommand::new(Box::new(|iteration| {
                LindenmayerSystemTurtleProgram::new(KochCurve::new(iteration))
            }))),
            SelectedFractal::LevyCCurve => Box::new(TurtleCommand::new(Box::new(|iteration| {
                LindenmayerSystemTurtleProgram::new(LevyCCurve::new(iteration))
            }))),
            SelectedFractal::Mandelbrot => {
                Box::new(EscapeTimeCommand::new(Box::new(|max_iterations, power| {
                    Mandelbrot::new(max_iterations, power)
                })))
            }
            SelectedFractal::RoadRunner => {
                Box::new(EscapeTimeCommand::new(Box::new(|max_iterations, power| {
                    RoadRunner::new(max_iterations, power)
                })))
            }
            SelectedFractal::Sierpinski => {
                Box::new(ChaosGameCommand::new(Box::new(SierpinskiChaosGame::new)))
            }
            SelectedFractal::TerDragon => Box::new(TurtleCommand::new(Box::new(|iteration| {
                LindenmayerSystemTurtleProgram::new(TerdragonFractal::new(iteration))
            }))),
        }
    }
}

pub fn add_subcommands<'a, 'b>(app: clap::App<'a, 'b>) -> clap::App<'a, 'b> {
    let mut app = app;
    for fractal in SelectedFractal::iter() {
        app = app.subcommand(
            fractal
                .subcommand()
                .command(fractal.into(), fractal.description()),
        );
    }
    app
}

pub fn run_subcommand(app_argmatches: &clap::ArgMatches) -> Result<(), String> {
    let (name, maybe_args) = app_argmatches.subcommand();
    if let Some(args) = maybe_args {
        if let Ok(fractal) = SelectedFractal::from_str(name) {
            fractal.subcommand().run(&args)
        } else {
            Err("Unknown subcommand".to_string())
        }
    } else {
        Err("Unknown subcommand".to_string())
    }
}
<commit_msg>Continue simplifying the fractaldata for fractal-piston<commit_after>// Copyright (c) 2015-2019 William (B.J.) Snow Orvis
//
// 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.

//! Code and data structures that glue together command line arguments to the code that draws them.

use super::pistonrendering;
use fractal_lib::chaosgame::barnsleyfern;
use fractal_lib::chaosgame::sierpinski::SierpinskiChaosGame;
use fractal_lib::chaosgame::ChaosGameMoveIterator;
use fractal_lib::curves::cesaro::CesaroFractal;
use fractal_lib::curves::cesarotri::CesaroTriFractal;
use fractal_lib::curves::dragon::DragonFractal;
use fractal_lib::curves::kochcurve::KochCurve;
use fractal_lib::curves::levyccurve::LevyCCurve;
use fractal_lib::curves::terdragon::TerdragonFractal;
use fractal_lib::escapetime::burningship::*;
use fractal_lib::escapetime::mandelbrot::Mandelbrot;
use fractal_lib::escapetime::EscapeTime;
use fractal_lib::lindenmayer::LindenmayerSystemTurtleProgram;
use fractal_lib::turtle::TurtleProgram;
use fractal_lib::{FractalCategory, SelectedFractal};
use std::str::FromStr;
use std::sync::Arc;
use strum::IntoEnumIterator;

/// Helper to extract and parse a value from a clap command line argument.
macro_rules! extract {
    ($matches:expr, $name:expr) => {
        $matches
            .value_of($name)
            .map(|s| parse_arg($name, s))
            .unwrap_or_else(|| Err(format!("Missing {}", $name)))
    };
}

/// Function to help with parsing a command line argument into some other type.
pub fn parse_arg<T>(opt_name: &str, opt_val: &str) -> Result<T, String>
where
    T: std::str::FromStr,
    <T as std::str::FromStr>::Err: std::fmt::Display,
{
    match opt_val.parse::<T>() {
        Err(e) => Err(format!("Error parsing {}: {}", opt_name, e)),
        Ok(v) => Ok(v),
    }
}

fn run_chaos_game<E, F>(ctor: &F, matches: &clap::ArgMatches) -> Result<(), String>
where
    E: ChaosGameMoveIterator + 'static,
    F: Fn() -> E,
{
    let drawrate = extract!(matches, "drawrate")?;

    let game = Box::new((ctor)());
    let mut handler = pistonrendering::chaosgame::ChaosGameWindowHandler::new(game, drawrate);
    pistonrendering::run(&mut handler);

    Ok(())
}

fn run_escape_time<E, F>(ctor: &F, matches: &clap::ArgMatches) -> Result<(), String>
where
    E: EscapeTime + Send + Sync + 'static,
    F: Fn(u64, u64) -> E,
{
    let max_iterations = (extract!(matches, "MAX_ITERATIONS"))?;
    // .unwrap_or_else(|| return Err("Must specify a MAX_ITERATIONS of 1 or greater!"));
    let power = (extract!(matches, "POWER"))?;
    // .unwrap_or_else(|| return Err("Must specify a POWER of 1 or greater!"));

    let et = Arc::new((ctor)(max_iterations, power));
    // TODO: `et` when passed in here wants E to be constraint by `'static`. Why?
    let mut handler = pistonrendering::escapetime::EscapeTimeWindowHandler::new(et);
    pistonrendering::run(&mut handler);

    Ok(())
}

fn run_turtle<E, F>(ctor: &F, matches: &clap::ArgMatches) -> Result<(), String>
where
    E: TurtleProgram + 'static,
    F: Fn(u64) -> E,
{
    let drawrate = (extract!(matches, "drawrate"))?;
    let iteration = (extract!(matches, "ITERATION"))?;
    // .unwrap_or_else(|| Err("Must specify an ITERATION of 1 or greater!"));

    let program = (ctor)(iteration);
    let mut handler = pistonrendering::turtle::construct_turtle_window_handler(&program, drawrate);
    pistonrendering::run(&mut *handler);

    Ok(())
}

trait SelectedFractalExt {
    fn clap_subcommand(&self) -> clap::App<'static, 'static>;
    fn run(&self, matches: &clap::ArgMatches) -> Result<(), String>;
}

impl SelectedFractalExt for SelectedFractal {
    /// Constructs a clap subcommand for a given `SelectedFractal` variant.
    ///
    /// It uses the fractal's category to determine which input arguments it supports.
    fn clap_subcommand(&self) -> clap::App<'static, 'static> {
        let subcommand = clap::SubCommand::with_name(self.into()).about(self.description());
        match self.category() {
            FractalCategory::ChaosGames => subcommand.arg(
                clap::Arg::with_name("drawrate")
                    .takes_value(true)
                    .help("The number of points to draw per frame")
                    .long("drawrate")
                    .value_name("MPF")
                    .default_value("1"),
            ),
            FractalCategory::EscapeTimeFractals => subcommand
                .arg(
                    clap::Arg::with_name("MAX_ITERATIONS")
                        .required(true)
                        .index(1)
                        .help(
                            "The maximum number of iterations of the escape time function before \
                         deciding the fracal has escaped",
                        ),
                )
                .arg(
                    clap::Arg::with_name("POWER")
                        .required(true)
                        .index(2)
                        .help("The exponent used in the escape time function (positive integer)"),
                ),
            FractalCategory::TurtleCurves => subcommand
                .arg(
                    clap::Arg::with_name("drawrate")
                        .takes_value(true)
                        .help("The number of points to draw per frame")
                        .long("drawrate")
                        .value_name("MPF")
                        .default_value("1"),
                )
                .arg(clap::Arg::with_name("ITERATION").required(true).index(1)),
        }
    }

    /// Parses the clap arguments for the command launches an animated renderer for the specified
    /// fractal variant.
    fn run(&self, matches: &clap::ArgMatches) -> Result<(), String> {
        match self {
            SelectedFractal::BarnsleyFern => run_chaos_game(
                &|| {
                    barnsleyfern::BarnsleyFern::new(
                        &barnsleyfern::REFERENCE_TRANSFORMS,
                        &barnsleyfern::REFERENCE_WEIGHTS,
                    )
                },
                matches,
            ),
            SelectedFractal::BurningMandel => run_escape_time(&BurningMandel::new, matches),
            SelectedFractal::BurningShip => run_escape_time(&BurningShip::new, matches),
            SelectedFractal::Cesaro => run_turtle(
                &|iteration| LindenmayerSystemTurtleProgram::new(CesaroFractal::new(iteration)),
                matches,
            ),
            SelectedFractal::CesaroTri => run_turtle(
                &|iteration| LindenmayerSystemTurtleProgram::new(CesaroTriFractal::new(iteration)),
                matches,
            ),
            SelectedFractal::Dragon => run_turtle(&DragonFractal::new, matches),
            SelectedFractal::KochCurve => run_turtle(
                &|iteration| LindenmayerSystemTurtleProgram::new(KochCurve::new(iteration)),
                matches,
            ),
            SelectedFractal::LevyCCurve => run_turtle(
                &|iteration| LindenmayerSystemTurtleProgram::new(LevyCCurve::new(iteration)),
                matches,
            ),
            SelectedFractal::Mandelbrot => run_escape_time(&Mandelbrot::new, matches),
            SelectedFractal::RoadRunner => run_escape_time(&RoadRunner::new, matches),
            SelectedFractal::Sierpinski => run_chaos_game(&SierpinskiChaosGame::new, matches),
            SelectedFractal::TerDragon => run_turtle(
                &|iteration| LindenmayerSystemTurtleProgram::new(TerdragonFractal::new(iteration)),
                matches,
            ),
        }
    }
}

pub fn add_subcommands<'a, 'b>(app: clap::App<'a, 'b>) -> clap::App<'a, 'b> {
    let mut app = app;
    for fractal in SelectedFractal::iter() {
        app = app.subcommand(fractal.clap_subcommand());
    }
    app
}

pub fn run_subcommand(app_argmatches: &clap::ArgMatches) -> Result<(), String> {
    let (name, maybe_args) = app_argmatches.subcommand();
    if let Some(args) = maybe_args {
        if let Ok(fractal) = SelectedFractal::from_str(name) {
            fractal.run(&args)
        } else {
            Err("Unknown subcommand".to_string())
        }
    } else {
        Err("Unknown subcommand".to_string())
    }
}
<|endoftext|>


<commit_before>// Copyright 2014 The Servo Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use layers::{BufferRequest, ContentAge, LayerBuffer};
use platform::surface::{NativeCompositingGraphicsContext, NativeSurfaceMethods};
use texturegl::Texture;

use geom::matrix::{Matrix4, identity};
use geom::point::Point2D;
use geom::size::Size2D;
use geom::rect::Rect;
use std::collections::hashmap::HashMap;
use std::iter::range_inclusive;
use std::mem;
use std::num::Zero;

pub struct Tile {
    /// The buffer displayed by this tile.
    buffer: Option<Box<LayerBuffer>>,

    /// The content age of any pending buffer request to avoid re-requesting
    /// a buffer while waiting for it to come back from rendering.
    content_age_of_pending_buffer: Option<ContentAge>,

    /// A handle to the GPU texture.
    pub texture: Texture,

    /// The transformation applied to this tiles texture.
    pub transform: Matrix4<f32>,
}

impl Tile {
    fn new() -> Tile {
        Tile {
            buffer: None,
            texture: Zero::zero(),
            transform: identity(),
            content_age_of_pending_buffer: None,
        }
    }

    fn should_use_new_buffer(&self, new_buffer: &Box<LayerBuffer>) -> bool {
        match self.buffer {
            Some(ref buffer) => new_buffer.content_age >= buffer.content_age,
            None => true,
        }
    }

    fn replace_buffer(&mut self, buffer: Box<LayerBuffer>) -> Option<Box<LayerBuffer>> {
        if !self.should_use_new_buffer(&buffer) {
            warn!("Layer received an old buffer.");
            return Some(buffer);
        }

        let old_buffer = self.buffer.take();
        self.buffer = Some(buffer);
        self.texture = Zero::zero(); // The old texture is bound to the old buffer.
        self.content_age_of_pending_buffer = None;
        return old_buffer;
    }

    fn create_texture(&mut self, graphics_context: &NativeCompositingGraphicsContext) {
        match self.buffer {
            Some(ref buffer) => {
                let size = Size2D(buffer.screen_pos.size.width as int,
                                  buffer.screen_pos.size.height as int);

                // If we already have a texture it should still be valid.
                if !self.texture.is_zero() {
                    return;
                }

                // Make a new texture and bind the LayerBuffer's surface to it.
                self.texture = Texture::new_with_buffer(buffer);
                debug!("Tile: binding to native surface {:d}",
                       buffer.native_surface.get_id() as int);
                buffer.native_surface.bind_to_texture(graphics_context, &self.texture, size);

                // Set the layer's transform.
                let rect = buffer.rect;
                let transform = identity().translate(rect.origin.x, rect.origin.y, 0.0);
                self.transform = transform.scale(rect.size.width, rect.size.height, 1.0);
            },
            None => {},
        }
    }

    fn should_request_buffer(&self, content_age: ContentAge) -> bool {
        // Don't resend a request if our buffer's content age matches the current content age.
        match self.buffer {
            Some(ref buffer) => {
                if buffer.content_age >= content_age {
                    return false;
                }
            }
            None => {}
        }

        // Don't resend a request, if we already have one pending.
        match self.content_age_of_pending_buffer {
            Some(pending_content_age) => pending_content_age != content_age,
            None => true,
        }
    }
}

pub struct TileGrid {
    pub tiles: HashMap<Point2D<uint>, Tile>,

    // The size of tiles in this grid in device pixels.
    tile_size: uint,

    // Buffers that are currently unused.
    unused_buffers: Vec<Box<LayerBuffer>>,
}

pub fn rect_uint_as_rect_f32(rect: Rect<uint>) -> Rect<f32> {
    Rect(Point2D(rect.origin.x as f32, rect.origin.y as f32),
         Size2D(rect.size.width as f32, rect.size.height as f32))
}

impl TileGrid {
    pub fn new(tile_size: uint) -> TileGrid {
        TileGrid {
            tiles: HashMap::new(),
            tile_size: tile_size,
            unused_buffers: Vec::new(),
        }
    }

    pub fn get_tile_index_range_for_rect(&self, rect: Rect<f32>) -> (Point2D<uint>, Point2D<uint>) {
        (Point2D((rect.origin.x / self.tile_size as f32) as uint,
                 (rect.origin.y / self.tile_size as f32) as uint),
         Point2D(((rect.origin.x + rect.size.width) / self.tile_size as f32) as uint,
                 ((rect.origin.y + rect.size.height) / self.tile_size as f32) as uint))
    }

    pub fn get_rect_for_tile_index(&self, tile_index: Point2D<uint>) -> Rect<uint> {
        Rect(Point2D(self.tile_size * tile_index.x, self.tile_size * tile_index.y),
             Size2D(self.tile_size, self.tile_size))
    }

    pub fn take_unused_buffers(&mut self) -> Vec<Box<LayerBuffer>> {
        let mut unused_buffers = Vec::new();
        mem::swap(&mut unused_buffers, &mut self.unused_buffers);
        return unused_buffers;
    }

    pub fn add_unused_buffer(&mut self, buffer: Option<Box<LayerBuffer>>) {
        match buffer {
            Some(buffer) => self.unused_buffers.push(buffer),
            None => {},
        }
    }

    pub fn mark_tiles_outside_of_rect_as_unused(&mut self, rect: Rect<f32>) {
        let mut tile_indexes_to_take = Vec::new();
        for tile_index in self.tiles.keys() {
            if !rect_uint_as_rect_f32(self.get_rect_for_tile_index(*tile_index)).intersects(&rect) {
                tile_indexes_to_take.push(tile_index.clone());
            }
        }

        for tile_index in tile_indexes_to_take.iter() {
            match self.tiles.pop(tile_index) {
                Some(ref mut tile) => self.add_unused_buffer(tile.buffer.take()),
                None => {},
            }
        }
    }

    pub fn get_buffer_request_for_tile(&mut self,
                                       tile_index: Point2D<uint>,
                                       current_content_age: ContentAge)
                                       -> Option<BufferRequest> {
        let tile_rect = self.get_rect_for_tile_index(tile_index);
        let tile_screen_rect = rect_uint_as_rect_f32(tile_rect);

        let tile = self.tiles.find_or_insert_with(tile_index, |_| Tile::new());
        if !tile.should_request_buffer(current_content_age) {
            return None;
        }

        tile.content_age_of_pending_buffer = Some(current_content_age);
        return Some(BufferRequest::new(tile_rect, tile_screen_rect, current_content_age));
    }

    pub fn get_buffer_requests_in_rect(&mut self,
                                       screen_rect: Rect<f32>,
                                       current_content_age: ContentAge)
                                       -> Vec<BufferRequest> {
        let mut buffer_requests = Vec::new();
        let rect_in_layer_pixels = screen_rect;
        let (top_left_index, bottom_right_index) =
            self.get_tile_index_range_for_rect(rect_in_layer_pixels);

        for x in range_inclusive(top_left_index.x, bottom_right_index.x) {
            for y in range_inclusive(top_left_index.y, bottom_right_index.y) {
                match self.get_buffer_request_for_tile(Point2D(x, y), current_content_age) {
                    Some(buffer) => buffer_requests.push(buffer),
                    None => {},
                }
            }
        }

        self.mark_tiles_outside_of_rect_as_unused(rect_in_layer_pixels);
        return buffer_requests;
    }

    pub fn get_tile_index_for_point(&self, point: Point2D<uint>) -> Point2D<uint> {
        assert!(point.x % self.tile_size == 0);
        assert!(point.y % self.tile_size == 0);
        Point2D((point.x / self.tile_size) as uint,
                (point.y / self.tile_size) as uint)
    }

    pub fn add_buffer(&mut self, buffer: Box<LayerBuffer>) {
        let index = self.get_tile_index_for_point(buffer.screen_pos.origin.clone());
        if !self.tiles.contains_key(&index) {
            warn!("Received buffer for non-existent tile!");
            self.add_unused_buffer(Some(buffer));
            return;
        }

        let replaced_buffer = self.tiles.get_mut(&index).replace_buffer(buffer);
        self.add_unused_buffer(replaced_buffer);
    }

    pub fn do_for_all_tiles(&self, f: |&Tile|) {
        for tile in self.tiles.values() {
            f(tile);
        }
    }

    pub fn collect_buffers(&mut self) -> Vec<Box<LayerBuffer>> {
        let mut collected_buffers = Vec::new();

        collected_buffers.push_all_move(self.take_unused_buffers());

        // We need to replace the HashMap since it cannot be used again after move_iter().
        let mut tile_map = HashMap::new();
        mem::swap(&mut tile_map, &mut self.tiles);

        for (_, mut tile) in tile_map.move_iter() {
            match tile.buffer.take() {
                Some(buffer) => collected_buffers.push(buffer),
                None => {},
            }
        }

        return collected_buffers;
    }

    pub fn create_textures(&mut self, graphics_context: &NativeCompositingGraphicsContext) {
        for (_, ref mut tile) in self.tiles.mut_iter() {
            tile.create_texture(graphics_context);
        }
    }
}
<commit_msg>Use DevicePixels for TileGrid size<commit_after>// Copyright 2014 The Servo Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use geometry::DevicePixel;
use layers::{BufferRequest, ContentAge, LayerBuffer};
use platform::surface::{NativeCompositingGraphicsContext, NativeSurfaceMethods};
use texturegl::Texture;

use geom::matrix::{Matrix4, identity};
use geom::point::Point2D;
use geom::rect::Rect;
use geom::size::{Size2D, TypedSize2D};
use std::collections::hashmap::HashMap;
use std::iter::range_inclusive;
use std::mem;
use std::num::Zero;

pub struct Tile {
    /// The buffer displayed by this tile.
    buffer: Option<Box<LayerBuffer>>,

    /// The content age of any pending buffer request to avoid re-requesting
    /// a buffer while waiting for it to come back from rendering.
    content_age_of_pending_buffer: Option<ContentAge>,

    /// A handle to the GPU texture.
    pub texture: Texture,

    /// The transformation applied to this tiles texture.
    pub transform: Matrix4<f32>,
}

impl Tile {
    fn new() -> Tile {
        Tile {
            buffer: None,
            texture: Zero::zero(),
            transform: identity(),
            content_age_of_pending_buffer: None,
        }
    }

    fn should_use_new_buffer(&self, new_buffer: &Box<LayerBuffer>) -> bool {
        match self.buffer {
            Some(ref buffer) => new_buffer.content_age >= buffer.content_age,
            None => true,
        }
    }

    fn replace_buffer(&mut self, buffer: Box<LayerBuffer>) -> Option<Box<LayerBuffer>> {
        if !self.should_use_new_buffer(&buffer) {
            warn!("Layer received an old buffer.");
            return Some(buffer);
        }

        let old_buffer = self.buffer.take();
        self.buffer = Some(buffer);
        self.texture = Zero::zero(); // The old texture is bound to the old buffer.
        self.content_age_of_pending_buffer = None;
        return old_buffer;
    }

    fn create_texture(&mut self, graphics_context: &NativeCompositingGraphicsContext) {
        match self.buffer {
            Some(ref buffer) => {
                let size = Size2D(buffer.screen_pos.size.width as int,
                                  buffer.screen_pos.size.height as int);

                // If we already have a texture it should still be valid.
                if !self.texture.is_zero() {
                    return;
                }

                // Make a new texture and bind the LayerBuffer's surface to it.
                self.texture = Texture::new_with_buffer(buffer);
                debug!("Tile: binding to native surface {:d}",
                       buffer.native_surface.get_id() as int);
                buffer.native_surface.bind_to_texture(graphics_context, &self.texture, size);

                // Set the layer's transform.
                let rect = buffer.rect;
                let transform = identity().translate(rect.origin.x, rect.origin.y, 0.0);
                self.transform = transform.scale(rect.size.width, rect.size.height, 1.0);
            },
            None => {},
        }
    }

    fn should_request_buffer(&self, content_age: ContentAge) -> bool {
        // Don't resend a request if our buffer's content age matches the current content age.
        match self.buffer {
            Some(ref buffer) => {
                if buffer.content_age >= content_age {
                    return false;
                }
            }
            None => {}
        }

        // Don't resend a request, if we already have one pending.
        match self.content_age_of_pending_buffer {
            Some(pending_content_age) => pending_content_age != content_age,
            None => true,
        }
    }
}

pub struct TileGrid {
    pub tiles: HashMap<Point2D<uint>, Tile>,

    // The size of tiles in this grid in device pixels.
    tile_size: uint,

    // Buffers that are currently unused.
    unused_buffers: Vec<Box<LayerBuffer>>,
}

pub fn rect_uint_as_rect_f32(rect: Rect<uint>) -> Rect<f32> {
    Rect(Point2D(rect.origin.x as f32, rect.origin.y as f32),
         Size2D(rect.size.width as f32, rect.size.height as f32))
}

impl TileGrid {
    pub fn new(tile_size: uint) -> TileGrid {
        TileGrid {
            tiles: HashMap::new(),
            tile_size: tile_size,
            unused_buffers: Vec::new(),
        }
    }

    pub fn get_tile_index_range_for_rect(&self, rect: Rect<f32>) -> (Point2D<uint>, Point2D<uint>) {
        (Point2D((rect.origin.x / self.tile_size as f32) as uint,
                 (rect.origin.y / self.tile_size as f32) as uint),
         Point2D(((rect.origin.x + rect.size.width) / self.tile_size as f32) as uint,
                 ((rect.origin.y + rect.size.height) / self.tile_size as f32) as uint))
    }

    pub fn get_rect_for_tile_index(&self, tile_index: Point2D<uint>) -> Rect<uint> {
        Rect(Point2D(self.tile_size * tile_index.x, self.tile_size * tile_index.y),
             Size2D(self.tile_size, self.tile_size))
    }

    pub fn take_unused_buffers(&mut self) -> Vec<Box<LayerBuffer>> {
        let mut unused_buffers = Vec::new();
        mem::swap(&mut unused_buffers, &mut self.unused_buffers);
        return unused_buffers;
    }

    pub fn add_unused_buffer(&mut self, buffer: Option<Box<LayerBuffer>>) {
        match buffer {
            Some(buffer) => self.unused_buffers.push(buffer),
            None => {},
        }
    }

    pub fn mark_tiles_outside_of_rect_as_unused(&mut self, rect: Rect<f32>) {
        let mut tile_indexes_to_take = Vec::new();
        for tile_index in self.tiles.keys() {
            if !rect_uint_as_rect_f32(self.get_rect_for_tile_index(*tile_index)).intersects(&rect) {
                tile_indexes_to_take.push(tile_index.clone());
            }
        }

        for tile_index in tile_indexes_to_take.iter() {
            match self.tiles.pop(tile_index) {
                Some(ref mut tile) => self.add_unused_buffer(tile.buffer.take()),
                None => {},
            }
        }
    }

    pub fn get_buffer_request_for_tile(&mut self,
                                       tile_index: Point2D<uint>,
                                       current_content_age: ContentAge)
                                       -> Option<BufferRequest> {
        let tile_rect = self.get_rect_for_tile_index(tile_index);
        let tile_screen_rect = rect_uint_as_rect_f32(tile_rect);

        let tile = self.tiles.find_or_insert_with(tile_index, |_| Tile::new());
        if !tile.should_request_buffer(current_content_age) {
            return None;
        }

        tile.content_age_of_pending_buffer = Some(current_content_age);
        return Some(BufferRequest::new(tile_rect, tile_screen_rect, current_content_age));
    }

    pub fn get_buffer_requests_in_rect(&mut self,
                                       screen_rect: Rect<f32>,
                                       current_content_age: ContentAge)
                                       -> Vec<BufferRequest> {
        let mut buffer_requests = Vec::new();
        let rect_in_layer_pixels = screen_rect;
        let (top_left_index, bottom_right_index) =
            self.get_tile_index_range_for_rect(rect_in_layer_pixels);

        for x in range_inclusive(top_left_index.x, bottom_right_index.x) {
            for y in range_inclusive(top_left_index.y, bottom_right_index.y) {
                match self.get_buffer_request_for_tile(Point2D(x, y), current_content_age) {
                    Some(buffer) => buffer_requests.push(buffer),
                    None => {},
                }
            }
        }

        self.mark_tiles_outside_of_rect_as_unused(rect_in_layer_pixels);
        return buffer_requests;
    }

    pub fn get_tile_index_for_point(&self, point: Point2D<uint>) -> Point2D<uint> {
        assert!(point.x % self.tile_size == 0);
        assert!(point.y % self.tile_size == 0);
        Point2D((point.x / self.tile_size) as uint,
                (point.y / self.tile_size) as uint)
    }

    pub fn add_buffer(&mut self, buffer: Box<LayerBuffer>) {
        let index = self.get_tile_index_for_point(buffer.screen_pos.origin.clone());
        if !self.tiles.contains_key(&index) {
            warn!("Received buffer for non-existent tile!");
            self.add_unused_buffer(Some(buffer));
            return;
        }

        let replaced_buffer = self.tiles.get_mut(&index).replace_buffer(buffer);
        self.add_unused_buffer(replaced_buffer);
    }

    pub fn do_for_all_tiles(&self, f: |&Tile|) {
        for tile in self.tiles.values() {
            f(tile);
        }
    }

    pub fn collect_buffers(&mut self) -> Vec<Box<LayerBuffer>> {
        let mut collected_buffers = Vec::new();

        collected_buffers.push_all_move(self.take_unused_buffers());

        // We need to replace the HashMap since it cannot be used again after move_iter().
        let mut tile_map = HashMap::new();
        mem::swap(&mut tile_map, &mut self.tiles);

        for (_, mut tile) in tile_map.move_iter() {
            match tile.buffer.take() {
                Some(buffer) => collected_buffers.push(buffer),
                None => {},
            }
        }

        return collected_buffers;
    }

    pub fn create_textures(&mut self, graphics_context: &NativeCompositingGraphicsContext) {
        for (_, ref mut tile) in self.tiles.mut_iter() {
            tile.create_texture(graphics_context);
        }
    }
}
<|endoftext|>


<commit_before>// Copyright 2015 The rust-pcre authors.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

extern crate bzip2;
extern crate libc;
extern crate pkg_config;
extern crate tar;

use bzip2::reader::{BzDecompressor};
use std::collections::{BTreeSet};
use std::env;
use std::ffi::{OsString};
use std::fs;
use std::fs::{OpenOptions};
use std::io;
use std::io::{ErrorKind};
use std::iter::{FromIterator};
use std::path::{Path, PathBuf};
use std::process::{Command};
use std::vec::{Vec};
use tar::{Archive};

const BUNDLED_PCRE_VERSION: &'static str = "8.37";

fn main() {
    match pkg_config::Config::new().atleast_version("8.20").find("libpcre") {
        Ok(pkg_config_lib) => {
            for link_pathbuf in pkg_config_lib.link_paths {
                println!("cargo:rustc-link-search=native={}", link_pathbuf.as_path().display());
            }
        },
        Err(_) => {
            let cargo_manifest_dir = env::var("CARGO_MANIFEST_DIR").unwrap();
            let out_dir = env::var("OUT_DIR").unwrap();

            let ext_pathbuf = Path::new(&cargo_manifest_dir).join("ext");

            let pcre_tbz2_pathbuf = ext_pathbuf.join(format!("pcre-{}.tar.bz2", BUNDLED_PCRE_VERSION));
            let pcre_tbz2_f = OpenOptions::new().read(true).open(pcre_tbz2_pathbuf).unwrap();
            let decompressor = BzDecompressor::new(pcre_tbz2_f);

            let mut archive = Archive::new(decompressor);
            // Keep track of which directory paths have already been created.
            let mut created_paths: BTreeSet<OsString> = BTreeSet::new();
            for file in archive.files_mut().unwrap() {
                let mut file = file.unwrap();
                let filename = String::from(file.filename().unwrap());

                let mut path_parts: Vec<&str> = filename.split('/').collect();
                let filename = path_parts.pop().unwrap();
                let parent_pathbuf = Path::new(&out_dir).join(PathBuf::from_iter(path_parts.iter()));
                if !path_parts.is_empty() {
                    if created_paths.insert(parent_pathbuf.as_os_str().to_os_string()) {
                        if let Err(e) = fs::create_dir_all(&parent_pathbuf) {
                            if e.kind() != ErrorKind::AlreadyExists {
                                panic!("failed to create the {} directory and parents: {}", parent_pathbuf.as_path().display(), e);
                            }
                        }
                    }
                }

                let out_pathbuf = parent_pathbuf.join(&filename);
                if filename.is_empty() {
                    if created_paths.insert(out_pathbuf.as_os_str().to_os_string()) {
                        if let Err(e) = fs::create_dir(&out_pathbuf) {
                            if e.kind() != ErrorKind::AlreadyExists {
                                panic!("failed to create the {} directory: {}", out_pathbuf.as_path().display(), e);
                            }
                        }
                    }
                } else {
                    let mut f = OpenOptions::new().write(true).create(true).open(&out_pathbuf).unwrap();
                    if let Err(e) = io::copy(&mut file, &mut f) {
                        panic!("failed to extract {} to {}: {}", filename, out_pathbuf.as_path().display(), e);
                    }
                }
                if cfg!(unix) {
                    // TODO Use `std::fs::Permissions` when `std::os::unix::fs::PermissionsExt` is stable.
                    use std::ffi::{CString};
                    use std::os::unix::ffi::{OsStringExt};
                    let out_pathbuf_cstring = CString::new(out_pathbuf.as_os_str().to_os_string().into_vec()).unwrap();
                    let mode = file.mode().unwrap();
                    unsafe {
                        libc::funcs::posix88::stat_::chmod(out_pathbuf_cstring.as_ptr(), mode as u16);
                    }
                }
            }

            let pcre_pathbuf = Path::new(&out_dir).join(format!("pcre-{}", BUNDLED_PCRE_VERSION));

            let mut cmd = Command::new("cmake");
            cmd.arg(".");
            cmd.arg("-DBUILD_SHARED_LIBS=OFF");
            cmd.arg("-DPCRE_BUILD_PCRECPP=OFF");
            cmd.arg("-DPCRE_BUILD_PCREGREP=OFF");
            cmd.arg("-DPCRE_BUILD_TESTS=OFF");
            cmd.arg("-DPCRE_BUILD_PCRE8=ON");
            cmd.arg("-DPCRE_SUPPORT_JIT=ON");
            cmd.arg("-DPCRE_SUPPORT_UTF=ON");
            cmd.arg("-DPCRE_SUPPORT_UNICODE_PROPERTIES=ON");
            cmd.current_dir(&pcre_pathbuf);
            let status = match cmd.status() {
                Err(ref e) if e.kind() == ErrorKind::NotFound => {
                    panic!("failed to execute `cmake`: {}. Is CMake installed?", e);
                },
                Err(e) => {
                    panic!("failed to execute `cmake`: {}", e);
                },
                Ok(status) => status
            };
            if !status.success() {
                panic!("`cmake . -DBUILD_SHARED_LIBS=OFF ...` did not run successfully.");
            }

            let mut cmd = Command::new("cmake");
            cmd.arg("--build").arg(".").current_dir(&pcre_pathbuf);
            let status = match cmd.status() {
                Err(ref e) if e.kind() == ErrorKind::NotFound => {
                    panic!("failed to execute `cmake`: {}. Is CMake installed?", e);
                },
                Err(e) => {
                    panic!("failed to execute `cmake`: {}", e);
                },
                Ok(status) => status
            };
            if !status.success() {
                panic!("`cmake --build .` did not run successfully.");
            }

            println!("cargo:rustc-link-search=native={}", pcre_pathbuf.as_path().display());
        }
    };
}
<commit_msg>Cast `mode` to `libc::mode_t`<commit_after>// Copyright 2015 The rust-pcre authors.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

extern crate bzip2;
extern crate libc;
extern crate pkg_config;
extern crate tar;

use bzip2::reader::{BzDecompressor};
use std::collections::{BTreeSet};
use std::env;
use std::ffi::{OsString};
use std::fs;
use std::fs::{OpenOptions};
use std::io;
use std::io::{ErrorKind};
use std::iter::{FromIterator};
use std::path::{Path, PathBuf};
use std::process::{Command};
use std::vec::{Vec};
use tar::{Archive};

const BUNDLED_PCRE_VERSION: &'static str = "8.37";

fn main() {
    match pkg_config::Config::new().atleast_version("8.20").find("libpcre") {
        Ok(pkg_config_lib) => {
            for link_pathbuf in pkg_config_lib.link_paths {
                println!("cargo:rustc-link-search=native={}", link_pathbuf.as_path().display());
            }
        },
        Err(_) => {
            let cargo_manifest_dir = env::var("CARGO_MANIFEST_DIR").unwrap();
            let out_dir = env::var("OUT_DIR").unwrap();

            let ext_pathbuf = Path::new(&cargo_manifest_dir).join("ext");

            let pcre_tbz2_pathbuf = ext_pathbuf.join(format!("pcre-{}.tar.bz2", BUNDLED_PCRE_VERSION));
            let pcre_tbz2_f = OpenOptions::new().read(true).open(pcre_tbz2_pathbuf).unwrap();
            let decompressor = BzDecompressor::new(pcre_tbz2_f);

            let mut archive = Archive::new(decompressor);
            // Keep track of which directory paths have already been created.
            let mut created_paths: BTreeSet<OsString> = BTreeSet::new();
            for file in archive.files_mut().unwrap() {
                let mut file = file.unwrap();
                let filename = String::from(file.filename().unwrap());

                let mut path_parts: Vec<&str> = filename.split('/').collect();
                let filename = path_parts.pop().unwrap();
                let parent_pathbuf = Path::new(&out_dir).join(PathBuf::from_iter(path_parts.iter()));
                if !path_parts.is_empty() {
                    if created_paths.insert(parent_pathbuf.as_os_str().to_os_string()) {
                        if let Err(e) = fs::create_dir_all(&parent_pathbuf) {
                            if e.kind() != ErrorKind::AlreadyExists {
                                panic!("failed to create the {} directory and parents: {}", parent_pathbuf.as_path().display(), e);
                            }
                        }
                    }
                }

                let out_pathbuf = parent_pathbuf.join(&filename);
                if filename.is_empty() {
                    if created_paths.insert(out_pathbuf.as_os_str().to_os_string()) {
                        if let Err(e) = fs::create_dir(&out_pathbuf) {
                            if e.kind() != ErrorKind::AlreadyExists {
                                panic!("failed to create the {} directory: {}", out_pathbuf.as_path().display(), e);
                            }
                        }
                    }
                } else {
                    let mut f = OpenOptions::new().write(true).create(true).open(&out_pathbuf).unwrap();
                    if let Err(e) = io::copy(&mut file, &mut f) {
                        panic!("failed to extract {} to {}: {}", filename, out_pathbuf.as_path().display(), e);
                    }
                }
                if cfg!(unix) {
                    // TODO Use `std::fs::Permissions` when `std::os::unix::fs::PermissionsExt` is stable.
                    use std::ffi::{CString};
                    use std::os::unix::ffi::{OsStringExt};
                    let out_pathbuf_cstring = CString::new(out_pathbuf.as_os_str().to_os_string().into_vec()).unwrap();
                    let mode = file.mode().unwrap();
                    unsafe {
                        libc::chmod(out_pathbuf_cstring.as_ptr(), mode as libc::mode_t);
                    }
                }
            }

            let pcre_pathbuf = Path::new(&out_dir).join(format!("pcre-{}", BUNDLED_PCRE_VERSION));

            let mut cmd = Command::new("cmake");
            cmd.arg(".");
            cmd.arg("-DBUILD_SHARED_LIBS=OFF");
            cmd.arg("-DPCRE_BUILD_PCRECPP=OFF");
            cmd.arg("-DPCRE_BUILD_PCREGREP=OFF");
            cmd.arg("-DPCRE_BUILD_TESTS=OFF");
            cmd.arg("-DPCRE_BUILD_PCRE8=ON");
            cmd.arg("-DPCRE_SUPPORT_JIT=ON");
            cmd.arg("-DPCRE_SUPPORT_UTF=ON");
            cmd.arg("-DPCRE_SUPPORT_UNICODE_PROPERTIES=ON");
            cmd.current_dir(&pcre_pathbuf);
            let status = match cmd.status() {
                Err(ref e) if e.kind() == ErrorKind::NotFound => {
                    panic!("failed to execute `cmake`: {}. Is CMake installed?", e);
                },
                Err(e) => {
                    panic!("failed to execute `cmake`: {}", e);
                },
                Ok(status) => status
            };
            if !status.success() {
                panic!("`cmake . -DBUILD_SHARED_LIBS=OFF ...` did not run successfully.");
            }

            let mut cmd = Command::new("cmake");
            cmd.arg("--build").arg(".").current_dir(&pcre_pathbuf);
            let status = match cmd.status() {
                Err(ref e) if e.kind() == ErrorKind::NotFound => {
                    panic!("failed to execute `cmake`: {}. Is CMake installed?", e);
                },
                Err(e) => {
                    panic!("failed to execute `cmake`: {}", e);
                },
                Ok(status) => status
            };
            if !status.success() {
                panic!("`cmake --build .` did not run successfully.");
            }

            println!("cargo:rustc-link-search=native={}", pcre_pathbuf.as_path().display());
        }
    };
}
<|endoftext|>


<commit_before>#![feature(bool_to_option)]
#![feature(crate_visibility_modifier)]
#![feature(decl_macro)]
#![feature(or_patterns)]
#![feature(proc_macro_diagnostic)]
#![feature(proc_macro_internals)]
#![feature(proc_macro_span)]
#![feature(try_blocks)]

#[macro_use]
extern crate rustc_macros;

extern crate proc_macro as pm;

mod placeholders;
mod proc_macro_server;

pub use mbe::macro_rules::compile_declarative_macro;
crate use rustc_span::hygiene;
pub mod base;
pub mod build;
#[macro_use]
pub mod config;
pub mod expand;
pub mod module;
pub mod proc_macro;

crate mod mbe;

// HACK(Centril, #64197): These shouldn't really be here.
// Rather, they should be with their respective modules which are defined in other crates.
// However, since for now constructing a `ParseSess` sorta requires `config` from this crate,
// these tests will need to live here in the iterim.

#[cfg(test)]
mod tests;
#[cfg(test)]
mod parse {
    mod tests;
}
#[cfg(test)]
mod tokenstream {
    mod tests;
}
#[cfg(test)]
mod mut_visit {
    mod tests;
}
<commit_msg>Rollup merge of #82129 - est31:master, r=jyn514<commit_after>#![feature(crate_visibility_modifier)]
#![feature(decl_macro)]
#![feature(or_patterns)]
#![feature(proc_macro_diagnostic)]
#![feature(proc_macro_internals)]
#![feature(proc_macro_span)]
#![feature(try_blocks)]

#[macro_use]
extern crate rustc_macros;

extern crate proc_macro as pm;

mod placeholders;
mod proc_macro_server;

pub use mbe::macro_rules::compile_declarative_macro;
crate use rustc_span::hygiene;
pub mod base;
pub mod build;
#[macro_use]
pub mod config;
pub mod expand;
pub mod module;
pub mod proc_macro;

crate mod mbe;

// HACK(Centril, #64197): These shouldn't really be here.
// Rather, they should be with their respective modules which are defined in other crates.
// However, since for now constructing a `ParseSess` sorta requires `config` from this crate,
// these tests will need to live here in the iterim.

#[cfg(test)]
mod tests;
#[cfg(test)]
mod parse {
    mod tests;
}
#[cfg(test)]
mod tokenstream {
    mod tests;
}
#[cfg(test)]
mod mut_visit {
    mod tests;
}
<|endoftext|>


<commit_before>// Module for rendering scene

extern crate rand;

use camera::Camera;
use model::{bvh, Renderable, Model};
use model::sphere::Sphere;
use ray::Ray;
use shader::material::Material;
use vec3::{Vec3};

use std::io::Write;
use std::thread;
use std::sync::Arc;
use rand::random;

const MIN_DISTANCE: f64 = 0.000001;
const MAX_DISTANCE: f64 = 1000.0;
const DEPTH_MAX: i32 = 50;

#[allow(unused)]
const COLOR_BLUE:    Vec3 = Vec3 { x: 0.5, y: 0.7, z: 1.0 };
#[allow(unused)]
const COLOR_WHITE:   Vec3 = Vec3 { x: 1.0, y: 1.0, z: 1.0 };
#[allow(unused)]
const COLOR_DEFAULT: Vec3 = Vec3 { x: 0.0, y: 0.0, z: 0.0 };

// Renders scene
//
// Return buffer of RGB triples as ints from top left to bottom right
// e.g. R G B R G B R G B ...
//
// Arguments:
//
// * `nx` - width of image
// * `ny` - height of image
// * `spp` - samples per pixel
pub fn render (
    scene: Box<Renderable + Sync>,
    camera: Arc<Camera>,
    nx: i32,
    ny: i32,
    spp: i32,
    nthreads: i32,
    debug: bool,
) -> Vec<i32>  {
    let mut threads = vec![];

    let shareable_scene: Arc<Box<Renderable>> = Arc::new(scene);

    // Each thread takes 1/nthreads of the image split into horizontal slices
    // rev because bottom of image first
    for nth in (0..nthreads).rev() {
        {
            let camera = camera.clone();
            let s = shareable_scene.clone();
            threads.push(thread::spawn(move || {
                // Get horizontal slice, final thread takes any extra due to int truncation
                let start = (ny/nthreads) * nth;
                let end = if nth == nthreads - 1 { ny } else { (ny/nthreads) * (nth+1) };
                let slice = end - start;

                let capacity = slice * nx * 3;
                let mut outbuf: Vec<i32> = Vec::with_capacity(capacity as usize);

                for j in (start..end).rev() {
                    for i in 0..nx {
                        let mut c = Vec3::new(0.0, 0.0, 0.0);

                        for _s in 0..spp {
                            c += sample(i,j,nx,ny,&(**s),&(*camera));
                        }
                        let c = c / (spp as f64);

                        // Output for PPM
                        // Gamma correct to 2: output color ^ (1/gamma) = x^(1/2) = sqrt
                        let c = c.map(&|x: f64| x.sqrt());
                        let c = c * 255.99;
                        let c = c.map(&|x: f64| if x > 256.99 { 255.99 } else { x });

                        // Save to buffer for image out
                        outbuf.push(c.x as i32);
                        outbuf.push(c.y as i32);
                        outbuf.push(c.z as i32);
                    }

                    // Write percentage progress
                    if debug && j % (slice / 10) == 0 {
                        writeln!(&mut ::std::io::stderr(), "{}: {}/{}", nth, slice-(j-start), slice).unwrap();
                    }
                }

                (outbuf, nth)
            }));
        }
    }

    // Join and create final buffer from results
    let mut outbuf: Vec<i32> = Vec::with_capacity((nx * ny * 3) as usize);

    for t in threads {
        let (mut res, nth) = t.join().unwrap(); // If thread fails, unrecoverable
        if debug {
            writeln!(&mut ::std::io::stderr(), "Thread {} done", nth);
        }
        outbuf.append(&mut res);
    }

    outbuf
}

fn sample(x: i32, y: i32, nx: i32, ny: i32, scene: &Renderable, camera: &Camera) -> Vec3 {
    // Get percent offset from bottom left corner
    let u = (x as f64 + random::<f64>()) / (nx as f64);
    let v = (y as f64 + random::<f64>()) / (ny as f64);

    // Make ray
    let r = camera.get_ray(u, v);

    // Get color
    color(&r, scene, 0)
}

fn color(r: &Ray, world: &Renderable, depth: i32) -> Vec3 {
    match world.hit(r, MIN_DISTANCE, MAX_DISTANCE) {
        Some((h, material)) => {
            let emitted = material.emitted(h.u, h.v, &h.p).unwrap_or(Vec3::new(0.0,0.0,0.0));
            if depth < DEPTH_MAX {
                match material.scatter(r, &h) {
                    Some((attentuation, scattered)) => {
                        emitted + attentuation * color(&scattered, world, depth+1)
                    }
                    // No scatter ray produced
                    None => emitted
                }
            } else {
                // Depth exceeded default color
                COLOR_DEFAULT
            }
        }
        None => {
            // Background

            // Sky
            // let unit_dir = r.dir.normalized();
            // let t = 0.5 * (unit_dir.y + 1.0);
            // COLOR_WHITE * (1.0-t) + COLOR_BLUE * (t)

            // Black
            COLOR_DEFAULT
        }
    }
}

pub fn random_scene() -> Box<Renderable + Sync> {
    let mut items: Vec<Box<bvh::BVHItem>> = Vec::new();

    // Ground
    items.push(Box::new(Model::new(
        Sphere {
            center: Vec3::new(0.0,-1000.0,0.0),
            radius: 1000.0
        },
        Material::lambertian_constant(random::<Vec3>()),
    )));

    // Big spheres
    items.push(Box::new(Model::new(
        Sphere {
            center: Vec3::new(-4.0,1.0,0.0),
            radius: 1.0,
        },
        Material::lambertian_constant(random::<Vec3>() * random::<Vec3>()),
    )));
    items.push(Box::new(Model::new(
        Sphere {
            center: Vec3::new(4.0, 1.0, 0.0),
            radius: 1.0,
        },
        Material::metal((random::<Vec3>() + 1.0) * 0.5, random::<f64>() * 0.3),
    )));
    items.push(Box::new(Model::new(
        Sphere {
            center: Vec3::new(0.0,1.0,0.0),
            radius: 1.0,
        },
        Material::dielectric(1.5),
    )));

    for a in -11..11 {
        for b in -11..11 {
            let choose_mat = random::<f64>();
            let center = Vec3::new(
                a as f64 + 0.9 * random::<f64>(),
                0.2,
                b as f64 + 0.9 * random::<f64>(),
            );
            if (center - Vec3::new(4.0,0.2,0.0)).length() > 0.9 {
                if choose_mat < 0.8 {
                    // diffuse
                    items.push(Box::new(Model::new(
                        Sphere {
                            center: center,
                            radius: 0.2,
                        },
                        Material::lambertian_constant(random::<Vec3>() * random::<Vec3>()),
                    )));
                } else if choose_mat < 0.95 {
                    // metal
                    items.push(Box::new(Model::new(
                        Sphere {
                            center: center,
                            radius: 0.2,
                        },
                        Material::metal(
                            (random::<Vec3>() + 1.0) * 0.5,
                            0.5 * random::<f64>(),
                        ),
                    )));

                } else {
                    // glass
                    items.push(Box::new(Model::new(
                        Sphere {
                            center: center,
                            radius: 0.2,
                        },
                        Material::dielectric(1.5),
                    )));

                }
            }
        }
    }

    Box::new(bvh::Node::new(items))
}
<commit_msg>Fix mod with 0 bug for tiny images<commit_after>// Module for rendering scene

extern crate rand;

use camera::Camera;
use model::{bvh, Renderable, Model};
use model::sphere::Sphere;
use ray::Ray;
use shader::material::Material;
use vec3::{Vec3};

use std::io::Write;
use std::thread;
use std::sync::Arc;
use rand::random;

const MIN_DISTANCE: f64 = 0.000001;
const MAX_DISTANCE: f64 = 1000.0;
const DEPTH_MAX: i32 = 50;

#[allow(unused)]
const COLOR_BLUE:    Vec3 = Vec3 { x: 0.5, y: 0.7, z: 1.0 };
#[allow(unused)]
const COLOR_WHITE:   Vec3 = Vec3 { x: 1.0, y: 1.0, z: 1.0 };
#[allow(unused)]
const COLOR_DEFAULT: Vec3 = Vec3 { x: 0.0, y: 0.0, z: 0.0 };

// Renders scene
//
// Return buffer of RGB triples as ints from top left to bottom right
// e.g. R G B R G B R G B ...
//
// Arguments:
//
// * `nx` - width of image
// * `ny` - height of image
// * `spp` - samples per pixel
pub fn render (
    scene: Box<Renderable + Sync>,
    camera: Arc<Camera>,
    nx: i32,
    ny: i32,
    spp: i32,
    nthreads: i32,
    debug: bool,
) -> Vec<i32>  {
    let mut threads = vec![];

    let shareable_scene: Arc<Box<Renderable>> = Arc::new(scene);

    // Each thread takes 1/nthreads of the image split into horizontal slices
    // rev because bottom of image first
    for nth in (0..nthreads).rev() {
        {
            let camera = camera.clone();
            let s = shareable_scene.clone();
            threads.push(thread::spawn(move || {
                // Get horizontal slice, final thread takes any extra due to int truncation
                let start = (ny/nthreads) * nth;
                let end = if nth == nthreads - 1 { ny } else { (ny/nthreads) * (nth+1) };
                let slice = end - start;

                let capacity = slice * nx * 3;
                let mut outbuf: Vec<i32> = Vec::with_capacity(capacity as usize);

                for j in (start..end).rev() {
                    for i in 0..nx {
                        let mut c = Vec3::new(0.0, 0.0, 0.0);

                        for _s in 0..spp {
                            c += sample(i,j,nx,ny,&(**s),&(*camera));
                        }
                        let c = c / (spp as f64);

                        // Output for PPM
                        // Gamma correct to 2: output color ^ (1/gamma) = x^(1/2) = sqrt
                        let c = c.map(&|x: f64| x.sqrt());
                        let c = c * 255.99;
                        let c = c.map(&|x: f64| if x > 256.99 { 255.99 } else { x });

                        // Save to buffer for image out
                        outbuf.push(c.x as i32);
                        outbuf.push(c.y as i32);
                        outbuf.push(c.z as i32);
                    }

                    // Write percentage progress
                    if debug && j % ::std::cmp::max(slice / 10, 1) == 0 {
                        writeln!(&mut ::std::io::stderr(), "{}: {}/{}", nth, slice-(j-start), slice).unwrap();
                    }
                }

                (outbuf, nth)
            }));
        }
    }

    // Join and create final buffer from results
    let mut outbuf: Vec<i32> = Vec::with_capacity((nx * ny * 3) as usize);

    for t in threads {
        let (mut res, nth) = t.join().unwrap(); // If thread fails, unrecoverable
        if debug {
            writeln!(&mut ::std::io::stderr(), "Thread {} done", nth);
        }
        outbuf.append(&mut res);
    }

    outbuf
}

fn sample(x: i32, y: i32, nx: i32, ny: i32, scene: &Renderable, camera: &Camera) -> Vec3 {
    // Get percent offset from bottom left corner
    let u = (x as f64 + random::<f64>()) / (nx as f64);
    let v = (y as f64 + random::<f64>()) / (ny as f64);

    // Make ray
    let r = camera.get_ray(u, v);

    // Get color
    color(&r, scene, 0)
}

fn color(r: &Ray, world: &Renderable, depth: i32) -> Vec3 {
    match world.hit(r, MIN_DISTANCE, MAX_DISTANCE) {
        Some((h, material)) => {
            let emitted = material.emitted(h.u, h.v, &h.p).unwrap_or(Vec3::new(0.0,0.0,0.0));
            if depth < DEPTH_MAX {
                match material.scatter(r, &h) {
                    Some((attentuation, scattered)) => {
                        emitted + attentuation * color(&scattered, world, depth+1)
                    }
                    // No scatter ray produced
                    None => emitted
                }
            } else {
                // Depth exceeded default color
                COLOR_DEFAULT
            }
        }
        None => {
            // Background

            // Sky
            // let unit_dir = r.dir.normalized();
            // let t = 0.5 * (unit_dir.y + 1.0);
            // COLOR_WHITE * (1.0-t) + COLOR_BLUE * (t)

            // Black
            COLOR_DEFAULT
        }
    }
}

pub fn random_scene() -> Box<Renderable + Sync> {
    let mut items: Vec<Box<bvh::BVHItem>> = Vec::new();

    // Ground
    items.push(Box::new(Model::new(
        Sphere {
            center: Vec3::new(0.0,-1000.0,0.0),
            radius: 1000.0
        },
        Material::lambertian_constant(random::<Vec3>()),
    )));

    // Big spheres
    items.push(Box::new(Model::new(
        Sphere {
            center: Vec3::new(-4.0,1.0,0.0),
            radius: 1.0,
        },
        Material::lambertian_constant(random::<Vec3>() * random::<Vec3>()),
    )));
    items.push(Box::new(Model::new(
        Sphere {
            center: Vec3::new(4.0, 1.0, 0.0),
            radius: 1.0,
        },
        Material::metal((random::<Vec3>() + 1.0) * 0.5, random::<f64>() * 0.3),
    )));
    items.push(Box::new(Model::new(
        Sphere {
            center: Vec3::new(0.0,1.0,0.0),
            radius: 1.0,
        },
        Material::dielectric(1.5),
    )));

    for a in -11..11 {
        for b in -11..11 {
            let choose_mat = random::<f64>();
            let center = Vec3::new(
                a as f64 + 0.9 * random::<f64>(),
                0.2,
                b as f64 + 0.9 * random::<f64>(),
            );
            if (center - Vec3::new(4.0,0.2,0.0)).length() > 0.9 {
                if choose_mat < 0.8 {
                    // diffuse
                    items.push(Box::new(Model::new(
                        Sphere {
                            center: center,
                            radius: 0.2,
                        },
                        Material::lambertian_constant(random::<Vec3>() * random::<Vec3>()),
                    )));
                } else if choose_mat < 0.95 {
                    // metal
                    items.push(Box::new(Model::new(
                        Sphere {
                            center: center,
                            radius: 0.2,
                        },
                        Material::metal(
                            (random::<Vec3>() + 1.0) * 0.5,
                            0.5 * random::<f64>(),
                        ),
                    )));

                } else {
                    // glass
                    items.push(Box::new(Model::new(
                        Sphere {
                            center: center,
                            radius: 0.2,
                        },
                        Material::dielectric(1.5),
                    )));

                }
            }
        }
    }

    Box::new(bvh::Node::new(items))
}
<|endoftext|>


<commit_before>// Copyright 2015 Nicholas Bishop
//
// 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 std::ops::{Add, Div, Mul, Sub};

/// Vector with three f32 components
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct Vec3f {
    pub x: f32,
    pub y: f32,
    pub z: f32
}

impl Vec3f {
    pub fn new(x: f32, y: f32, z: f32) -> Vec3f {
        Vec3f { x: x,
                y: y,
                z: z }
    }

    pub fn from_scalar<T: CastF32>(s: T) -> Vec3f {
        let f = s.as_f32();
        Vec3f {
            x: f,
            y: f,
            z: f
        }
    }

    pub fn magnitude_squared(&self) -> f32 {
        dot3(*self, *self)
    }

    pub fn magnitude(&self) -> f32 {
        self.magnitude_squared().sqrt()
    }
}

/// Vec3f(0.0, 0.0, 0.0)
pub const ZERO_3F: Vec3f = Vec3f { x: 0.0, y: 0.0, z: 0.0 };

pub trait CastF32 { fn as_f32(&self) -> f32; }

impl CastF32 for f32 { fn as_f32(&self) -> f32 { *self } }
impl CastF32 for f64 { fn as_f32(&self) -> f32 { *self as f32 } }
impl CastF32 for i8  { fn as_f32(&self) -> f32 { *self as f32 } }
impl CastF32 for i16 { fn as_f32(&self) -> f32 { *self as f32 } }
impl CastF32 for i32 { fn as_f32(&self) -> f32 { *self as f32 } }
impl CastF32 for u8  { fn as_f32(&self) -> f32 { *self as f32 } }
impl CastF32 for u16 { fn as_f32(&self) -> f32 { *self as f32 } }
impl CastF32 for u32 { fn as_f32(&self) -> f32 { *self as f32 } }

/// Create a Vec3f from x, y, and z inputs
///
/// This is a convenience function that provides a little more
/// flexibility than Vec3f::new in that it will happily take numbers
/// that aren't f32 (including a mix of different types for each
/// component). Vec3f is such a common type that it seems reasonable
/// to provide a little extra ease of use.
pub fn vec3f<X: CastF32, Y: CastF32, Z: CastF32>(x: X, y: Y, z: Z) -> Vec3f {
    Vec3f { x: x.as_f32(), y: y.as_f32(), z: z.as_f32() }
}

/// Inner product of two Vec3f inputs
pub fn dot3(a: Vec3f, b: Vec3f) -> f32 {
    let v = a * b;
    v.x + v.y + v.z
}

/// Cross product of two Vec3f inputs
pub fn cross(a: Vec3f, b: Vec3f) -> Vec3f {
    Vec3f::new(a.y * b.z - a.z * b.y,
               a.z * b.x - a.x * b.z,
               a.x * b.y - a.y * b.x)
}

impl Add for Vec3f {
    type Output = Vec3f;
    fn add(self, v: Vec3f) -> Vec3f {
        Vec3f::new(self.x + v.x, self.y + v.y, self.z + v.z)
    }
}

impl Div for Vec3f {
    type Output = Vec3f;
    fn div(self, v: Vec3f) -> Vec3f {
        Vec3f::new(self.x / v.x, self.y / v.y, self.z / v.z)
    }
}

impl Mul<Vec3f> for Vec3f {
    type Output = Vec3f;
    fn mul(self, v: Vec3f) -> Vec3f {
        Vec3f::new(self.x * v.x, self.y * v.y, self.z * v.z)
    }
}

impl Mul<f32> for Vec3f {
    type Output = Vec3f;
    fn mul(self, f: f32) -> Vec3f {
        Vec3f::new(self.x * f, self.y * f, self.z * f)
    }
}

impl Sub for Vec3f {
    type Output = Vec3f;
    fn sub(self, v: Vec3f) -> Vec3f {
        Vec3f::new(self.x - v.x, self.y - v.y, self.z - v.z)
    }
}

#[test]
fn test_vec3f_create() {
    vec3f(1.0f32, 2, 3i32);
    assert!(Vec3f::from_scalar(1) == vec3f(1, 1, 1));
}

#[test]
fn test_vec3f_magnitude() {
    let v = vec3f(-4, 0, 0);
    assert!(v.magnitude_squared() == 16.0);
    assert!(v.magnitude() == 4.0);
}

#[test]
fn test_vec3f_arithmetic() {
    let a = vec3f(1, 2, 3);
    let b = vec3f(4, 5, 6);
    assert!(a + b == vec3f(5, 7, 9));
    assert!(a - b == vec3f(-3, -3, -3));
    assert!(a * b == vec3f(4, 10, 18));
    assert!(a / b == vec3f(0.25, 2.0 / 5.0, 0.5));
}

#[test]
fn test_vec3f_dot() {
    assert!(dot3(vec3f(1, 2, 3), vec3f(4, 5, 6)) == 32.0);
}

#[test]
fn test_vec3f_cross() {
    assert!(cross(vec3f(1, 0, 0), vec3f(0, 1, 0)) == vec3f(0, 0, 1));
}
<commit_msg>Add vector::distance3<commit_after>// Copyright 2015 Nicholas Bishop
//
// 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 std::ops::{Add, Div, Mul, Sub};

/// Vector with three f32 components
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct Vec3f {
    pub x: f32,
    pub y: f32,
    pub z: f32
}

impl Vec3f {
    pub fn new(x: f32, y: f32, z: f32) -> Vec3f {
        Vec3f { x: x,
                y: y,
                z: z }
    }

    pub fn from_scalar<T: CastF32>(s: T) -> Vec3f {
        let f = s.as_f32();
        Vec3f {
            x: f,
            y: f,
            z: f
        }
    }

    pub fn magnitude_squared(&self) -> f32 {
        dot3(*self, *self)
    }

    pub fn magnitude(&self) -> f32 {
        self.magnitude_squared().sqrt()
    }
}

/// Vec3f(0.0, 0.0, 0.0)
pub const ZERO_3F: Vec3f = Vec3f { x: 0.0, y: 0.0, z: 0.0 };

pub trait CastF32 { fn as_f32(&self) -> f32; }

impl CastF32 for f32 { fn as_f32(&self) -> f32 { *self } }
impl CastF32 for f64 { fn as_f32(&self) -> f32 { *self as f32 } }
impl CastF32 for i8  { fn as_f32(&self) -> f32 { *self as f32 } }
impl CastF32 for i16 { fn as_f32(&self) -> f32 { *self as f32 } }
impl CastF32 for i32 { fn as_f32(&self) -> f32 { *self as f32 } }
impl CastF32 for u8  { fn as_f32(&self) -> f32 { *self as f32 } }
impl CastF32 for u16 { fn as_f32(&self) -> f32 { *self as f32 } }
impl CastF32 for u32 { fn as_f32(&self) -> f32 { *self as f32 } }

/// Create a Vec3f from x, y, and z inputs
///
/// This is a convenience function that provides a little more
/// flexibility than Vec3f::new in that it will happily take numbers
/// that aren't f32 (including a mix of different types for each
/// component). Vec3f is such a common type that it seems reasonable
/// to provide a little extra ease of use.
pub fn vec3f<X: CastF32, Y: CastF32, Z: CastF32>(x: X, y: Y, z: Z) -> Vec3f {
    Vec3f { x: x.as_f32(), y: y.as_f32(), z: z.as_f32() }
}

/// Inner product of two Vec3f inputs
pub fn dot3(a: Vec3f, b: Vec3f) -> f32 {
    let v = a * b;
    v.x + v.y + v.z
}

/// Cross product of two Vec3f inputs
pub fn cross(a: Vec3f, b: Vec3f) -> Vec3f {
    Vec3f::new(a.y * b.z - a.z * b.y,
               a.z * b.x - a.x * b.z,
               a.x * b.y - a.y * b.x)
}

/// Distance between two vectors
pub fn distance3(a: Vec3f, b: Vec3f) -> f32 {
    (a - b).magnitude()
}

impl Add for Vec3f {
    type Output = Vec3f;
    fn add(self, v: Vec3f) -> Vec3f {
        Vec3f::new(self.x + v.x, self.y + v.y, self.z + v.z)
    }
}

impl Div for Vec3f {
    type Output = Vec3f;
    fn div(self, v: Vec3f) -> Vec3f {
        Vec3f::new(self.x / v.x, self.y / v.y, self.z / v.z)
    }
}

impl Mul<Vec3f> for Vec3f {
    type Output = Vec3f;
    fn mul(self, v: Vec3f) -> Vec3f {
        Vec3f::new(self.x * v.x, self.y * v.y, self.z * v.z)
    }
}

impl Mul<f32> for Vec3f {
    type Output = Vec3f;
    fn mul(self, f: f32) -> Vec3f {
        Vec3f::new(self.x * f, self.y * f, self.z * f)
    }
}

impl Sub for Vec3f {
    type Output = Vec3f;
    fn sub(self, v: Vec3f) -> Vec3f {
        Vec3f::new(self.x - v.x, self.y - v.y, self.z - v.z)
    }
}

#[test]
fn test_vec3f_create() {
    vec3f(1.0f32, 2, 3i32);
    assert!(Vec3f::from_scalar(1) == vec3f(1, 1, 1));
}

#[test]
fn test_vec3f_magnitude() {
    let v = vec3f(-4, 0, 0);
    assert!(v.magnitude_squared() == 16.0);
    assert!(v.magnitude() == 4.0);
}

#[test]
fn test_vec3f_distance3() {
    assert!(distance3(vec3f(0, -4, 0), vec3f(0, 4, 0)) == 8.0);
}

#[test]
fn test_vec3f_arithmetic() {
    let a = vec3f(1, 2, 3);
    let b = vec3f(4, 5, 6);
    assert!(a + b == vec3f(5, 7, 9));
    assert!(a - b == vec3f(-3, -3, -3));
    assert!(a * b == vec3f(4, 10, 18));
    assert!(a / b == vec3f(0.25, 2.0 / 5.0, 0.5));
}

#[test]
fn test_vec3f_dot() {
    assert!(dot3(vec3f(1, 2, 3), vec3f(4, 5, 6)) == 32.0);
}

#[test]
fn test_vec3f_cross() {
    assert!(cross(vec3f(1, 0, 0), vec3f(0, 1, 0)) == vec3f(0, 0, 1));
}
<|endoftext|>


<commit_before>#![feature(phase)]
#[phase(syntax, link)] extern crate log;
extern crate collections;
extern crate sync;
extern crate rand;
extern crate serialize;
use std::io::MemWriter;
use serialize::ebml::writer;
use serialize::ebml::reader;
use serialize::{Encodable, Decodable};
mod buffer;

#[deriving(Encodable, Decodable)]
enum SqlType {
	Char(uint),
	Varchar(uint),
	Integer,
}

#[deriving(Encodable, Decodable)]
enum SqlAttribute {
	Null,
	NotNull,
}

#[deriving(Encodable, Decodable)]
struct Column {
	name: ~str,
	datatype: SqlType,
	attributes: Vec<SqlAttribute>,
}

#[deriving(Encodable, Decodable)]
struct Relation {
	name: ~str,
	columns: Vec<Column>,
}

impl Relation {
	pub fn new(name: ~str) -> Relation {
		Relation {name: name, columns: Vec::new()}
	}

	pub fn add_column(&mut self, column: Column) {
		self.columns.push(column);
	}
}

#[deriving(Encodable, Decodable)]
struct Schema {
	relations: Vec<Relation>,
}

impl Schema {
	pub fn new() -> Schema {
		Schema {relations: Vec::new()}
	}

	pub fn new_from_disk(bufmanager: buffer::BufferManager) -> Schema {
		// TODO
		Schema {relations: Vec::new()}
	}

	pub fn add_relation(&mut self, relation: Relation) {
		self.relations.push(relation);
	}

	pub fn save_to_disk(&self) {
		let mut wr = MemWriter::new();
		let v: u64 = 42;
		{
			let mut ebml_w = writer::Encoder(&mut wr);
			let _ = self.encode(&mut ebml_w);
		}
		let ebml_doc = reader::Doc(wr.get_ref());
		let mut deser = reader::Decoder(ebml_doc);
		let v1: Schema = Decodable::decode(&mut deser).unwrap();
		println!("v1 == {:?}", v1);

		for rel in self.relations.iter() {
			//rel.save_to_disk()
		}
	}
}

struct Record {
	// TODO: do we even need this?
	len: uint,
	data: Vec<u8>,
}

impl Record {
	/* move semantics, no copy */
	pub fn new(len: uint, data: Vec<u8>) -> Record {
		Record {len: len, data: data}
	}

	pub fn get_data<'a>(&'a self) -> &'a [u8] {
		self.data.as_slice()
	}
}

struct SPSegment;

/* our newtype struct: create a TID type as an alias to u64 */
struct TID(u64);

impl SPSegment {
	pub fn insert(r: Record) -> TID {
		TID(0_u64)
	}

	pub fn remove(tid: TID) -> bool {
		false
	}

	pub fn lookup(tid: TID) -> Record {
		// TODO
		Record {len: 1, data: vec!(1)}
	}

	pub fn update(tid: TID, r: Record) -> bool {
		false
	}
}

#[test]
fn main() {
}

#[test]
fn create_schema() {
	let name = Column {name: ~"name", datatype: Varchar(128), attributes: vec!(NotNull)};
	let age = Column {name: ~"age", datatype: Integer, attributes: vec!(NotNull)};
	let mut relation = Relation::new(~"Person");
	relation.add_column(name);
	relation.add_column(age);
	let mut schema = Schema::new();
	schema.add_relation(relation);
	schema.save_to_disk();
	assert!(false);
}
<commit_msg>Added barebones implementation of SchemaWriter traits<commit_after>#![feature(phase)]
#[phase(syntax, link)] extern crate log;
extern crate collections;
extern crate sync;
extern crate rand;
extern crate serialize;
use std::io::{IoResult, IoError, IoUnavailable, SeekStyle, MemWriter};
use serialize::ebml::{reader,writer};
use serialize::{Encodable, Decodable};
mod buffer;

#[deriving(Encodable, Decodable)]
enum SqlType {
	Char(uint),
	Varchar(uint),
	Integer,
}

#[deriving(Encodable, Decodable)]
enum SqlAttribute {
	Null,
	NotNull,
}

#[deriving(Encodable, Decodable)]
struct Column {
	name: ~str,
	datatype: SqlType,
	attributes: Vec<SqlAttribute>,
}

#[deriving(Encodable, Decodable)]
struct Relation {
	name: ~str,
	columns: Vec<Column>,
}

impl Relation {
	pub fn new(name: ~str) -> Relation {
		Relation {name: name, columns: Vec::new()}
	}

	pub fn add_column(&mut self, column: Column) {
		self.columns.push(column);
	}
}

#[deriving(Encodable, Decodable)]
struct Schema {
	relations: Vec<Relation>,
}

struct SchemaWriter{
	buffer_manager: buffer::BufferManager,
}

impl Writer for SchemaWriter {
	fn write(&mut self, buf: &[u8]) -> IoResult<()> {
		Err(IoError {kind: IoUnavailable, desc: "Unavailable", detail: None})
	}
}

impl Seek for SchemaWriter {
	fn tell(&self) -> IoResult<u64> {
		Err(IoError {kind: IoUnavailable, desc: "Unavailable", detail: None})
	}

	fn seek(&mut self, pos: i64, style: SeekStyle) -> IoResult<()> {
		Err(IoError {kind: IoUnavailable, desc: "Unavailable", detail: None})
	}
}

impl Schema {
	pub fn new() -> Schema {
		Schema {relations: Vec::new()}
	}

	pub fn new_from_disk(bufmanager: buffer::BufferManager) -> Schema {
		// TODO
		Schema {relations: Vec::new()}
	}

	pub fn add_relation(&mut self, relation: Relation) {
		self.relations.push(relation);
	}

	pub fn save_to_disk(&self) {
		let mut wr = MemWriter::new();
		let v: u64 = 42;
		{
			let mut ebml_w = writer::Encoder(&mut wr);
			let _ = self.encode(&mut ebml_w);
		}
		let ebml_doc = reader::Doc(wr.get_ref());
		let mut deser = reader::Decoder(ebml_doc);
		let v1: Schema = Decodable::decode(&mut deser).unwrap();
		println!("v1 == {:?}", v1);

		for rel in self.relations.iter() {
			//rel.save_to_disk()
		}
	}
}

struct Record {
	// TODO: do we even need this?
	len: uint,
	data: Vec<u8>,
}

impl Record {
	/* move semantics, no copy */
	pub fn new(len: uint, data: Vec<u8>) -> Record {
		Record {len: len, data: data}
	}

	pub fn get_data<'a>(&'a self) -> &'a [u8] {
		self.data.as_slice()
	}
}

struct SPSegment;

/* our newtype struct: create a TID type as an alias to u64 */
struct TID(u64);

impl SPSegment {
	pub fn insert(r: Record) -> TID {
		TID(0_u64)
	}

	pub fn remove(tid: TID) -> bool {
		false
	}

	pub fn lookup(tid: TID) -> Record {
		// TODO
		Record {len: 1, data: vec!(1)}
	}

	pub fn update(tid: TID, r: Record) -> bool {
		false
	}
}

#[test]
fn main() {
}

#[test]
fn create_schema() {
	let name = Column {name: ~"name", datatype: Varchar(128), attributes: vec!(NotNull)};
	let age = Column {name: ~"age", datatype: Integer, attributes: vec!(NotNull)};
	let mut relation = Relation::new(~"Person");
	relation.add_column(name);
	relation.add_column(age);
	let mut schema = Schema::new();
	schema.add_relation(relation);
	schema.save_to_disk();
	assert!(false);
}
<|endoftext|>