<commit_before>// Copyright 2016 Joe Wilm, The Alacritty Project Contributors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
//! Alacritty - The GPU Enhanced Terminal
#![feature(plugin)]
#![cfg_attr(feature = "clippy", plugin(clippy))]

#[macro_use]
extern crate alacritty;

use std::error::Error;
use std::sync::Arc;

use alacritty::cli;
use alacritty::config::{self, Config};
use alacritty::display::Display;
use alacritty::event;
use alacritty::event_loop::EventLoop;
use alacritty::input;
use alacritty::sync::FairMutex;
use alacritty::term::{Term};
use alacritty::tty::{self, process_should_exit};

fn main() {
    // Load configuration
    let config = match Config::load() {
        // Error loading config
        Err(err) => match err {
            // Use default config when not found
            config::Error::NotFound => {
                err_println!("Config file not found; using defaults");
                Config::default()
            },

            // If there's a problem with the config file, print an error
            // and exit.
            _ => die!("{}", err),
        },

        // Successfully loaded config from file
        Ok(config) => config
    };

    // Load command line options
    let options = cli::Options::load();

    // Run alacritty
    if let Err(err) = run(config, options) {
        die!("{}", err);
    }

    println!("Goodbye");
}

/// Run Alacritty
///
/// Creates a window, the terminal state, pty, I/O event loop, input processor,
/// config change monitor, and runs the main display loop.
fn run(config: Config, options: cli::Options) -> Result<(), Box<Error>> {
    // Create a display.
    //
    // The display manages a window and can draw the terminal
    let mut display = Display::new(&config, &options)?;

    // Create the terminal
    //
    // This object contains all of the state about what's being displayed. It's
    // wrapped in a clonable mutex since both the I/O loop and display need to
    // access it.
    let terminal = Arc::new(FairMutex::new(Term::new(display.size().to_owned())));

    // Create the pty
    //
    // The pty forks a process to run the shell on the slave side of the
    // pseudoterminal. A file descriptor for the master side is retained for
    // reading/writing to the shell.
    let mut pty = tty::new(display.size());

    // Create the pseudoterminal I/O loop
    //
    // pty I/O is ran on another thread as to not occupy cycles used by the
    // renderer and input processing. Note that access to the terminal state is
    // synchronized since the I/O loop updates the state, and the display
    // consumes it periodically.
    let event_loop = EventLoop::new(
        terminal.clone(),
        display.notifier(),
        pty.reader(),
        options.ref_test,
    );

    // The event loop channel allows write requests from the event processor
    // to be sent to the loop and ultimately written to the pty.
    let loop_tx = event_loop.channel();

    // Event processor
    //
    // Need the Rc<RefCell<_>> here since a ref is shared in the resize callback
    let mut processor = event::Processor::new(
        input::LoopNotifier(loop_tx),
        terminal.clone(),
        display.resize_channel(),
        &config,
        options.ref_test,
    );

    // Create a config monitor when config was loaded from path
    //
    // The monitor watches the config file for changes and reloads it. Pending
    // config changes are processed in the main loop.
    let config_monitor = config.path()
        .map(|path| config::Monitor::new(path, display.notifier()));

    // Kick off the I/O thread
    let io_thread = event_loop.spawn(None);

    // Main display loop
    loop {
        // Process input and window events
        let wakeup_request = processor.process_events(display.window());

        // Handle config reloads
        let config_updated = config_monitor.as_ref()
            .and_then(|monitor| monitor.pending_config())
            .map(|config| {
                display.update_config(&config);
                processor.update_config(&config);
                true
            }).unwrap_or(false);

        // Maybe draw the terminal
        let mut terminal = terminal.lock();
        if wakeup_request || config_updated {
            // Handle pending resize events
            //
            // The second argument is a list of types that want to be notified
            // of display size changes.
            display.handle_resize(&mut terminal, &mut [&mut pty, &mut processor]);

            // Draw the current state of the terminal
            display.draw(terminal, &config);
        }

        // Begin shutdown if the flag was raised.
        if process_should_exit() {
            break;
        }
    }

    // FIXME patch notify library to have a shutdown method
    // config_reloader.join().ok();

    // Wait for the I/O thread thread to finish
    let _ = io_thread.join();

    Ok(())
}
<commit_msg>Fix config reloading<commit_after>// Copyright 2016 Joe Wilm, The Alacritty Project Contributors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
//! Alacritty - The GPU Enhanced Terminal
#![feature(plugin)]
#![cfg_attr(feature = "clippy", plugin(clippy))]

#[macro_use]
extern crate alacritty;

use std::error::Error;
use std::sync::Arc;

use alacritty::cli;
use alacritty::config::{self, Config};
use alacritty::display::Display;
use alacritty::event;
use alacritty::event_loop::EventLoop;
use alacritty::input;
use alacritty::sync::FairMutex;
use alacritty::term::{Term};
use alacritty::tty::{self, process_should_exit};

fn main() {
    // Load configuration
    let config = match Config::load() {
        // Error loading config
        Err(err) => match err {
            // Use default config when not found
            config::Error::NotFound => {
                err_println!("Config file not found; using defaults");
                Config::default()
            },

            // If there's a problem with the config file, print an error
            // and exit.
            _ => die!("{}", err),
        },

        // Successfully loaded config from file
        Ok(config) => config
    };

    // Load command line options
    let options = cli::Options::load();

    // Run alacritty
    if let Err(err) = run(config, options) {
        die!("{}", err);
    }

    println!("Goodbye");
}

/// Run Alacritty
///
/// Creates a window, the terminal state, pty, I/O event loop, input processor,
/// config change monitor, and runs the main display loop.
fn run(mut config: Config, options: cli::Options) -> Result<(), Box<Error>> {
    // Create a display.
    //
    // The display manages a window and can draw the terminal
    let mut display = Display::new(&config, &options)?;

    // Create the terminal
    //
    // This object contains all of the state about what's being displayed. It's
    // wrapped in a clonable mutex since both the I/O loop and display need to
    // access it.
    let terminal = Arc::new(FairMutex::new(Term::new(display.size().to_owned())));

    // Create the pty
    //
    // The pty forks a process to run the shell on the slave side of the
    // pseudoterminal. A file descriptor for the master side is retained for
    // reading/writing to the shell.
    let mut pty = tty::new(display.size());

    // Create the pseudoterminal I/O loop
    //
    // pty I/O is ran on another thread as to not occupy cycles used by the
    // renderer and input processing. Note that access to the terminal state is
    // synchronized since the I/O loop updates the state, and the display
    // consumes it periodically.
    let event_loop = EventLoop::new(
        terminal.clone(),
        display.notifier(),
        pty.reader(),
        options.ref_test,
    );

    // The event loop channel allows write requests from the event processor
    // to be sent to the loop and ultimately written to the pty.
    let loop_tx = event_loop.channel();

    // Event processor
    //
    // Need the Rc<RefCell<_>> here since a ref is shared in the resize callback
    let mut processor = event::Processor::new(
        input::LoopNotifier(loop_tx),
        terminal.clone(),
        display.resize_channel(),
        &config,
        options.ref_test,
    );

    // Create a config monitor when config was loaded from path
    //
    // The monitor watches the config file for changes and reloads it. Pending
    // config changes are processed in the main loop.
    let config_monitor = config.path()
        .map(|path| config::Monitor::new(path, display.notifier()));

    // Kick off the I/O thread
    let io_thread = event_loop.spawn(None);

    // Main display loop
    loop {
        // Process input and window events
        let wakeup_request = processor.process_events(display.window());

        // Handle config reloads
        let config_updated = config_monitor.as_ref()
            .and_then(|monitor| monitor.pending_config())
            .map(|new_config| {
                display.update_config(&config);
                processor.update_config(&config);
                config = new_config;
                true
            }).unwrap_or(false);

        // Maybe draw the terminal
        let mut terminal = terminal.lock();
        if wakeup_request || config_updated {
            // Handle pending resize events
            //
            // The second argument is a list of types that want to be notified
            // of display size changes.
            display.handle_resize(&mut terminal, &mut [&mut pty, &mut processor]);

            // Draw the current state of the terminal
            display.draw(terminal, &config);
        }

        // Begin shutdown if the flag was raised.
        if process_should_exit() {
            break;
        }
    }

    // FIXME patch notify library to have a shutdown method
    // config_reloader.join().ok();

    // Wait for the I/O thread thread to finish
    let _ = io_thread.join();

    Ok(())
}
<|endoftext|>


<commit_before>use std::io::prelude::*;
use std::io::Error;
use std::fs::File;
use parser::parse;
use std::time::Instant;
use docopt::Docopt;
use std::process;

pub mod lexicon;
pub mod tokenizer;
pub mod parser;
pub mod grammar;
pub mod transformer;
pub mod codegen;
extern crate docopt;
extern crate rustc_serialize;

const VERSION: &'static str = env!("CARGO_PKG_VERSION");
const USAGE: &'static str = "
honeybadger

Usage:
  badger [options]
  badger --version

Options:
  -h --help                 Show this screen.
  --version                 Show version.
  -f FILE, --file=FILE      Specifies the input file.
  -o FILE, --output=FILE    Specifies the output file.
  --ast                     Print out the Abstract Syntax Tree of the input.
";

fn read_file(path: &str) -> Result<String, Error> {
    let mut f = try!(File::open(path));
    let mut s = String::new();
    match f.read_to_string(&mut s) {
        Ok(_) => Ok(s),
        Err(err) => Err(err)
    }
}

fn write_file(filename: &str, program: String) -> Result<(), Error> {
    let mut f = try!(File::create(filename));
    match f.write_all(&program.into_bytes()[..]) {
        Ok(_) => Ok(()),
        Err(err) => Err(err)
    }
}

#[derive(Debug, RustcDecodable)]
struct Args {
    flag_file: Option<String>,
    flag_output: Option<String>,
    flag_version: bool,
    flag_ast: bool,
}

fn main() {
    let args: Args = Docopt::new(USAGE)
        .and_then(|d| d.decode())
        .unwrap_or_else(|e| e.exit());

    if args.flag_version {
        println!("v{}", VERSION);
        process::exit(0);
    }

    if args.flag_file.is_none() {
        println!("{}", USAGE);
        process::exit(0);
    }

    let file = match read_file(&args.flag_file.unwrap()) {
        Ok(file) => file,
        Err(err) => {
            println!("ERR Couldn't read file: {:?}", err);
            process::exit(1)
        }
    };

    let ast = parser::parse(file);

    if args.flag_ast {
        println!("{:#?}", ast);
        process::exit(0);
    }

    let transformed_ast = transformer::traverse(ast);
    let program = codegen::generate_code(transformed_ast, false);

    if args.flag_output.is_none() {
        println!("{}", program);
        process::exit(0);
    }

    match write_file(&args.flag_output.unwrap(), program) {
        Ok(()) => {},
        Err(err) => {
            println!("ERR Writing out.js {}", err);
            process::exit(1);
        }
    }
}
<commit_msg>Print out duration of each step<commit_after>extern crate docopt;
extern crate rustc_serialize;

use std::process;
use std::io::prelude::*;
use std::io::Error;
use std::fs::File;
use std::time::{ Instant, Duration };
use parser::parse;
use docopt::Docopt;

pub mod lexicon;
pub mod tokenizer;
pub mod parser;
pub mod grammar;
pub mod transformer;
pub mod codegen;

fn print_ms(label: &str, duration: &Duration) {
    let delta = ((duration.as_secs() as f64) * 1000.0) +
                (duration.subsec_nanos() as f64) / 1_000_000.0;

    println!("{} {}ms", label, delta);
}

const VERSION: &'static str = env!("CARGO_PKG_VERSION");
const USAGE: &'static str = "
honeybadger

Usage:
  badger [options]
  badger --version

Options:
  -h --help                 Show this screen.
  --version                 Show version.
  -f FILE, --file=FILE      Specifies the input file.
  -o FILE, --output=FILE    Specifies the output file.
  --ast                     Print out the Abstract Syntax Tree of the input.
";

fn read_file(path: &str) -> Result<String, Error> {
    let mut f = try!(File::open(path));
    let mut s = String::new();
    match f.read_to_string(&mut s) {
        Ok(_) => Ok(s),
        Err(err) => Err(err)
    }
}

fn write_file(filename: &str, program: String) -> Result<(), Error> {
    let mut f = try!(File::create(filename));
    match f.write_all(&program.into_bytes()[..]) {
        Ok(_) => Ok(()),
        Err(err) => Err(err)
    }
}

#[derive(Debug, RustcDecodable)]
struct Args {
    flag_file: Option<String>,
    flag_output: Option<String>,
    flag_version: bool,
    flag_ast: bool,
}

fn main() {
    let args: Args = Docopt::new(USAGE)
        .and_then(|d| d.decode())
        .unwrap_or_else(|e| e.exit());

    if args.flag_version {
        println!("v{}", VERSION);
        process::exit(0);
    }

    if args.flag_file.is_none() {
        println!("{}", USAGE);
        process::exit(0);
    }

    let file = match read_file(&args.flag_file.unwrap()) {
        Ok(file) => file,
        Err(err) => {
            println!("ERR Couldn't read file: {:?}", err);
            process::exit(1)
        }
    };

    let start = Instant::now();
    let ast = parser::parse(file);
    let parse_duration = Instant::now().duration_since(start);

    if args.flag_ast {
        println!("{:#?}", ast);
        print_ms("Parsing", &parse_duration);
        process::exit(0);
    }

    let start = Instant::now();
    let transformed_ast = transformer::traverse(ast);
    let transform_duration = Instant::now().duration_since(start);

    let start = Instant::now();
    let program = codegen::generate_code(transformed_ast, false);
    let codegen_duration = Instant::now().duration_since(start);

    if args.flag_output.is_none() {
        println!("{}", program);
        print_ms("Parsing        ", &parse_duration);
        print_ms("Transformation ", &transform_duration);
        print_ms("Code generation", &codegen_duration);

        process::exit(0);
    }

    match write_file(&args.flag_output.unwrap(), program) {
        Ok(()) => {},
        Err(err) => {
            println!("ERR Writing out.js {}", err);
            process::exit(1);
        }
    }
}
<|endoftext|>


<commit_before>// Aldaron's Memory Interface
// Copyright (c) 2018 Jeron Lau <jeron.lau@plopgrizzly.com>
// Licensed under the MIT LICENSE
//
// mat4.rs

// use std::ops::*;
// use std::fmt::*;

use Vec3;
use Plane;
use Frustum;

/// A 4x4 Matrix
#[derive(Clone, Copy, PartialEq)]
pub struct Mat4(pub [f32; 16]);

impl Mat4 {
	/// A no-op transform (identity matrix).
	pub fn new() -> Mat4 {
		Mat4([
			1.0, 0.0, 0.0, 0.0,
			0.0, 1.0, 0.0, 0.0,
			0.0, 0.0, 1.0, 0.0,
			0.0, 0.0, 0.0, 1.0,
		])
	}

	/// Multiply `self` by a matrix.
	pub fn matrix(self, matrix: [f32; 16]) -> Mat4 {
		self * Mat4(matrix)
	}

	/// Multiply `self` by a scale transformation matrix.
	pub fn scale(self, x: f32, y: f32, z: f32) -> Mat4 {
		self.matrix([
			x,   0.0, 0.0, 0.0,
			0.0, y,   0.0, 0.0,
			0.0, 0.0, z,   0.0,
			0.0, 0.0, 0.0, 1.0,
		])
	}

	/// Multiply `self` by a translation matrix.
	pub fn translate(self, x: f32, y: f32, z: f32) -> Mat4 {
		self.matrix([
			1.0, 0.0, 0.0, 0.0,
			0.0, 1.0, 0.0, 0.0,
			0.0, 0.0, 1.0, 0.0,
			x,   y,   z,   1.0,
		])
	}

	/// Multiply `self` by a rotation matrix.  `x`, `y` and `z` are in PI
	/// Radians.
	pub fn rotate(self, x: f32, y: f32, z: f32) -> Mat4 {
		let num9 = z * ::std::f32::consts::PI;
		let num6 = num9.sin();
		let num5 = num9.cos();
		let num8 = x * ::std::f32::consts::PI;
		let num4 = num8.sin();
		let num3 = num8.cos();
		let num7 = y * ::std::f32::consts::PI;
		let num2 = num7.sin();
		let num = num7.cos();

		let qx = ((num * num4) * num5) + ((num2 * num3) * num6);
		let qy = ((num2 * num3) * num5) - ((num * num4) * num6);
		let qz = ((num * num3) * num6) - ((num2 * num4) * num5);
		let qw = ((num * num3) * num5) + ((num2 * num4) * num6);

		let nx = -qx;
		let ny = -qy;
		let nz = -qz;

		self.matrix([
			qw,nz,qy,nx,
			qz,qw,nx,ny,
			ny,qx,qw,nz,
			qx,qy,qz,qw
		]).matrix([
			qw,nz,qy,qx,
			qz,qw,nx,qy,
			ny,qx,qw,qz,
			nx,ny,nz,qw
		])
	}
}

impl ::std::ops::Mul<Frustum> for Mat4 {
	type Output = Frustum;

	fn mul(self, rhs: Frustum) -> Self::Output {
		Frustum {
			center: self * rhs.center,
			radius: rhs.radius,
			wfov: rhs.wfov,
			hfov: rhs.hfov,
			xrot: rhs.xrot, // TODO
			yrot: rhs.yrot, // TODO
//			near: self * rhs.near,
//			far: self * rhs.far,
//			top: self * rhs.top,
//			bottom: self * rhs.bottom,
//			right: self * rhs.right,
//			left: self * rhs.left,
		}
	}
}

impl ::std::ops::Mul<Plane> for Mat4 {
	type Output = Plane;

	fn mul(self, rhs: Plane) -> Self::Output {
		let facing = rhs.facing.transform_dir(self);
		// translation vector
		let t = Vec3::new(self.0[12], self.0[13], self.0[14]);
		//
		if t == Vec3::zero() {
			return Plane { facing, offset: rhs.offset };
		}
		// Angle between normal and translation
		let mut a = facing.angle(t).abs();

		// If more than full circle, reduce
		while a > ::std::f32::consts::PI * 2.0 {
			a -= ::std::f32::consts::PI * 2.0;
		}

		let mut b = 1.0;

		// If value is over 90° it can be reduced
		if a > ::std::f32::consts::PI / 2.0 {
			// 90°-180° quadrant
			if a < ::std::f32::consts::PI {
				a = ::std::f32::consts::PI - a;
				b = -b;
			// 180°-270° quadrant
			} else if a < 3.0 * ::std::f32::consts::PI / 2.0 {
				a -= ::std::f32::consts::PI;
				b = -b;
			// 270°-360° quadrant
			} else {
				a = (2.0 * ::std::f32::consts::PI) - a;
			}
		}

		// if a == 90°
		let offset = rhs.offset + if a >= ::std::f32::consts::PI / 2.0 {
			0.0
		} else {
			a.cos() * t.mag() * b
		};

		Plane { facing, offset }
	}
}

impl ::std::ops::Mul<Vec3<f32>> for Mat4 {
	type Output = Vec3<f32>;

	/// Transform as a position.
	fn mul(self, rhs: Vec3<f32>) -> Self::Output {
		let x = self.0[0]*rhs.x + self.0[4]*rhs.y + self.0[8]*rhs.z + self.0[12]*1.0;
		let y = self.0[1]*rhs.x + self.0[5]*rhs.y + self.0[9]*rhs.z + self.0[13]*1.0;
		let z = self.0[2]*rhs.x + self.0[6]*rhs.y + self.0[10]*rhs.z + self.0[14]*1.0;

		Vec3::new(x, y, z)
	}
}

impl ::std::ops::Mul<Mat4> for Mat4 {
	type Output = Mat4;

	fn mul(self, rhs: Mat4) -> Self::Output {
		Mat4([
			(self.0[0] * rhs.0[0]) + (self.0[1] * rhs.0[4]) +
			(self.0[2] * rhs.0[8]) + (self.0[3] * rhs.0[12]),
			(self.0[0] * rhs.0[1]) + (self.0[1] * rhs.0[5]) +
			(self.0[2] * rhs.0[9]) + (self.0[3] * rhs.0[13]),
			(self.0[0] * rhs.0[2]) + (self.0[1] * rhs.0[6]) +
			(self.0[2] * rhs.0[10]) + (self.0[3] * rhs.0[14]),
			(self.0[0] * rhs.0[3]) + (self.0[1] * rhs.0[7]) +
			(self.0[2] * rhs.0[11]) + (self.0[3] * rhs.0[15]),

			(self.0[4] * rhs.0[0]) + (self.0[5] * rhs.0[4]) +
			(self.0[6] * rhs.0[8]) + (self.0[7] * rhs.0[12]),
			(self.0[4] * rhs.0[1]) + (self.0[5] * rhs.0[5]) +
			(self.0[6] * rhs.0[9]) + (self.0[7] * rhs.0[13]),
			(self.0[4] * rhs.0[2]) + (self.0[5] * rhs.0[6]) +
			(self.0[6] * rhs.0[10]) + (self.0[7] * rhs.0[14]),
			(self.0[4] * rhs.0[3]) + (self.0[5] * rhs.0[7]) +
			(self.0[6] * rhs.0[11]) + (self.0[7] * rhs.0[15]),

			(self.0[8] * rhs.0[0]) + (self.0[9] * rhs.0[4]) +
			(self.0[10] * rhs.0[8]) + (self.0[11] * rhs.0[12]),
			(self.0[8] * rhs.0[1]) + (self.0[9] * rhs.0[5]) +
			(self.0[10] * rhs.0[9]) + (self.0[11] * rhs.0[13]),
			(self.0[8] * rhs.0[2]) + (self.0[9] * rhs.0[6]) +
			(self.0[10] * rhs.0[10]) + (self.0[11] * rhs.0[14]),
			(self.0[8] * rhs.0[3]) + (self.0[9] * rhs.0[7]) +
			(self.0[10] * rhs.0[11]) + (self.0[11] * rhs.0[15]),

			(self.0[12] * rhs.0[0]) + (self.0[13] * rhs.0[4]) +
			(self.0[14] * rhs.0[8]) + (self.0[15] * rhs.0[12]),
			(self.0[12] * rhs.0[1]) + (self.0[13] * rhs.0[5]) +
			(self.0[14] * rhs.0[9]) + (self.0[15] * rhs.0[13]),
			(self.0[12] * rhs.0[2]) + (self.0[13] * rhs.0[6]) +
			(self.0[14] * rhs.0[10]) + (self.0[15] * rhs.0[14]),
			(self.0[12] * rhs.0[3]) + (self.0[13] * rhs.0[7]) +
			(self.0[14] * rhs.0[11]) + (self.0[15] * rhs.0[15])
		])
	}
}

impl ::std::fmt::Display for Mat4 {
	fn fmt(&self, fmtr: &mut ::std::fmt::Formatter) ->
		::std::result::Result<(), ::std::fmt::Error>
	{
		write!(fmtr, "{:?}", self.0)
	}
}
<commit_msg>Added Vec4<commit_after>// Aldaron's Memory Interface
// Copyright (c) 2018 Jeron Lau <jeron.lau@plopgrizzly.com>
// Licensed under the MIT LICENSE
//
// mat4.rs

// use std::ops::*;
// use std::fmt::*;

use Vec4;
use Vec3;
use Plane;
use Frustum;

/// A 4x4 Matrix
#[derive(Clone, Copy, PartialEq)]
pub struct Mat4(pub [f32; 16]);

impl Mat4 {
	/// A no-op transform (identity matrix).
	pub fn new() -> Mat4 {
		Mat4([
			1.0, 0.0, 0.0, 0.0,
			0.0, 1.0, 0.0, 0.0,
			0.0, 0.0, 1.0, 0.0,
			0.0, 0.0, 0.0, 1.0,
		])
	}

	/// Multiply `self` by a matrix.
	pub fn matrix(self, matrix: [f32; 16]) -> Mat4 {
		self * Mat4(matrix)
	}

	/// Multiply `self` by a scale transformation matrix.
	pub fn scale(self, x: f32, y: f32, z: f32) -> Mat4 {
		self.matrix([
			x,   0.0, 0.0, 0.0,
			0.0, y,   0.0, 0.0,
			0.0, 0.0, z,   0.0,
			0.0, 0.0, 0.0, 1.0,
		])
	}

	/// Multiply `self` by a translation matrix.
	pub fn translate(self, x: f32, y: f32, z: f32) -> Mat4 {
		self.matrix([
			1.0, 0.0, 0.0, 0.0,
			0.0, 1.0, 0.0, 0.0,
			0.0, 0.0, 1.0, 0.0,
			x,   y,   z,   1.0,
		])
	}

	/// Multiply `self` by a rotation matrix.  `x`, `y` and `z` are in PI
	/// Radians.
	pub fn rotate(self, x: f32, y: f32, z: f32) -> Mat4 {
		let num9 = z * ::std::f32::consts::PI;
		let num6 = num9.sin();
		let num5 = num9.cos();
		let num8 = x * ::std::f32::consts::PI;
		let num4 = num8.sin();
		let num3 = num8.cos();
		let num7 = y * ::std::f32::consts::PI;
		let num2 = num7.sin();
		let num = num7.cos();

		let qx = ((num * num4) * num5) + ((num2 * num3) * num6);
		let qy = ((num2 * num3) * num5) - ((num * num4) * num6);
		let qz = ((num * num3) * num6) - ((num2 * num4) * num5);
		let qw = ((num * num3) * num5) + ((num2 * num4) * num6);

		let nx = -qx;
		let ny = -qy;
		let nz = -qz;

		self.matrix([
			qw,nz,qy,nx,
			qz,qw,nx,ny,
			ny,qx,qw,nz,
			qx,qy,qz,qw
		]).matrix([
			qw,nz,qy,qx,
			qz,qw,nx,qy,
			ny,qx,qw,qz,
			nx,ny,nz,qw
		])
	}
}

impl ::std::ops::Mul<Frustum> for Mat4 {
	type Output = Frustum;

	fn mul(self, rhs: Frustum) -> Self::Output {
		Frustum {
			center: self * rhs.center,
			radius: rhs.radius,
			wfov: rhs.wfov,
			hfov: rhs.hfov,
			xrot: rhs.xrot, // TODO
			yrot: rhs.yrot, // TODO
//			near: self * rhs.near,
//			far: self * rhs.far,
//			top: self * rhs.top,
//			bottom: self * rhs.bottom,
//			right: self * rhs.right,
//			left: self * rhs.left,
		}
	}
}

impl ::std::ops::Mul<Plane> for Mat4 {
	type Output = Plane;

	fn mul(self, rhs: Plane) -> Self::Output {
		let facing = rhs.facing.transform_dir(self);
		// translation vector
		let t = Vec3::new(self.0[12], self.0[13], self.0[14]);
		//
		if t == Vec3::zero() {
			return Plane { facing, offset: rhs.offset };
		}
		// Angle between normal and translation
		let mut a = facing.angle(t).abs();

		// If more than full circle, reduce
		while a > ::std::f32::consts::PI * 2.0 {
			a -= ::std::f32::consts::PI * 2.0;
		}

		let mut b = 1.0;

		// If value is over 90° it can be reduced
		if a > ::std::f32::consts::PI / 2.0 {
			// 90°-180° quadrant
			if a < ::std::f32::consts::PI {
				a = ::std::f32::consts::PI - a;
				b = -b;
			// 180°-270° quadrant
			} else if a < 3.0 * ::std::f32::consts::PI / 2.0 {
				a -= ::std::f32::consts::PI;
				b = -b;
			// 270°-360° quadrant
			} else {
				a = (2.0 * ::std::f32::consts::PI) - a;
			}
		}

		// if a == 90°
		let offset = rhs.offset + if a >= ::std::f32::consts::PI / 2.0 {
			0.0
		} else {
			a.cos() * t.mag() * b
		};

		Plane { facing, offset }
	}
}

impl ::std::ops::Mul<Vec3<f32>> for Mat4 {
	type Output = Vec3<f32>;

	/// Transform as a position.
	fn mul(self, rhs: Vec3<f32>) -> Self::Output {
		let x = self.0[0]*rhs.x + self.0[4]*rhs.y + self.0[8]*rhs.z + self.0[12]*1.0;
		let y = self.0[1]*rhs.x + self.0[5]*rhs.y + self.0[9]*rhs.z + self.0[13]*1.0;
		let z = self.0[2]*rhs.x + self.0[6]*rhs.y + self.0[10]*rhs.z + self.0[14]*1.0;

		Vec3::new(x, y, z)
	}
}

impl ::std::ops::Mul<Vec4<f32>> for Mat4 {
	type Output = Vec4<f32>;

	/// Transform as a position.
	fn mul(self, rhs: Vec4<f32>) -> Self::Output {
		let x = self.0[0]*rhs.x + self.0[4]*rhs.y + self.0[8]*rhs.z + self.0[12]*rhs.w;
		let y = self.0[1]*rhs.x + self.0[5]*rhs.y + self.0[9]*rhs.z + self.0[13]*rhs.w;
		let z = self.0[2]*rhs.x + self.0[6]*rhs.y + self.0[10]*rhs.z + self.0[14]*rhs.w;
		let w = self.0[3]*rhs.x + self.0[7]*rhs.y + self.0[11]*rhs.z + self.0[15]*rhs.w;

		Vec4::new(x, y, z, w)
	}
}

impl ::std::ops::Mul<Mat4> for Mat4 {
	type Output = Mat4;

	fn mul(self, rhs: Mat4) -> Self::Output {
		Mat4([
			(self.0[0] * rhs.0[0]) + (self.0[1] * rhs.0[4]) +
			(self.0[2] * rhs.0[8]) + (self.0[3] * rhs.0[12]),
			(self.0[0] * rhs.0[1]) + (self.0[1] * rhs.0[5]) +
			(self.0[2] * rhs.0[9]) + (self.0[3] * rhs.0[13]),
			(self.0[0] * rhs.0[2]) + (self.0[1] * rhs.0[6]) +
			(self.0[2] * rhs.0[10]) + (self.0[3] * rhs.0[14]),
			(self.0[0] * rhs.0[3]) + (self.0[1] * rhs.0[7]) +
			(self.0[2] * rhs.0[11]) + (self.0[3] * rhs.0[15]),

			(self.0[4] * rhs.0[0]) + (self.0[5] * rhs.0[4]) +
			(self.0[6] * rhs.0[8]) + (self.0[7] * rhs.0[12]),
			(self.0[4] * rhs.0[1]) + (self.0[5] * rhs.0[5]) +
			(self.0[6] * rhs.0[9]) + (self.0[7] * rhs.0[13]),
			(self.0[4] * rhs.0[2]) + (self.0[5] * rhs.0[6]) +
			(self.0[6] * rhs.0[10]) + (self.0[7] * rhs.0[14]),
			(self.0[4] * rhs.0[3]) + (self.0[5] * rhs.0[7]) +
			(self.0[6] * rhs.0[11]) + (self.0[7] * rhs.0[15]),

			(self.0[8] * rhs.0[0]) + (self.0[9] * rhs.0[4]) +
			(self.0[10] * rhs.0[8]) + (self.0[11] * rhs.0[12]),
			(self.0[8] * rhs.0[1]) + (self.0[9] * rhs.0[5]) +
			(self.0[10] * rhs.0[9]) + (self.0[11] * rhs.0[13]),
			(self.0[8] * rhs.0[2]) + (self.0[9] * rhs.0[6]) +
			(self.0[10] * rhs.0[10]) + (self.0[11] * rhs.0[14]),
			(self.0[8] * rhs.0[3]) + (self.0[9] * rhs.0[7]) +
			(self.0[10] * rhs.0[11]) + (self.0[11] * rhs.0[15]),

			(self.0[12] * rhs.0[0]) + (self.0[13] * rhs.0[4]) +
			(self.0[14] * rhs.0[8]) + (self.0[15] * rhs.0[12]),
			(self.0[12] * rhs.0[1]) + (self.0[13] * rhs.0[5]) +
			(self.0[14] * rhs.0[9]) + (self.0[15] * rhs.0[13]),
			(self.0[12] * rhs.0[2]) + (self.0[13] * rhs.0[6]) +
			(self.0[14] * rhs.0[10]) + (self.0[15] * rhs.0[14]),
			(self.0[12] * rhs.0[3]) + (self.0[13] * rhs.0[7]) +
			(self.0[14] * rhs.0[11]) + (self.0[15] * rhs.0[15])
		])
	}
}

impl ::std::fmt::Display for Mat4 {
	fn fmt(&self, fmtr: &mut ::std::fmt::Formatter) ->
		::std::result::Result<(), ::std::fmt::Error>
	{
		write!(fmtr, "{:?}", self.0)
	}
}
<|endoftext|>


<commit_before>use libc::{c_int, c_ulong, c_long, c_double, c_void};
use gmp::mpz::{Mpz, mpz_ptr, mpz_srcptr};
use gmp::mpq::{Mpq, mpq_srcptr};
use gmp::mpf::{Mpf, mpf_ptr, mpf_srcptr};
use std::mem::uninitialized;
use std::cmp::{Eq, PartialEq, Ord, PartialOrd, Ordering};
use std::convert::{From, Into};

type mpfr_prec_t = c_int;
type mpfr_sign_t = c_int;
type mpfr_exp_t = c_int;

#[repr(C)]
pub enum mpfr_rnd_t {
	MPFR_RNDN=0,  /* round to nearest, with ties to even */
	MPFR_RNDZ,    /* round toward zero */
	MPFR_RNDU,    /* round toward +Inf */
	MPFR_RNDD,    /* round toward -Inf */
	MPFR_RNDA,    /* round away from zero */
	MPFR_RNDF,    /* faithful rounding (not implemented yet) */
	MPFR_RNDNA=-1 /* round to nearest, with ties away from zero (mpfr_rouund) */
}

#[repr(C)]
pub struct mpfr_struct {
    _mpfr_prec: mpfr_prec_t,
    _mpfr_sign: mpfr_sign_t,
    _mpfr_exp: mpfr_exp_t,
    _mpfr_d: *mut c_void
}

pub type mpfr_srcptr = *const mpfr_struct;
pub type mpfr_ptr = *mut mpfr_struct;

#[link(name = "mpfr")]
extern "C" {
	// Initialization
	fn mpfr_init2(x: mpfr_ptr, prec: mpfr_prec_t);
	fn mpfr_clear(x: mpfr_ptr);
	fn mpfr_set_default_prec(prec: mpfr_prec_t);
	fn mpfr_get_default_prec() -> mpfr_prec_t;
	fn mpfr_set_prec(x: mpfr_ptr, prec: mpfr_prec_t);
	fn mpfr_get_prec(x: mpfr_srcptr) -> mpfr_prec_t;

	// Assignment
	fn mpfr_set_ui_2exp(rop: mpfr_ptr, op: c_ulong, e: mpfr_exp_t, rnd: mpfr_rnd_t) -> c_int;
	fn mpfr_set_si_2exp(rop: mpfr_ptr, op: c_long, e: mpfr_exp_t, rnd: mpfr_rnd_t) -> c_int;
	fn mpfr_set_z_2exp(rop: mpfr_ptr, op: mpz_srcptr, e: mpfr_exp_t, rnd: mpfr_rnd_t) -> c_int;
	fn mpfr_set_nan(x: mpfr_ptr);
	fn mpfr_set_inf(x: mpfr_ptr, sign: c_int);
	fn mpfr_set_zero(x: mpfr_ptr, sign: c_int);

	// Initialization and assignment
	fn mpfr_init_set(rop: mpfr_ptr, op: mpfr_srcptr, rnd: mpfr_rnd_t) -> c_int;
	fn mpfr_init_set_ui(rop: mpfr_ptr, op: c_ulong, rnd: mpfr_rnd_t) -> c_int;
	fn mpfr_init_set_si(rop: mpfr_ptr, op: c_long, rnd: mpfr_rnd_t) -> c_int;
	fn mpfr_init_set_d(rop: mpfr_ptr, op: c_double, rnd: mpfr_rnd_t) -> c_int;
	fn mpfr_init_set_z(rop: mpfr_ptr, op: mpz_srcptr, rnd: mpfr_rnd_t) -> c_int;
	fn mpfr_init_set_q(rop: mpfr_ptr, op: mpq_srcptr, rnd: mpfr_rnd_t) -> c_int;
	fn mpfr_init_set_f(rop: mpfr_ptr, op: mpf_srcptr, rnd: mpfr_rnd_t) -> c_int;

	// Conversion
	fn mpfr_get_ui(op: mpfr_srcptr, rnd: mpfr_rnd_t) -> c_ulong;
	fn mpfr_get_si(op: mpfr_srcptr, rnd: mpfr_rnd_t) -> c_long;
	fn mpfr_get_d(op: mpfr_srcptr, rnd: mpfr_rnd_t) -> c_double;
	fn mpfr_get_z(rop: mpz_ptr, op: mpfr_srcptr, rnd: mpfr_rnd_t) -> c_int;
	fn mpfr_get_f(rop: mpf_ptr, op: mpfr_srcptr, rnd: mpfr_rnd_t) -> c_int;

	// Comparison
	fn mpfr_cmp(op1: mpfr_srcptr, op2: mpfr_srcptr) -> c_int;
}

pub struct Mpfr {
    pub mpfr: mpfr_struct,
}

unsafe impl Send for Mpfr { }

impl Drop for Mpfr {
    fn drop(&mut self) { unsafe { mpfr_clear(&mut self.mpfr) } }
}

impl Clone for Mpfr {
    fn clone(&self) -> Mpfr {
        unsafe {
            let mut mpfr = uninitialized();
            mpfr_init_set(&mut mpfr, &self.mpfr, mpfr_rnd_t::MPFR_RNDN);
            Mpfr { mpfr: mpfr }
        }
    }
}

impl Mpfr {
    pub fn new(precision: u64) -> Mpfr {
        unsafe {
            let mut mpfr = uninitialized();
            mpfr_init2(&mut mpfr, precision as c_int);
            Mpfr { mpfr: mpfr }
        }
    }

    pub fn new_u64_2exp(base: u64, exp: i32) -> Mpfr {
    	unsafe {
    		let mut mpfr = Mpfr::new(Mpfr::get_default_prec());
    		mpfr_set_ui_2exp(&mut mpfr.mpfr, base as c_ulong, exp as mpfr_exp_t, mpfr_rnd_t::MPFR_RNDN);
    		mpfr
    	}
    }

    pub fn new_i64_2exp(base: i64, exp: i32) -> Mpfr {
    	unsafe {
    		let mut mpfr = Mpfr::new(Mpfr::get_default_prec());
    		mpfr_set_si_2exp(&mut mpfr.mpfr, base as c_long, exp as mpfr_exp_t, mpfr_rnd_t::MPFR_RNDN);
    		mpfr
    	}
    }

    pub fn new_mpz_2exp(base: &Mpz, exp: i32) -> Mpfr {
    	unsafe {
    		let mut mpfr = Mpfr::new(Mpfr::get_default_prec());
    		mpfr_set_z_2exp(&mut mpfr.mpfr, &base.mpz, exp as mpfr_exp_t, mpfr_rnd_t::MPFR_RNDN);
    		mpfr
    	}
    }

    pub fn zero(sign: i32) -> Mpfr {
    	unsafe {
    		let mut mpfr = Mpfr::new(Mpfr::get_default_prec());
    		mpfr_set_zero(&mut mpfr.mpfr, sign as c_int);
    		mpfr
    	}
    }

    pub fn inf(sign: i32) -> Mpfr {
    	unsafe {
    		let mut mpfr = Mpfr::new(Mpfr::get_default_prec());
    		mpfr_set_inf(&mut mpfr.mpfr, sign as c_int);
    		mpfr
    	}
    }

    pub fn nan() -> Mpfr {
    	unsafe {
    		let mut mpfr = Mpfr::new(Mpfr::get_default_prec());
    		mpfr_set_nan(&mut mpfr.mpfr);
    		mpfr
    	}
    }

    pub fn get_default_prec() -> u64 {
    	unsafe {
    		mpfr_get_default_prec() as u64
    	}
    }

    pub fn set_default_prec(precision: u64) {
    	unsafe {
    		mpfr_set_default_prec(precision as c_int);
    	}
    }

    pub fn get_prec(&self) -> u64 {
    	unsafe {
    		mpfr_get_prec(&self.mpfr) as u64
    	}
    }

    pub fn set_prec(&mut self, precision: u64) {
    	unsafe {
    		mpfr_set_prec(&mut self.mpfr, precision as c_int);
    	}
    }
}

impl Eq for Mpfr { }
impl PartialEq for Mpfr {
	fn eq(&self, other: &Mpfr) -> bool {
		unsafe {
			mpfr_cmp(&self.mpfr, &other.mpfr) == 0
		}
	}
}

impl Ord for Mpfr {
    fn cmp(&self, other: &Mpfr) -> Ordering {
        let cmp = unsafe { mpfr_cmp(&self.mpfr, &other.mpfr) };
        if cmp == 0 {
            Ordering::Equal
        } else if cmp > 0 {
            Ordering::Greater
        } else {
            Ordering::Less
        }
    }
}

impl PartialOrd for Mpfr {
    fn partial_cmp(&self, other: &Mpfr) -> Option<Ordering> {
    	Some(self.cmp(other))
    }
}

// Conversions

impl From<i64> for Mpfr {
	fn from(x: i64) -> Mpfr {
        unsafe {
            let mut mpfr = uninitialized();
            mpfr_init_set_si(&mut mpfr, x as c_long, mpfr_rnd_t::MPFR_RNDN);
            Mpfr { mpfr: mpfr }
        }
	}
}

impl From<u64> for Mpfr {
	fn from(x: u64) -> Mpfr {
        unsafe {
            let mut mpfr = uninitialized();
            mpfr_init_set_ui(&mut mpfr, x as c_ulong, mpfr_rnd_t::MPFR_RNDN);
            Mpfr { mpfr: mpfr }
        }
	}
}

impl From<f64> for Mpfr {
	fn from(x: f64) -> Mpfr {
        unsafe {
            let mut mpfr = uninitialized();
            mpfr_init_set_d(&mut mpfr, x as c_double, mpfr_rnd_t::MPFR_RNDN);
            Mpfr { mpfr: mpfr }
        }
	}
}

impl From<Mpz> for Mpfr {
	fn from(x: Mpz) -> Mpfr {
        unsafe {
            let mut mpfr = uninitialized();
            mpfr_init_set_z(&mut mpfr, &x.mpz, mpfr_rnd_t::MPFR_RNDN);
            Mpfr { mpfr: mpfr }
        }
	}
}

impl From<Mpq> for Mpfr {
	fn from(x: Mpq) -> Mpfr {
        unsafe {
            let mut mpfr = uninitialized();
            mpfr_init_set_q(&mut mpfr, &x.mpq, mpfr_rnd_t::MPFR_RNDN);
            Mpfr { mpfr: mpfr }
        }
	}
}

impl From<Mpf> for Mpfr {
	fn from(x: Mpf) -> Mpfr {
        unsafe {
            let mut mpfr = uninitialized();
            mpfr_init_set_f(&mut mpfr, &x.mpf, mpfr_rnd_t::MPFR_RNDN);
            Mpfr { mpfr: mpfr }
        }
	}
}

impl<'a> Into<i64> for &'a Mpfr {
	fn into(self) -> i64 {
		unsafe {
			mpfr_get_si(&self.mpfr, mpfr_rnd_t::MPFR_RNDN) as i64
		}
	}
}

impl<'a> Into<u64> for &'a Mpfr {
	fn into(self) -> u64 {
		unsafe {
			mpfr_get_ui(&self.mpfr, mpfr_rnd_t::MPFR_RNDN) as u64
		}
	}
}

impl<'a> Into<f64> for &'a Mpfr {
	fn into(self) -> f64 {
		unsafe {
			mpfr_get_d(&self.mpfr, mpfr_rnd_t::MPFR_RNDN) as f64
		}
	}
}

impl<'a> Into<Mpz> for &'a Mpfr {
	fn into(self) -> Mpz {
		unsafe {
			let mut result = Mpz::new();
			mpfr_get_z(&mut result.mpz, &self.mpfr, mpfr_rnd_t::MPFR_RNDN);
			result
		}
	}
}

impl<'a> Into<Mpf> for &'a Mpfr {
	fn into(self) -> Mpf {
		unsafe {
			let mut result = Mpf::new(self.get_prec());
			mpfr_get_f(&mut result.mpf, &self.mpfr, mpfr_rnd_t::MPFR_RNDN);
			result
		}
	}
}
<commit_msg>Implemented simple arithmetic functions<commit_after>use libc::{c_int, c_ulong, c_long, c_double, c_void};
use gmp::mpz::{Mpz, mpz_ptr, mpz_srcptr};
use gmp::mpq::{Mpq, mpq_srcptr};
use gmp::mpf::{Mpf, mpf_ptr, mpf_srcptr};
use std::mem::uninitialized;
use std::cmp;
use std::cmp::{Eq, PartialEq, Ord, PartialOrd, Ordering};
use std::convert::{From, Into};
use std::ops::{Add, Sub, Mul, Div, Neg};

type mpfr_prec_t = c_int;
type mpfr_sign_t = c_int;
type mpfr_exp_t = c_int;

#[repr(C)]
pub enum mpfr_rnd_t {
	MPFR_RNDN=0,  /* round to nearest, with ties to even */
	MPFR_RNDZ,    /* round toward zero */
	MPFR_RNDU,    /* round toward +Inf */
	MPFR_RNDD,    /* round toward -Inf */
	MPFR_RNDA,    /* round away from zero */
	MPFR_RNDF,    /* faithful rounding (not implemented yet) */
	MPFR_RNDNA=-1 /* round to nearest, with ties away from zero (mpfr_rouund) */
}

#[repr(C)]
pub struct mpfr_struct {
    _mpfr_prec: mpfr_prec_t,
    _mpfr_sign: mpfr_sign_t,
    _mpfr_exp: mpfr_exp_t,
    _mpfr_d: *mut c_void
}

pub type mpfr_srcptr = *const mpfr_struct;
pub type mpfr_ptr = *mut mpfr_struct;

#[link(name = "mpfr")]
extern "C" {
	// Initialization
	fn mpfr_init2(x: mpfr_ptr, prec: mpfr_prec_t);
	fn mpfr_clear(x: mpfr_ptr);
	fn mpfr_set_default_prec(prec: mpfr_prec_t);
	fn mpfr_get_default_prec() -> mpfr_prec_t;
	fn mpfr_set_prec(x: mpfr_ptr, prec: mpfr_prec_t);
	fn mpfr_get_prec(x: mpfr_srcptr) -> mpfr_prec_t;

	// Assignment
	fn mpfr_set_ui_2exp(rop: mpfr_ptr, op: c_ulong, e: mpfr_exp_t, rnd: mpfr_rnd_t) -> c_int;
	fn mpfr_set_si_2exp(rop: mpfr_ptr, op: c_long, e: mpfr_exp_t, rnd: mpfr_rnd_t) -> c_int;
	fn mpfr_set_z_2exp(rop: mpfr_ptr, op: mpz_srcptr, e: mpfr_exp_t, rnd: mpfr_rnd_t) -> c_int;
	fn mpfr_set_nan(x: mpfr_ptr);
	fn mpfr_set_inf(x: mpfr_ptr, sign: c_int);
	fn mpfr_set_zero(x: mpfr_ptr, sign: c_int);

	// Initialization and assignment
	fn mpfr_init_set(rop: mpfr_ptr, op: mpfr_srcptr, rnd: mpfr_rnd_t) -> c_int;
	fn mpfr_init_set_ui(rop: mpfr_ptr, op: c_ulong, rnd: mpfr_rnd_t) -> c_int;
	fn mpfr_init_set_si(rop: mpfr_ptr, op: c_long, rnd: mpfr_rnd_t) -> c_int;
	fn mpfr_init_set_d(rop: mpfr_ptr, op: c_double, rnd: mpfr_rnd_t) -> c_int;
	fn mpfr_init_set_z(rop: mpfr_ptr, op: mpz_srcptr, rnd: mpfr_rnd_t) -> c_int;
	fn mpfr_init_set_q(rop: mpfr_ptr, op: mpq_srcptr, rnd: mpfr_rnd_t) -> c_int;
	fn mpfr_init_set_f(rop: mpfr_ptr, op: mpf_srcptr, rnd: mpfr_rnd_t) -> c_int;

	// Conversion
	fn mpfr_get_ui(op: mpfr_srcptr, rnd: mpfr_rnd_t) -> c_ulong;
	fn mpfr_get_si(op: mpfr_srcptr, rnd: mpfr_rnd_t) -> c_long;
	fn mpfr_get_d(op: mpfr_srcptr, rnd: mpfr_rnd_t) -> c_double;
	fn mpfr_get_z(rop: mpz_ptr, op: mpfr_srcptr, rnd: mpfr_rnd_t) -> c_int;
	fn mpfr_get_f(rop: mpf_ptr, op: mpfr_srcptr, rnd: mpfr_rnd_t) -> c_int;

	// Comparison
	fn mpfr_cmp(op1: mpfr_srcptr, op2: mpfr_srcptr) -> c_int;
	fn mpfr_cmp_ui(op1: mpfr_srcptr, op2: c_ulong) -> c_int;

	// Arithmetic
	fn mpfr_add(rop: mpfr_ptr, op1: mpfr_srcptr, op2: mpfr_srcptr, rnd: mpfr_rnd_t) -> c_int;
	fn mpfr_sub(rop: mpfr_ptr, op1: mpfr_srcptr, op2: mpfr_srcptr, rnd: mpfr_rnd_t) -> c_int;
	fn mpfr_mul(rop: mpfr_ptr, op1: mpfr_srcptr, op2: mpfr_srcptr, rnd: mpfr_rnd_t) -> c_int;
	fn mpfr_div(rop: mpfr_ptr, op1: mpfr_srcptr, op2: mpfr_srcptr, rnd: mpfr_rnd_t) -> c_int;
	fn mpfr_neg(rop: mpfr_ptr, op: mpfr_srcptr, rnd: mpfr_rnd_t) -> c_int;
}

pub struct Mpfr {
    pub mpfr: mpfr_struct,
}

unsafe impl Send for Mpfr { }

impl Drop for Mpfr {
    fn drop(&mut self) { unsafe { mpfr_clear(&mut self.mpfr) } }
}

impl Clone for Mpfr {
    fn clone(&self) -> Mpfr {
        unsafe {
            let mut mpfr = uninitialized();
            mpfr_init_set(&mut mpfr, &self.mpfr, mpfr_rnd_t::MPFR_RNDN);
            Mpfr { mpfr: mpfr }
        }
    }
}

impl Mpfr {
    pub fn new(precision: u64) -> Mpfr {
        unsafe {
            let mut mpfr = uninitialized();
            mpfr_init2(&mut mpfr, precision as c_int);
            Mpfr { mpfr: mpfr }
        }
    }

    pub fn new_u64_2exp(base: u64, exp: i32) -> Mpfr {
    	unsafe {
    		let mut mpfr = Mpfr::new(Mpfr::get_default_prec());
    		mpfr_set_ui_2exp(&mut mpfr.mpfr, base as c_ulong, exp as mpfr_exp_t, mpfr_rnd_t::MPFR_RNDN);
    		mpfr
    	}
    }

    pub fn new_i64_2exp(base: i64, exp: i32) -> Mpfr {
    	unsafe {
    		let mut mpfr = Mpfr::new(Mpfr::get_default_prec());
    		mpfr_set_si_2exp(&mut mpfr.mpfr, base as c_long, exp as mpfr_exp_t, mpfr_rnd_t::MPFR_RNDN);
    		mpfr
    	}
    }

    pub fn new_mpz_2exp(base: &Mpz, exp: i32) -> Mpfr {
    	unsafe {
    		let mut mpfr = Mpfr::new(Mpfr::get_default_prec());
    		mpfr_set_z_2exp(&mut mpfr.mpfr, &base.mpz, exp as mpfr_exp_t, mpfr_rnd_t::MPFR_RNDN);
    		mpfr
    	}
    }

    pub fn zero(sign: i32) -> Mpfr {
    	unsafe {
    		let mut mpfr = Mpfr::new(Mpfr::get_default_prec());
    		mpfr_set_zero(&mut mpfr.mpfr, sign as c_int);
    		mpfr
    	}
    }

    pub fn inf(sign: i32) -> Mpfr {
    	unsafe {
    		let mut mpfr = Mpfr::new(Mpfr::get_default_prec());
    		mpfr_set_inf(&mut mpfr.mpfr, sign as c_int);
    		mpfr
    	}
    }

    pub fn nan() -> Mpfr {
    	unsafe {
    		let mut mpfr = Mpfr::new(Mpfr::get_default_prec());
    		mpfr_set_nan(&mut mpfr.mpfr);
    		mpfr
    	}
    }

    pub fn get_default_prec() -> u64 {
    	unsafe {
    		mpfr_get_default_prec() as u64
    	}
    }

    pub fn set_default_prec(precision: u64) {
    	unsafe {
    		mpfr_set_default_prec(precision as c_int);
    	}
    }

    pub fn get_prec(&self) -> u64 {
    	unsafe {
    		mpfr_get_prec(&self.mpfr) as u64
    	}
    }

    pub fn set_prec(&mut self, precision: u64) {
    	unsafe {
    		mpfr_set_prec(&mut self.mpfr, precision as c_int);
    	}
    }
}

impl Eq for Mpfr { }
impl PartialEq for Mpfr {
	fn eq(&self, other: &Mpfr) -> bool {
		unsafe {
			mpfr_cmp(&self.mpfr, &other.mpfr) == 0
		}
	}
}

impl Ord for Mpfr {
    fn cmp(&self, other: &Mpfr) -> Ordering {
        let cmp = unsafe { mpfr_cmp(&self.mpfr, &other.mpfr) };
        if cmp == 0 {
            Ordering::Equal
        } else if cmp > 0 {
            Ordering::Greater
        } else {
            Ordering::Less
        }
    }
}

impl PartialOrd for Mpfr {
    fn partial_cmp(&self, other: &Mpfr) -> Option<Ordering> {
    	Some(self.cmp(other))
    }
}

// Conversions

impl From<i64> for Mpfr {
	fn from(x: i64) -> Mpfr {
        unsafe {
            let mut mpfr = uninitialized();
            mpfr_init_set_si(&mut mpfr, x as c_long, mpfr_rnd_t::MPFR_RNDN);
            Mpfr { mpfr: mpfr }
        }
	}
}

impl From<u64> for Mpfr {
	fn from(x: u64) -> Mpfr {
        unsafe {
            let mut mpfr = uninitialized();
            mpfr_init_set_ui(&mut mpfr, x as c_ulong, mpfr_rnd_t::MPFR_RNDN);
            Mpfr { mpfr: mpfr }
        }
	}
}

impl From<f64> for Mpfr {
	fn from(x: f64) -> Mpfr {
        unsafe {
            let mut mpfr = uninitialized();
            mpfr_init_set_d(&mut mpfr, x as c_double, mpfr_rnd_t::MPFR_RNDN);
            Mpfr { mpfr: mpfr }
        }
	}
}

impl From<Mpz> for Mpfr {
	fn from(x: Mpz) -> Mpfr {
        unsafe {
            let mut mpfr = uninitialized();
            mpfr_init_set_z(&mut mpfr, &x.mpz, mpfr_rnd_t::MPFR_RNDN);
            Mpfr { mpfr: mpfr }
        }
	}
}

impl From<Mpq> for Mpfr {
	fn from(x: Mpq) -> Mpfr {
        unsafe {
            let mut mpfr = uninitialized();
            mpfr_init_set_q(&mut mpfr, &x.mpq, mpfr_rnd_t::MPFR_RNDN);
            Mpfr { mpfr: mpfr }
        }
	}
}

impl From<Mpf> for Mpfr {
	fn from(x: Mpf) -> Mpfr {
        unsafe {
            let mut mpfr = uninitialized();
            mpfr_init_set_f(&mut mpfr, &x.mpf, mpfr_rnd_t::MPFR_RNDN);
            Mpfr { mpfr: mpfr }
        }
	}
}

impl<'a> Into<i64> for &'a Mpfr {
	fn into(self) -> i64 {
		unsafe {
			mpfr_get_si(&self.mpfr, mpfr_rnd_t::MPFR_RNDN) as i64
		}
	}
}

impl<'a> Into<u64> for &'a Mpfr {
	fn into(self) -> u64 {
		unsafe {
			mpfr_get_ui(&self.mpfr, mpfr_rnd_t::MPFR_RNDN) as u64
		}
	}
}

impl<'a> Into<f64> for &'a Mpfr {
	fn into(self) -> f64 {
		unsafe {
			mpfr_get_d(&self.mpfr, mpfr_rnd_t::MPFR_RNDN) as f64
		}
	}
}

impl<'a> Into<Mpz> for &'a Mpfr {
	fn into(self) -> Mpz {
		unsafe {
			let mut result = Mpz::new();
			mpfr_get_z(&mut result.mpz, &self.mpfr, mpfr_rnd_t::MPFR_RNDN);
			result
		}
	}
}

impl<'a> Into<Mpf> for &'a Mpfr {
	fn into(self) -> Mpf {
		unsafe {
			let mut result = Mpf::new(self.get_prec());
			mpfr_get_f(&mut result.mpf, &self.mpfr, mpfr_rnd_t::MPFR_RNDN);
			result
		}
	}
}

impl<'a, 'b> Add<&'a Mpfr> for &'b Mpfr {
    type Output = Mpfr;
    fn add(self, other: &Mpfr) -> Mpfr {
        unsafe {
            let mut res = Mpfr::new(cmp::max(self.get_prec() as usize,
                                             other.get_prec() as usize) as c_ulong);
            mpfr_add(&mut res.mpfr, &self.mpfr, &other.mpfr, mpfr_rnd_t::MPFR_RNDN);
            res
        }
    }
}

impl<'a, 'b> Sub<&'a Mpfr> for &'b Mpfr {
    type Output = Mpfr;
    fn sub(self, other: &Mpfr) -> Mpfr {
        unsafe {
            let mut res = Mpfr::new(cmp::max(self.get_prec() as usize,
                                             other.get_prec() as usize) as c_ulong);
            mpfr_sub(&mut res.mpfr, &self.mpfr, &other.mpfr, mpfr_rnd_t::MPFR_RNDN);
            res
        }
    }
}

impl<'a, 'b> Mul<&'a Mpfr> for &'b Mpfr {
    type Output = Mpfr;
    fn mul(self, other: &Mpfr) -> Mpfr {
        unsafe {
            let mut res = Mpfr::new(cmp::max(self.get_prec() as usize,
                                             other.get_prec() as usize) as c_ulong);
            mpfr_mul(&mut res.mpfr, &self.mpfr, &other.mpfr, mpfr_rnd_t::MPFR_RNDN);
            res
        }
    }
}

impl<'a, 'b> Div<&'a Mpfr> for &'b Mpfr {
    type Output = Mpfr;
    fn div(self, other: &Mpfr) -> Mpfr {
        unsafe {
            if mpfr_cmp_ui(&other.mpfr, 0) == 0 {
                panic!("divide by zero")
            }

            let mut res = Mpfr::new(cmp::max(self.get_prec() as usize,
                                             other.get_prec() as usize) as c_ulong);
            mpfr_div(&mut res.mpfr, &self.mpfr, &other.mpfr, mpfr_rnd_t::MPFR_RNDN);
            res
        }
    }
}

impl<'b> Neg for &'b Mpfr {
    type Output = Mpfr;
    fn neg(self) -> Mpfr {
        unsafe {
            let mut res = Mpfr::new(self.get_prec());
            mpfr_neg(&mut res.mpfr, &self.mpfr, mpfr_rnd_t::MPFR_RNDN);
            res
        }
    }
}

gen_overloads!(Mpfr);
<|endoftext|>


<commit_before>use message;

pub struct Server {
    id: i32,
}

static CONNACK_OK : [u8; 4] = [32, 2, 0, 0];
static PING_RESP : [u8; 2] = [0xd0, 0];

impl Server {
    pub fn new() -> Self {
        Server { id: 4 }
    }

    fn new_message<C: Client>(&mut self, client: &mut C, bytes: &[u8]) {
        let message_type = message::message_type(bytes);
        println!("Well...");
        match message_type {
            message::MqttType::Connect => {
                client.send(&CONNACK_OK);
            },
            message::MqttType::PingReq => {
                client.send(&PING_RESP);
            },
            message::MqttType::Subscribe => {
                let msg_id = message::subscribe_msg_id(bytes);
                let qos: u8 = 0;
                client.send(&[0x90u8, 3, 0, msg_id as u8, qos][..]);
            },
            _ => panic!("Unknown message type")
        }
    }
}

pub struct Stream {
    //the reason there's bytes_start and bytes_read is because bytes_read always grows,
    //but bytes_start only moves if full messages have been processed
    buffer: Vec<u8>,
    bytes_start: usize, //the start of the next byte window
}

impl Stream {
    pub fn new() -> Self {
        Stream { buffer: vec![0; 1024], bytes_start: 0 }
    }

    pub fn buffer(&mut self) -> &mut [u8] {
        &mut self.buffer[self.bytes_start .. ]
    }

    pub fn handle_messages<C: Client>(&mut self, bytes_read: usize, server: &mut Server, client: &mut C) {
        let vec : Vec<u8>;
        {
            let mut slice = &self.buffer[0 .. self.bytes_start + bytes_read];
            const HEADER_LEN: usize = 2;
            let mut total_len = HEADER_LEN;
            while slice.len() >= total_len {
                total_len = message::remaining_length(slice) + HEADER_LEN;
                let msg = &slice[0 .. total_len];
                slice = &slice[total_len..];
                self.bytes_start += total_len;
                server.new_message(client, msg);
            }
            vec = slice.to_vec();
        }

        //shift everything to the beginning of the buffer
        for i in 0 .. vec.len() {
            self.buffer[i] = vec[i];
        }

        self.bytes_start = vec.len();
    }
}

pub trait Client {
    fn send(&mut self, bytes: &[u8]);
}

#[cfg(test)]
struct TestClient {
    msgs: Vec<Vec<u8>>,
}

#[cfg(test)]
impl TestClient {
    fn new() -> Self {
        TestClient { msgs: vec!() }
    }

    fn last_msg(&self) -> &[u8] {
        self.msgs.last().unwrap()
    }

    fn read(&self, buffer: &mut [u8], bytes: &[u8]) -> usize {
        for i in 0..bytes.len() {
            buffer[i] = bytes[i];
        }
        bytes.len()
    }
}

#[cfg(test)]
impl Client for TestClient {
    fn send(&mut self, bytes: &[u8]) {
        self.msgs.push(bytes.to_vec());
    }
}

#[test]
fn test_connect() {
    let connect_bytes = &[
        0x10u8, 0x2a, // fixed header
        0x00, 0x06, 'M' as u8, 'Q' as u8, 'I' as u8, 's' as u8, 'd' as u8, 'p' as u8,
        0x03, // protocol version
        0xcc, // connection flags 1100111x user, pw, !wr, w(01), w, !c, x
        0x00, 0x0a, // keepalive of 100
        0x00, 0x03, 'c' as u8, 'i' as u8, 'd' as u8, // client ID
        0x00, 0x04, 'w' as u8, 'i' as u8, 'l' as u8, 'l' as u8, // will topic
        0x00, 0x04, 'w' as u8, 'm' as u8, 's' as u8, 'g' as u8, // will msg
        0x00, 0x07, 'g' as u8, 'l' as u8, 'i' as u8, 'f' as u8, 't' as u8, 'e' as u8, 'l' as u8, // username
        0x00, 0x02, 'p' as u8, 'w' as u8, // password
        ][0..];

    let mut server = Server::new();
    let mut client = TestClient::new();

    server.new_message(&mut client, connect_bytes);
    assert_eq!(client.last_msg(), &CONNACK_OK);
}

#[test]
fn test_ping() {
    let ping_bytes =  &[0xc0u8, 0][0..];

    let mut server = Server::new();
    let mut client = TestClient::new();

    server.new_message(&mut client, ping_bytes);

    assert_eq!(client.last_msg(), &PING_RESP);
}

#[test]
fn test_pings_all_at_once() {
    let ping_bytes = &[0xc0u8, 0, 0xc0, 0, 0xc0, 0, 0xc0, 0][0..];

    let mut server = Server::new();
    let mut client = TestClient::new();
    let mut stream = Stream::new();

    let bytes_read = client.read(stream.buffer(), ping_bytes);
    stream.handle_messages(bytes_read, &mut server, &mut client);

    assert_eq!(client.msgs.len(), 4);
    for msg in client.msgs {
        assert_eq!(msg, &PING_RESP);
    }
}

#[test]
fn test_pings_multiple_time_unbroken() {
    let ping_bytes = &[0xc0u8, 0, 0xc0, 0][0..];

    let mut server = Server::new();
    let mut client = TestClient::new();
    let mut stream = Stream::new();

    let bytes_read = client.read(stream.buffer(), ping_bytes);
    stream.handle_messages(bytes_read, &mut server, &mut client);
    assert_eq!(client.msgs.len(), 2);

    let bytes_read = client.read(stream.buffer(), ping_bytes);
    stream.handle_messages(bytes_read, &mut server, &mut client);
    assert_eq!(client.msgs.len(), 4);

    for msg in client.msgs {
        assert_eq!(msg, &PING_RESP);
    }
}

#[test]
fn test_pings_broken() {
    let ping_fst = &[0xc0u8][0..];
    let ping_snd = &[0u8][0..];

    let mut server = Server::new();
    let mut client = TestClient::new();
    let mut stream = Stream::new();

    let bytes_read = client.read(stream.buffer(), ping_fst);
    stream.handle_messages(bytes_read, &mut server, &mut client);
    assert_eq!(client.msgs.len(), 0);

    let bytes_read = client.read(stream.buffer(), ping_snd);
    stream.handle_messages(bytes_read, &mut server, &mut client);
    assert_eq!(client.msgs.len(), 1);

    let bytes_read = client.read(stream.buffer(), ping_fst);
    stream.handle_messages(bytes_read, &mut server, &mut client);
    assert_eq!(client.msgs.len(), 1);

    let bytes_read = client.read(stream.buffer(), ping_snd);
    stream.handle_messages(bytes_read, &mut server, &mut client);
    assert_eq!(client.msgs.len(), 2);

    for msg in client.msgs {
        assert_eq!(msg, &PING_RESP);
    }
}

#[cfg(test)]
fn string_to_bytes(s: &str) -> Vec<u8> {
    let mut vec: Vec<u8> = vec![];
    for c in s.chars() {
        vec.push(c as u8);
    }
    vec
}

#[cfg(test)]
fn subscribe_bytes(topic: &str, msg_id: u16) -> Vec<u8> {
    let mut fixed_header = [0x8cu8, 5 + topic.len() as u8].to_vec();
    let mut msg_part = vec![0, msg_id as u8];
    let mut topic_header = vec![0, topic.len() as u8];
    let mut string_bytes = string_to_bytes(topic);
    let mut bytes = vec![];
    bytes.append(&mut fixed_header);
    bytes.append(&mut msg_part);
    bytes.append(&mut topic_header);
    bytes.append(&mut string_bytes);
    bytes.push(0u8); //qos
    bytes
}

#[test]
fn test_subscribe() {
    let subscribe_bytes = &subscribe_bytes("topic", 42)[..];
    let qos: u8 = 0;
    let suback_bytes = &[0x90u8, 3, 0, 42, qos][..];

    let mut server = Server::new();
    let mut client = TestClient::new();
    let mut stream = Stream::new();
    let bytes_read = client.read(stream.buffer(), &subscribe_bytes);
    stream.handle_messages(bytes_read, &mut server, &mut client);
    assert_eq!(client.last_msg(), suback_bytes);
}
<commit_msg>cleanup<commit_after>use message;

pub struct Server {
    id: i32,
}

static CONNACK_OK : [u8; 4] = [32, 2, 0, 0];
static PING_RESP : [u8; 2] = [0xd0, 0];

impl Server {
    pub fn new() -> Self {
        Server { id: 4 }
    }

    fn new_message<C: Client>(&mut self, client: &mut C, bytes: &[u8]) {
        let message_type = message::message_type(bytes);
        match message_type {
            message::MqttType::Connect => {
                client.send(&CONNACK_OK);
            },
            message::MqttType::PingReq => {
                client.send(&PING_RESP);
            },
            message::MqttType::Subscribe => {
                let msg_id = message::subscribe_msg_id(bytes);
                let qos: u8 = 0;
                client.send(&[0x90u8, 3, 0, msg_id as u8, qos][..]);
            },
            _ => panic!("Unknown message type")
        }
    }
}

pub struct Stream {
    buffer: Vec<u8>,
    bytes_start: usize, //the start of the next byte window
}

impl Stream {
    pub fn new() -> Self {
        Stream { buffer: vec![0; 1024], bytes_start: 0 }
    }

    pub fn buffer(&mut self) -> &mut [u8] {
        &mut self.buffer[self.bytes_start .. ]
    }

    pub fn handle_messages<C: Client>(&mut self, bytes_read: usize, server: &mut Server, client: &mut C) {
        let vec : Vec<u8>;
        {
            let mut slice = &self.buffer[0 .. self.bytes_start + bytes_read];
            const HEADER_LEN: usize = 2;
            let mut total_len = HEADER_LEN;
            while slice.len() >= total_len {
                total_len = message::remaining_length(slice) + HEADER_LEN;
                let msg = &slice[0 .. total_len];
                slice = &slice[total_len..];
                self.bytes_start += total_len;
                server.new_message(client, msg);
            }
            vec = slice.to_vec();
        }

        //shift everything to the beginning of the buffer
        for i in 0 .. vec.len() {
            self.buffer[i] = vec[i];
        }

        self.bytes_start = vec.len();
    }
}

pub trait Client {
    fn send(&mut self, bytes: &[u8]);
}

#[cfg(test)]
struct TestClient {
    msgs: Vec<Vec<u8>>,
}

#[cfg(test)]
impl TestClient {
    fn new() -> Self {
        TestClient { msgs: vec!() }
    }

    fn last_msg(&self) -> &[u8] {
        self.msgs.last().unwrap()
    }

    fn read(&self, buffer: &mut [u8], bytes: &[u8]) -> usize {
        for i in 0..bytes.len() {
            buffer[i] = bytes[i];
        }
        bytes.len()
    }
}

#[cfg(test)]
impl Client for TestClient {
    fn send(&mut self, bytes: &[u8]) {
        self.msgs.push(bytes.to_vec());
    }
}

#[test]
fn test_connect() {
    let connect_bytes = &[
        0x10u8, 0x2a, // fixed header
        0x00, 0x06, 'M' as u8, 'Q' as u8, 'I' as u8, 's' as u8, 'd' as u8, 'p' as u8,
        0x03, // protocol version
        0xcc, // connection flags 1100111x user, pw, !wr, w(01), w, !c, x
        0x00, 0x0a, // keepalive of 100
        0x00, 0x03, 'c' as u8, 'i' as u8, 'd' as u8, // client ID
        0x00, 0x04, 'w' as u8, 'i' as u8, 'l' as u8, 'l' as u8, // will topic
        0x00, 0x04, 'w' as u8, 'm' as u8, 's' as u8, 'g' as u8, // will msg
        0x00, 0x07, 'g' as u8, 'l' as u8, 'i' as u8, 'f' as u8, 't' as u8, 'e' as u8, 'l' as u8, // username
        0x00, 0x02, 'p' as u8, 'w' as u8, // password
        ][0..];

    let mut server = Server::new();
    let mut client = TestClient::new();

    server.new_message(&mut client, connect_bytes);
    assert_eq!(client.last_msg(), &CONNACK_OK);
}

#[test]
fn test_ping() {
    let ping_bytes =  &[0xc0u8, 0][0..];

    let mut server = Server::new();
    let mut client = TestClient::new();

    server.new_message(&mut client, ping_bytes);

    assert_eq!(client.last_msg(), &PING_RESP);
}

#[test]
fn test_pings_all_at_once() {
    let ping_bytes = &[0xc0u8, 0, 0xc0, 0, 0xc0, 0, 0xc0, 0][0..];

    let mut server = Server::new();
    let mut client = TestClient::new();
    let mut stream = Stream::new();

    let bytes_read = client.read(stream.buffer(), ping_bytes);
    stream.handle_messages(bytes_read, &mut server, &mut client);

    assert_eq!(client.msgs.len(), 4);
    for msg in client.msgs {
        assert_eq!(msg, &PING_RESP);
    }
}

#[test]
fn test_pings_multiple_time_unbroken() {
    let ping_bytes = &[0xc0u8, 0, 0xc0, 0][0..];

    let mut server = Server::new();
    let mut client = TestClient::new();
    let mut stream = Stream::new();

    let bytes_read = client.read(stream.buffer(), ping_bytes);
    stream.handle_messages(bytes_read, &mut server, &mut client);
    assert_eq!(client.msgs.len(), 2);

    let bytes_read = client.read(stream.buffer(), ping_bytes);
    stream.handle_messages(bytes_read, &mut server, &mut client);
    assert_eq!(client.msgs.len(), 4);

    for msg in client.msgs {
        assert_eq!(msg, &PING_RESP);
    }
}

#[test]
fn test_pings_broken() {
    let ping_fst = &[0xc0u8][0..];
    let ping_snd = &[0u8][0..];

    let mut server = Server::new();
    let mut client = TestClient::new();
    let mut stream = Stream::new();

    let bytes_read = client.read(stream.buffer(), ping_fst);
    stream.handle_messages(bytes_read, &mut server, &mut client);
    assert_eq!(client.msgs.len(), 0);

    let bytes_read = client.read(stream.buffer(), ping_snd);
    stream.handle_messages(bytes_read, &mut server, &mut client);
    assert_eq!(client.msgs.len(), 1);

    let bytes_read = client.read(stream.buffer(), ping_fst);
    stream.handle_messages(bytes_read, &mut server, &mut client);
    assert_eq!(client.msgs.len(), 1);

    let bytes_read = client.read(stream.buffer(), ping_snd);
    stream.handle_messages(bytes_read, &mut server, &mut client);
    assert_eq!(client.msgs.len(), 2);

    for msg in client.msgs {
        assert_eq!(msg, &PING_RESP);
    }
}

#[cfg(test)]
fn string_to_bytes(s: &str) -> Vec<u8> {
    let mut vec: Vec<u8> = vec![];
    for c in s.chars() {
        vec.push(c as u8);
    }
    vec
}

#[cfg(test)]
fn subscribe_bytes(topic: &str, msg_id: u16) -> Vec<u8> {
    let mut fixed_header = [0x8cu8, 5 + topic.len() as u8].to_vec();
    let mut msg_part = vec![0, msg_id as u8];
    let mut topic_header = vec![0, topic.len() as u8];
    let mut string_bytes = string_to_bytes(topic);
    let mut bytes = vec![];
    bytes.append(&mut fixed_header);
    bytes.append(&mut msg_part);
    bytes.append(&mut topic_header);
    bytes.append(&mut string_bytes);
    bytes.push(0u8); //qos
    bytes
}

#[test]
fn test_subscribe() {
    let subscribe_bytes = &subscribe_bytes("topic", 42)[..];
    let qos: u8 = 0;
    let suback_bytes = &[0x90u8, 3, 0, 42, qos][..];

    let mut server = Server::new();
    let mut client = TestClient::new();
    let mut stream = Stream::new();
    let bytes_read = client.read(stream.buffer(), &subscribe_bytes);
    stream.handle_messages(bytes_read, &mut server, &mut client);
    assert_eq!(client.last_msg(), suback_bytes);
}
<|endoftext|>


<commit_before>#![allow(non_upper_case_globals)]
use rustc_serialize::json::{self, ToJson};

use rs_es::Client;

use iron::prelude::*;
use iron::status;
use iron::mime::Mime;

use logger::Logger;

use router::Router;

use params::*;

use config::*;
use search::SearchResult;
use resource::Resource;

use std::collections::HashMap;
use std::env;
use std::io::Read;
use std::marker::PhantomData;

macro_rules! try_or_422 {
  ($expr:expr) => (match $expr {
    Ok(val)  => val,
    Err(err) => {
      let mut error = HashMap::new();
      error.insert("error", format!("{}", err));

      let content_type = "application/json".parse::<Mime>().unwrap();
      return Ok(Response::with(
        (content_type, status::UnprocessableEntity, json::encode(&error).unwrap())
      ))
    }
  })
}

#[derive(Clone)]
pub struct Server<R: Resource> {
  config:   Config,
  endpoint: String,
  resource: PhantomData<R>
}

impl<R: Resource> Server<R> {
  pub fn new(endpoint: String) -> Self {
    let config = match env::args().nth(1) {
      Some(file) => Config::from_file(file),
      None       => Config::from_env()
    };

    Server {
      config:   config,
      endpoint: endpoint,
      resource: PhantomData
    }
  }

  pub fn start(&self) {
    let host = format!("{}:{}", self.config.http.host, self.config.http.port);

    println!("Searchspot v{}\n{}\n{}\n", env!("CARGO_PKG_VERSION"),
                                         self.config.es,
                                         self.config.http);

    let mut router = Router::new();
    self.handle_search(&mut router);
    self.handle_indexing(&mut router);
    self.handle_reset(&mut router);

    let mut chain = Chain::new(router);

    // for some reasons, chain::link makes heroku crash
    if env::var("DYNO").is_err() {
      chain.link(Logger::new(None));
    }

    Iron::new(chain).http(&*host).unwrap();
  }

  fn handle_search(&self, mut router: &mut Router) {
    let config = self.config.clone();

    router.get(self.endpoint.clone(), move |r: &mut Request| {
      let mut es = Client::new(&*config.es.host, config.es.port);
      Self::search(r, &mut es, &*config.es.index)
    });
  }

  fn handle_indexing(&self, mut router: &mut Router) {
    let config = self.config.clone();

    router.post(self.endpoint.clone(), move |r: &mut Request| {
      let mut es = Client::new(&*config.es.host, config.es.port);
      Self::index(r, &mut es, &*config.es.index)
    });
  }

  fn handle_reset(&self, mut router: &mut Router) {
    let config = self.config.clone();

    router.delete(self.endpoint.clone(), move |r: &mut Request| {
      let mut es = Client::new(&*config.es.host, config.es.port);
      Self::reset(r, &mut es, &*config.es.index)
    });
  }

  fn search(req: &mut Request, mut es: &mut Client, index: &str) -> IronResult<Response> {
    let params   = try_or_422!(req.get_ref::<Params>());
    let response = SearchResult {
      results: R::search(&mut es, index, params),
      params:  params.clone()
    };

    let content_type = "application/json".parse::<Mime>().unwrap();
    Ok(Response::with(
      (content_type, status::Ok, try_or_422!(json::encode(&response.to_json())))
    ))
  }

  fn index(req: &mut Request, mut es: &mut Client, index: &str) -> IronResult<Response> {
    let mut payload = String::new();
    req.body.read_to_string(&mut payload).unwrap();

    let resources: Vec<R> = try_or_422!(json::decode(&payload));
    for resource in resources {
      try_or_422!(resource.index(es, index));
    }

    Ok(Response::with(status::Created))
  }

  fn reset(_: &mut Request, mut es: &mut Client, index: &str) -> IronResult<Response> {
    match R::reset_index(&mut es, index) {
      Ok(_)  => Ok(Response::with(status::NoContent)),
      Err(_) => Ok(Response::with(status::UnprocessableEntity))
    }
  }
}
<commit_msg>server: remove bulk creation on index<commit_after>#![allow(non_upper_case_globals)]
use rustc_serialize::json::{self, ToJson};

use rs_es::Client;

use iron::prelude::*;
use iron::status;
use iron::mime::Mime;

use logger::Logger;

use router::Router;

use params::*;

use config::*;
use search::SearchResult;
use resource::Resource;

use std::collections::HashMap;
use std::env;
use std::io::Read;
use std::marker::PhantomData;

macro_rules! try_or_422 {
  ($expr:expr) => (match $expr {
    Ok(val)  => val,
    Err(err) => {
      let mut error = HashMap::new();
      error.insert("error", format!("{}", err));

      let content_type = "application/json".parse::<Mime>().unwrap();
      return Ok(Response::with(
        (content_type, status::UnprocessableEntity, json::encode(&error).unwrap())
      ))
    }
  })
}

#[derive(Clone)]
pub struct Server<R: Resource> {
  config:   Config,
  endpoint: String,
  resource: PhantomData<R>
}

impl<R: Resource> Server<R> {
  pub fn new(endpoint: String) -> Self {
    let config = match env::args().nth(1) {
      Some(file) => Config::from_file(file),
      None       => Config::from_env()
    };

    Server {
      config:   config,
      endpoint: endpoint,
      resource: PhantomData
    }
  }

  pub fn start(&self) {
    let host = format!("{}:{}", self.config.http.host, self.config.http.port);

    println!("Searchspot v{}\n{}\n{}\n", env!("CARGO_PKG_VERSION"),
                                         self.config.es,
                                         self.config.http);

    let mut router = Router::new();
    self.handle_search(&mut router);
    self.handle_indexing(&mut router);
    self.handle_reset(&mut router);

    let mut chain = Chain::new(router);

    // for some reasons, chain::link makes heroku crash
    if env::var("DYNO").is_err() {
      chain.link(Logger::new(None));
    }

    Iron::new(chain).http(&*host).unwrap();
  }

  fn handle_search(&self, mut router: &mut Router) {
    let config = self.config.clone();

    router.get(self.endpoint.clone(), move |r: &mut Request| {
      let mut es = Client::new(&*config.es.host, config.es.port);
      Self::search(r, &mut es, &*config.es.index)
    });
  }

  fn handle_indexing(&self, mut router: &mut Router) {
    let config = self.config.clone();

    router.post(self.endpoint.clone(), move |r: &mut Request| {
      let mut es = Client::new(&*config.es.host, config.es.port);
      Self::index(r, &mut es, &*config.es.index)
    });
  }

  fn handle_reset(&self, mut router: &mut Router) {
    let config = self.config.clone();

    router.delete(self.endpoint.clone(), move |r: &mut Request| {
      let mut es = Client::new(&*config.es.host, config.es.port);
      Self::reset(r, &mut es, &*config.es.index)
    });
  }

  fn search(req: &mut Request, mut es: &mut Client, index: &str) -> IronResult<Response> {
    let params   = try_or_422!(req.get_ref::<Params>());
    let response = SearchResult {
      results: R::search(&mut es, index, params),
      params:  params.clone()
    };

    let content_type = "application/json".parse::<Mime>().unwrap();
    Ok(Response::with(
      (content_type, status::Ok, try_or_422!(json::encode(&response.to_json())))
    ))
  }

  fn index(req: &mut Request, mut es: &mut Client, index: &str) -> IronResult<Response> {
    let mut payload = String::new();
    req.body.read_to_string(&mut payload).unwrap();

    let resource: R = try_or_422!(json::decode(&payload));
    try_or_422!(resource.index(es, index));

    Ok(Response::with(status::Created))
  }

  fn reset(_: &mut Request, mut es: &mut Client, index: &str) -> IronResult<Response> {
    match R::reset_index(&mut es, index) {
      Ok(_)  => Ok(Response::with(status::NoContent)),
      Err(_) => Ok(Response::with(status::UnprocessableEntity))
    }
  }
}
<|endoftext|>


<commit_before>//! `Server` listens for HTTP requests.
//!
//!```rust
//!# use rustful::server::Server;
//!# use rustful::router::Router;
//!# let routes = [];
//!let server = Server {
//!	handlers: Router::from_routes(routes),
//!	port: 8080
//!};
//!
//!server.run();
//!```

use router::Router;
use request::Request;
use response::Response;
use response::status::NotFound;

use http;
use http::server::{ResponseWriter, Config};
use http::server::request::{AbsoluteUri, AbsolutePath};
use http::headers::content_type::MediaType;
use http::method::Post;

use std::io::net::ip::{SocketAddr, Ipv4Addr, Port};
use std::str::from_utf8_owned;
use std::uint;
use std::io::BufReader;
use std::vec::Vec;

use collections::hashmap::HashMap;

use time;

use HTTP = http::server::Server;

///A handler function for routing.
pub type HandlerFn = fn(&Request, &mut Response);

#[deriving(Clone)]
pub struct Server {
	///A routing tree with response handlers
	pub handlers: Router<HandlerFn>,

	///The port where the server will listen for requests
	pub port: Port
}

impl Server {
	///Start the server and run forever.
	///This will only return if the initial connection fails.
	pub fn run(&self) {
		self.clone().serve_forever();
	}
}

impl HTTP for Server {
	fn get_config(&self) -> Config {
		Config {
			bind_address: SocketAddr {
				ip: Ipv4Addr(0, 0, 0, 0),
				port: self.port
			}
		}
	}

	fn handle_request(&self, request: &http::server::request::Request, writer: &mut ResponseWriter) {
		let mut response = Response::new(writer);
		response.headers.date = Some(time::now_utc());
		response.headers.content_type = Some(MediaType {
			type_: StrBuf::from_str("text"),
			subtype: StrBuf::from_str("plain"),
			parameters: vec!((StrBuf::from_str("charset"), StrBuf::from_str("UTF-8")))
		});
		response.headers.server = Some(StrBuf::from_str("rustful"));

		let found = match build_request(request) {
			Some(mut request) => match self.handlers.find(request.method.clone(), request.path) {
				Some((&handler, variables)) => {
					request.variables = variables;
					handler(&request, &mut response);
					true
				},
				None => false
			},
			None => false
		};

		if !found {
			let content = bytes!("File not found");
			response.headers.content_length = Some(content.len());
			response.status = NotFound;
			match response.write(content) {
				Err(e) => println!("error while writing 404: {}", e),
				_ => {}
			}
		}

		response.end();
	}
}

fn build_request<'a>(request: &'a http::server::request::Request) -> Option<Request<'a>> {
	let path = match request.request_uri {
		AbsoluteUri(ref url) => {
			Some((url.path.as_slice(), url.query.iter().map(|v| v.clone()).collect(), url.fragment.as_ref().map(|v| v.as_slice())))
		},
		AbsolutePath(ref path) => Some(parse_path(path.as_slice())),
		_ => None
	};

	match path {
		Some((path, query, fragment)) => {
			let post = if request.method == Post {
				parse_parameters(request.body.as_slice())
			} else {
				HashMap::new()
			};

			Some(Request {
				headers: *request.headers.clone(),
				method: request.method.clone(),
				path: path,
				variables: HashMap::new(),
				post: post,
				query: query,
				fragment: fragment,
				body: request.body.as_slice()
			})
		}
		None => None
	}
}

fn parse_parameters(source: &str) -> HashMap<~str, ~str> {
	let mut parameters = HashMap::new();
	for parameter in source.split('&') {
		let parts: Vec<&str> = parameter.split('=').collect();
		match parts.as_slice() {
			[name, value] => {
				parameters.insert(url_decode(name), url_decode(value));
			},
			[name] => {
				parameters.insert(url_decode(name), "".to_owned());
			},
			[name, value, ..] => {
				parameters.insert(url_decode(name), url_decode(value));
			},
			[] => {}
		}
	}

	parameters
}

fn parse_path<'a>(path: &'a str) -> (&'a str, HashMap<~str, ~str>, Option<&'a str>) {
	match path.find('?') {
		Some(index) => {
			let (query, fragment) = parse_fragment(path.slice(index+1, path.len()));
			(path.slice(0, index), parse_parameters(query), fragment)
		},
		None => {
			let (path, fragment) = parse_fragment(path);
			(path, HashMap::new(), fragment)
		}
	}
}

fn parse_fragment<'a>(path: &'a str) -> (&'a str, Option<&'a str>) {
	match path.find('#') {
		Some(index) => (path.slice(0, index), Some(path.slice(index+1, path.len()))),
		None => (path, None)
	}
}

fn url_decode(string: &str) -> ~str {
	let mut rdr = BufReader::new(string.as_bytes());
	let mut out = Vec::new();

	loop {
		let mut buf = [0];
		let ch = match rdr.read(buf) {
			Err(..) => break,
			Ok(..) => buf[0] as char
		};
		match ch {
			'+' => out.push(' ' as u8),
			'%' => {
				let mut bytes = [0, 0];
				match rdr.read(bytes) {
					Ok(2) => {}
					_ => fail!()
				}
				let ch = uint::parse_bytes(bytes, 16u).unwrap() as u8;
				out.push(ch);
			}
			ch => out.push(ch as u8)
		}
	}

	from_utf8_owned(out.as_slice().to_owned()).unwrap_or(string.to_owned())
}

#[test]
fn parsing_parameters() {
	let parameters = parse_parameters("a=1&aa=2&ab=202");
	let a = "1".to_owned();
	let aa = "2".to_owned();
	let ab = "202".to_owned();
	assert_eq!(parameters.find(&"a".to_owned()), Some(&a));
	assert_eq!(parameters.find(&"aa".to_owned()), Some(&aa));
	assert_eq!(parameters.find(&"ab".to_owned()), Some(&ab));
}

#[test]
fn parsing_parameters_with_plus() {
	let parameters = parse_parameters("a=1&aa=2+%2B+extra+meat&ab=202+fifth+avenue");
	let a = "1".to_owned();
	let aa = "2 + extra meat".to_owned();
	let ab = "202 fifth avenue".to_owned();
	assert_eq!(parameters.find(&"a".to_owned()), Some(&a));
	assert_eq!(parameters.find(&"aa".to_owned()), Some(&aa));
	assert_eq!(parameters.find(&"ab".to_owned()), Some(&ab));
}

#[test]
fn parsing_strange_parameters() {
	let parameters = parse_parameters("a=1=2&=2&ab=");
	let a = "1".to_owned();
	let aa = "2".to_owned();
	let ab = "".to_owned();
	assert_eq!(parameters.find(&"a".to_owned()), Some(&a));
	assert_eq!(parameters.find(&"".to_owned()), Some(&aa));
	assert_eq!(parameters.find(&"ab".to_owned()), Some(&ab));
}

#[test]
fn parse_path_parts() {
	let with = "this".to_owned();
	let and = "that".to_owned();
	let (path, query, fragment) = parse_path("/path/to/something?with=this&and=that#lol");
	assert_eq!(path, "/path/to/something");
	assert_eq!(query.find(&"with".to_owned()), Some(&with));
	assert_eq!(query.find(&"and".to_owned()), Some(&and));
	assert_eq!(fragment, Some("lol"));
}

#[test]
fn parse_strange_path() {
	let with = "this".to_owned();
	let and = "what?".to_owned();
	let (path, query, fragment) = parse_path("/path/to/something?with=this&and=what?#");
	assert_eq!(path, "/path/to/something");
	assert_eq!(query.find(&"with".to_owned()), Some(&with));
	assert_eq!(query.find(&"and".to_owned()), Some(&and));
	assert_eq!(fragment, Some(""));
}

#[test]
fn parse_missing_path_parts() {
	let with = "this".to_owned();
	let and = "that".to_owned();
	let (path, query, fragment) = parse_path("/path/to/something?with=this&and=that");
	assert_eq!(path, "/path/to/something");
	assert_eq!(query.find(&"with".to_owned()), Some(&with));
	assert_eq!(query.find(&"and".to_owned()), Some(&and));
	assert_eq!(fragment, None);

	let (path, query, fragment) = parse_path("/path/to/something#lol");
	assert_eq!(path, "/path/to/something");
	assert_eq!(query.len(), 0);
	assert_eq!(fragment, Some("lol"));

	let (path, query, fragment) = parse_path("?with=this&and=that#lol");
	assert_eq!(path, "");
	assert_eq!(query.find(&"with".to_owned()), Some(&with));
	assert_eq!(query.find(&"and".to_owned()), Some(&and));
	assert_eq!(fragment, Some("lol"));
}<commit_msg>Rewrote parse_parameters to be more lazy<commit_after>//! `Server` listens for HTTP requests.
//!
//!```rust
//!# use rustful::server::Server;
//!# use rustful::router::Router;
//!# let routes = [];
//!let server = Server {
//!	handlers: Router::from_routes(routes),
//!	port: 8080
//!};
//!
//!server.run();
//!```

use router::Router;
use request::Request;
use response::Response;
use response::status::NotFound;

use http;
use http::server::{ResponseWriter, Config};
use http::server::request::{AbsoluteUri, AbsolutePath};
use http::headers::content_type::MediaType;
use http::method::Post;

use std::io::net::ip::{SocketAddr, Ipv4Addr, Port};
use std::str::from_utf8_owned;
use std::uint;
use std::io::BufReader;
use std::vec::Vec;

use collections::hashmap::HashMap;

use time;

use HTTP = http::server::Server;

///A handler function for routing.
pub type HandlerFn = fn(&Request, &mut Response);

#[deriving(Clone)]
pub struct Server {
	///A routing tree with response handlers
	pub handlers: Router<HandlerFn>,

	///The port where the server will listen for requests
	pub port: Port
}

impl Server {
	///Start the server and run forever.
	///This will only return if the initial connection fails.
	pub fn run(&self) {
		self.clone().serve_forever();
	}
}

impl HTTP for Server {
	fn get_config(&self) -> Config {
		Config {
			bind_address: SocketAddr {
				ip: Ipv4Addr(0, 0, 0, 0),
				port: self.port
			}
		}
	}

	fn handle_request(&self, request: &http::server::request::Request, writer: &mut ResponseWriter) {
		let mut response = Response::new(writer);
		response.headers.date = Some(time::now_utc());
		response.headers.content_type = Some(MediaType {
			type_: StrBuf::from_str("text"),
			subtype: StrBuf::from_str("plain"),
			parameters: vec!((StrBuf::from_str("charset"), StrBuf::from_str("UTF-8")))
		});
		response.headers.server = Some(StrBuf::from_str("rustful"));

		let found = match build_request(request) {
			Some(mut request) => match self.handlers.find(request.method.clone(), request.path) {
				Some((&handler, variables)) => {
					request.variables = variables;
					handler(&request, &mut response);
					true
				},
				None => false
			},
			None => false
		};

		if !found {
			let content = bytes!("File not found");
			response.headers.content_length = Some(content.len());
			response.status = NotFound;
			match response.write(content) {
				Err(e) => println!("error while writing 404: {}", e),
				_ => {}
			}
		}

		response.end();
	}
}

fn build_request<'a>(request: &'a http::server::request::Request) -> Option<Request<'a>> {
	let path = match request.request_uri {
		AbsoluteUri(ref url) => {
			Some((url.path.as_slice(), url.query.iter().map(|v| v.clone()).collect(), url.fragment.as_ref().map(|v| v.as_slice())))
		},
		AbsolutePath(ref path) => Some(parse_path(path.as_slice())),
		_ => None
	};

	match path {
		Some((path, query, fragment)) => {
			let post = if request.method == Post {
				parse_parameters(request.body.as_slice())
			} else {
				HashMap::new()
			};

			Some(Request {
				headers: *request.headers.clone(),
				method: request.method.clone(),
				path: path,
				variables: HashMap::new(),
				post: post,
				query: query,
				fragment: fragment,
				body: request.body.as_slice()
			})
		}
		None => None
	}
}

fn parse_parameters(source: &str) -> HashMap<~str, ~str> {
	let mut parameters = HashMap::new();
	for parameter in source.split('&') {
		let mut parts = parameter.split('=');
		parts.next().map(|name|
			parameters.insert(
				url_decode(name),
				parts.next().map(|v| url_decode(v)).unwrap_or_else(|| "".to_owned())
			)
		);
	}

	parameters
}

fn parse_path<'a>(path: &'a str) -> (&'a str, HashMap<~str, ~str>, Option<&'a str>) {
	match path.find('?') {
		Some(index) => {
			let (query, fragment) = parse_fragment(path.slice(index+1, path.len()));
			(path.slice(0, index), parse_parameters(query), fragment)
		},
		None => {
			let (path, fragment) = parse_fragment(path);
			(path, HashMap::new(), fragment)
		}
	}
}

fn parse_fragment<'a>(path: &'a str) -> (&'a str, Option<&'a str>) {
	match path.find('#') {
		Some(index) => (path.slice(0, index), Some(path.slice(index+1, path.len()))),
		None => (path, None)
	}
}

fn url_decode(string: &str) -> ~str {
	let mut rdr = BufReader::new(string.as_bytes());
	let mut out = Vec::new();

	loop {
		let mut buf = [0];
		let ch = match rdr.read(buf) {
			Err(..) => break,
			Ok(..) => buf[0] as char
		};
		match ch {
			'+' => out.push(' ' as u8),
			'%' => {
				let mut bytes = [0, 0];
				match rdr.read(bytes) {
					Ok(2) => {}
					_ => fail!()
				}
				let ch = uint::parse_bytes(bytes, 16u).unwrap() as u8;
				out.push(ch);
			}
			ch => out.push(ch as u8)
		}
	}

	from_utf8_owned(out.as_slice().to_owned()).unwrap_or(string.to_owned())
}

#[test]
fn parsing_parameters() {
	let parameters = parse_parameters("a=1&aa=2&ab=202");
	let a = "1".to_owned();
	let aa = "2".to_owned();
	let ab = "202".to_owned();
	assert_eq!(parameters.find(&"a".to_owned()), Some(&a));
	assert_eq!(parameters.find(&"aa".to_owned()), Some(&aa));
	assert_eq!(parameters.find(&"ab".to_owned()), Some(&ab));
}

#[test]
fn parsing_parameters_with_plus() {
	let parameters = parse_parameters("a=1&aa=2+%2B+extra+meat&ab=202+fifth+avenue");
	let a = "1".to_owned();
	let aa = "2 + extra meat".to_owned();
	let ab = "202 fifth avenue".to_owned();
	assert_eq!(parameters.find(&"a".to_owned()), Some(&a));
	assert_eq!(parameters.find(&"aa".to_owned()), Some(&aa));
	assert_eq!(parameters.find(&"ab".to_owned()), Some(&ab));
}

#[test]
fn parsing_strange_parameters() {
	let parameters = parse_parameters("a=1=2&=2&ab=");
	let a = "1".to_owned();
	let aa = "2".to_owned();
	let ab = "".to_owned();
	assert_eq!(parameters.find(&"a".to_owned()), Some(&a));
	assert_eq!(parameters.find(&"".to_owned()), Some(&aa));
	assert_eq!(parameters.find(&"ab".to_owned()), Some(&ab));
}

#[test]
fn parse_path_parts() {
	let with = "this".to_owned();
	let and = "that".to_owned();
	let (path, query, fragment) = parse_path("/path/to/something?with=this&and=that#lol");
	assert_eq!(path, "/path/to/something");
	assert_eq!(query.find(&"with".to_owned()), Some(&with));
	assert_eq!(query.find(&"and".to_owned()), Some(&and));
	assert_eq!(fragment, Some("lol"));
}

#[test]
fn parse_strange_path() {
	let with = "this".to_owned();
	let and = "what?".to_owned();
	let (path, query, fragment) = parse_path("/path/to/something?with=this&and=what?#");
	assert_eq!(path, "/path/to/something");
	assert_eq!(query.find(&"with".to_owned()), Some(&with));
	assert_eq!(query.find(&"and".to_owned()), Some(&and));
	assert_eq!(fragment, Some(""));
}

#[test]
fn parse_missing_path_parts() {
	let with = "this".to_owned();
	let and = "that".to_owned();
	let (path, query, fragment) = parse_path("/path/to/something?with=this&and=that");
	assert_eq!(path, "/path/to/something");
	assert_eq!(query.find(&"with".to_owned()), Some(&with));
	assert_eq!(query.find(&"and".to_owned()), Some(&and));
	assert_eq!(fragment, None);

	let (path, query, fragment) = parse_path("/path/to/something#lol");
	assert_eq!(path, "/path/to/something");
	assert_eq!(query.len(), 0);
	assert_eq!(fragment, Some("lol"));

	let (path, query, fragment) = parse_path("?with=this&and=that#lol");
	assert_eq!(path, "");
	assert_eq!(query.find(&"with".to_owned()), Some(&with));
	assert_eq!(query.find(&"and".to_owned()), Some(&and));
	assert_eq!(fragment, Some("lol"));
}<|endoftext|>


<commit_before>use std::io::{self, Write, BufReader, BufRead};
use std::sync::mpsc::{self, TryRecvError};

use serde_json;

use app::TurtleApp;
use event::Event;
use query::{Query, DrawingCommand, Request, StateUpdate, Response};

/// Continuously read queries from stdin and send them to the renderer
pub fn run(
    mut app: TurtleApp,
    drawing_tx: mpsc::Sender<DrawingCommand>,
    events_rx: mpsc::Receiver<Event>,
    // Intentionally unused. Only used to tell if thread has already quit.
    _running_tx: mpsc::Sender<()>,
) {
    // Read queries from the turtle process
    let stdin = io::stdin();
    let mut reader = BufReader::new(stdin);
    loop {
        let mut buffer = String::new();
        let read_bytes = reader.read_line(&mut buffer)
            .expect("bug: unable to read data from stdin");
        if read_bytes == 0 {
            // Reached EOF, turtle process must have quit
            // We stop this loop since there is no point in continuing to read from something that
            // will never produce anything again
            break;
        }

        let query: Result<Query, _> = serde_json::from_str(&buffer);
        match query {
            Ok(query) => match query {
                Query::Request(req) => match handle_request(req, &app, &events_rx) {
                    Ok(_) => {},
                    Err(_) => break,
                },
                Query::Update(update) => handle_update(update, &mut app),
                Query::Drawing(cmd) => match drawing_tx.send(cmd) {
                    Ok(_) => {},
                    // The renderer thread is no longer around, so quit
                    Err(_) => break,
                },
            },
            Err(err) => {
                if err.is_io() || err.is_syntax() || err.is_data() {
                    panic!("bug: failed to read command from turtle process");
                }
                else if err.is_eof() {
                    // Could not read anymore bytes from stdin, the turtle process must have ended
                    break;
                }
            },
        }
    }
}

fn handle_request(
    request: Request,
    app: &TurtleApp,
    events_rx: &mpsc::Receiver<Event>,
) -> Result<(), ()> {
    use self::Request::*;
    send_response(&match request {
        TurtleState => Response::TurtleState((*app.turtle()).clone()),
        DrawingState => Response::DrawingState((*app.drawing()).clone()),
        Event => Response::Event(match events_rx.try_recv() {
            Ok(event) => Some(event),
            Err(TryRecvError::Empty) => None,
            Err(TryRecvError::Disconnected) => return Err(()),
        }),
    })
}

fn handle_update(
    update: StateUpdate,
    app: &mut TurtleApp,
) {
    use self::StateUpdate::*;
    match update {
        TurtleState(turtle) => *app.turtle_mut() = turtle,
        DrawingState(drawing) => *app.drawing_mut() = drawing,
        TemporaryPath(path) => app.set_temporary_path(path),
    }
}

/// Sends a response to stdout
fn send_response(response: &Response) -> Result<(), ()> {
    let mut stdout = io::stdout();
    match serde_json::to_writer(&mut stdout, response) {
        Ok(_) => {
            writeln!(&mut stdout)
                .expect("bug: unable to write final newline when sending response");
            Ok(())
        },
        Err(err) => {
            if err.is_io() || err.is_eof() {
                Err(())
            }
            else {
                // The other cases for err all have to do with input, so those should never occur
                unreachable!("bug: got an input error when writing output");
            }
        },
    }
}
<commit_msg>Publically exposing the logic to handle queries<commit_after>use std::io::{self, Write, BufReader, BufRead};
use std::sync::mpsc::{self, TryRecvError};

use serde_json;

use app::TurtleApp;
use event::Event;
use query::{Query, DrawingCommand, Request, StateUpdate, Response};

/// Continuously read queries from stdin and send them to the renderer
pub fn run(
    mut app: TurtleApp,
    drawing_tx: mpsc::Sender<DrawingCommand>,
    events_rx: mpsc::Receiver<Event>,
    // Intentionally unused. Only used to tell if thread has already quit.
    _running_tx: mpsc::Sender<()>,
) {
    // Read queries from the turtle process
    let stdin = io::stdin();
    let mut reader = BufReader::new(stdin);
    loop {
        let mut buffer = String::new();
        let read_bytes = reader.read_line(&mut buffer)
            .expect("bug: unable to read data from stdin");
        if read_bytes == 0 {
            // Reached EOF, turtle process must have quit
            // We stop this loop since there is no point in continuing to read from something that
            // will never produce anything again
            break;
        }

        let query: Result<Query, _> = serde_json::from_str(&buffer);
        let result: Result<(), ()> = query.map_err(|err| {
            if err.is_io() || err.is_syntax() || err.is_data() {
                panic!("bug: failed to read command from turtle process");
            }
            else if err.is_eof() {
                // Could not read anymore bytes from stdin, the turtle process must have ended
                ()
            }
            else {
                unreachable!("bug: reached unreachable case of serde error");
            }
        }).and_then(|query| {
            handle_query(query, &mut app, &events_rx, &drawing_tx).and_then(|resp| match resp {
                Some(ref response) => send_response(response),
                None => Ok(()),
            })
        });
        if let Err(_) = result {
            break;
        }
    }
}

/// Returns the appropriate Response (if any) to the given Query
///
/// Returns Err(()) if it is time to quit because we have been disconnected.
pub fn handle_query(
    query: Query,
    app: &mut TurtleApp,
    events_rx: &mpsc::Receiver<Event>,
    drawing_tx: &mpsc::Sender<DrawingCommand>,
) -> Result<Option<Response>, ()> {
    match query {
        Query::Request(req) => handle_request(req, &app, &events_rx),
        Query::Update(update) => handle_update(update, app),
        Query::Drawing(cmd) => drawing_tx.send(cmd).map(|_| None).map_err(|_| ()),
    }
}

fn handle_request(
    request: Request,
    app: &TurtleApp,
    events_rx: &mpsc::Receiver<Event>,
) -> Result<Option<Response>, ()> {
    use self::Request::*;
    Ok(Some(match request {
        TurtleState => Response::TurtleState((*app.turtle()).clone()),
        DrawingState => Response::DrawingState((*app.drawing()).clone()),
        Event => Response::Event(match events_rx.try_recv() {
            Ok(event) => Some(event),
            Err(TryRecvError::Empty) => None,
            Err(TryRecvError::Disconnected) => return Err(()),
        }),
    }))
}

fn handle_update(
    update: StateUpdate,
    app: &mut TurtleApp,
) -> Result<Option<Response>, ()> {
    use self::StateUpdate::*;
    match update {
        TurtleState(turtle) => *app.turtle_mut() = turtle,
        DrawingState(drawing) => *app.drawing_mut() = drawing,
        TemporaryPath(path) => app.set_temporary_path(path),
    }

    Ok(None)
}

/// Sends a response to stdout
fn send_response(response: &Response) -> Result<(), ()> {
    let mut stdout = io::stdout();
    match serde_json::to_writer(&mut stdout, response) {
        Ok(_) => {
            writeln!(&mut stdout)
                .expect("bug: unable to write final newline when sending response");
            Ok(())
        },
        Err(err) => {
            if err.is_io() || err.is_eof() {
                Err(())
            }
            else {
                // The other cases for err all have to do with input, so those should never occur
                unreachable!("bug: got an input error when writing output");
            }
        },
    }
}
<|endoftext|>