<commit_before>//! Playing a music file with SDL2 mixer.

extern crate sdl2_game_window;
extern crate sdl2_mixer;
extern crate sdl2;
extern crate piston;

use sdl2_game_window::WindowSDL2;
use sdl2_mixer as mix;
use piston::{
    AssetStore,
    EventIterator,
    EventSettings,
    WindowSettings,
};

fn init_audio() {
    sdl2::init(sdl2::InitAudio | sdl2::InitTimer);
    // Load dynamic libraries.
    mix::init(
          mix::InitMp3
        | mix::InitFlac
        | mix::InitMod
        | mix::InitFluidSynth
        | mix::InitModPlug
        | mix::InitOgg
    );
    mix::open_audio(
        mix::DEFAULT_FREQUENCY,
        mix::DEFAULT_FORMAT,
        mix::DEFAULT_CHANNELS,
        1024
    ).unwrap();
    mix::allocate_channels(mix::DEFAULT_CHANNELS);
}

fn main() {
    let mut window = WindowSDL2::new(
        piston::shader_version::opengl::OpenGL_3_2,
        WindowSettings {
            title: "Music".to_string(),
            size: [300, 300],
            fullscreen: false,
            exit_on_esc: true,
            samples: 0,
        }
    );

    init_audio();

    // Load music file.
    let asset_store = AssetStore::from_folder("../bin/assets");
    let file = asset_store.path("piano.wav").unwrap();
    let music = mix::Music::from_file(&file).unwrap();

    // Loop once.
    music.play(4).unwrap();

    let event_settings = EventSettings {
            updates_per_second: 120,
            max_frames_per_second: 60,
        };
    for _e in EventIterator::new(&mut window, &event_settings) {}
}

<commit_msg>Upgraded to latest rust-sdl2<commit_after>//! Playing a music file with SDL2 mixer.

extern crate sdl2_game_window;
extern crate sdl2_mixer;
extern crate sdl2;
extern crate piston;

use sdl2_game_window::WindowSDL2;
use sdl2_mixer as mix;
use piston::{
    AssetStore,
    EventIterator,
    EventSettings,
    WindowSettings,
};

fn init_audio() {
    sdl2::init(sdl2::INIT_AUDIO | sdl2::INIT_TIMER);
    // Load dynamic libraries.
    mix::init(
          mix::InitMp3
        | mix::InitFlac
        | mix::InitMod
        | mix::InitFluidSynth
        | mix::InitModPlug
        | mix::InitOgg
    );
    mix::open_audio(
        mix::DEFAULT_FREQUENCY,
        mix::DEFAULT_FORMAT,
        mix::DEFAULT_CHANNELS,
        1024
    ).unwrap();
    mix::allocate_channels(mix::DEFAULT_CHANNELS);
}

fn main() {
    let mut window = WindowSDL2::new(
        piston::shader_version::opengl::OpenGL_3_2,
        WindowSettings {
            title: "Music".to_string(),
            size: [300, 300],
            fullscreen: false,
            exit_on_esc: true,
            samples: 0,
        }
    );

    init_audio();

    // Load music file.
    let asset_store = AssetStore::from_folder("../bin/assets");
    let file = asset_store.path("piano.wav").unwrap();
    let music = mix::Music::from_file(&file).unwrap();

    // Loop once.
    music.play(4).unwrap();

    let event_settings = EventSettings {
            updates_per_second: 120,
            max_frames_per_second: 60,
        };
    for _e in EventIterator::new(&mut window, &event_settings) {}
}

<|endoftext|>


<commit_before>use circle::Circle;
use fx32::Fx32;
use ray2::Ray2;
use vec2::Vec2;

#[derive (Clone, Copy)]
pub enum Ray2TraceResult {
	Hit (Fx32, Vec2, Vec2),
	Miss,
}

pub fn fold_closer_result (a: Ray2TraceResult, b: Ray2TraceResult) -> Ray2TraceResult {
	match a {
		Ray2TraceResult::Miss => {
			return b;
		},
		Ray2TraceResult::Hit (a_t, ..) => {
			match b {
				Ray2TraceResult::Miss => {
					return a;
				},
				Ray2TraceResult::Hit (b_t, ..) => {
					if a_t < b_t {
						return a;
					}
					else {
						return b;
					}
				}
			}
		},
	}
}

pub fn ray_trace_circle (ray: &Ray2, circle: &Circle) -> Ray2TraceResult {
	let toward_circle = circle.center - ray.start;

	let ray_dot_circle = toward_circle * ray.dir;

	if ray_dot_circle < Fx32::from_int (0) {
		// Ray is heading out of the circle's space or is already out
		return Ray2TraceResult::Miss;
	}

	// TODO: Handle ray starting inside circle

	// The following is derived from the quadratic formula and my Lua code
	let a = ray.dir.length_sq ();

	if a == Fx32::from_int (0) {
		return Ray2TraceResult::Miss;
	}

	// This part is different from the canonical quadratic formula
	// I negated it because it will save a negation later on
	// Then I also halved it
	let half_b = ray_dot_circle;

	let c = toward_circle.length_sq () - circle.radius.square_64 ();

	let determinant = Fx32::from_int (4) * (half_b.square_64 () - a * c);
	if determinant < Fx32::from_int (0) {
		return Ray2TraceResult::Miss;
	}

	let t = (half_b * Fx32::from_int (2) - determinant.sqrt_64 ()) / (Fx32::from_int (2) * a);

	if t >= Fx32::from_int (0) && t <= Fx32::from_int (1) {
		let ccd_pos = ray.at (t);

		let normal = (ccd_pos - circle.center).normalized ();

		return Ray2TraceResult::Hit (t, ccd_pos, normal);
	}

	Ray2TraceResult::Miss
}
<commit_msg>Still refactoring. The quadratic formula gets a lot simpler when you know a priori what numbers the coefficients will be.<commit_after>use circle::Circle;
use fx32::Fx32;
use ray2::Ray2;
use vec2::Vec2;

#[derive (Clone, Copy)]
pub enum Ray2TraceResult {
	Hit (Fx32, Vec2, Vec2),
	Miss,
}

pub fn fold_closer_result (a: Ray2TraceResult, b: Ray2TraceResult) -> Ray2TraceResult {
	match a {
		Ray2TraceResult::Miss => {
			return b;
		},
		Ray2TraceResult::Hit (a_t, ..) => {
			match b {
				Ray2TraceResult::Miss => {
					return a;
				},
				Ray2TraceResult::Hit (b_t, ..) => {
					if a_t < b_t {
						return a;
					}
					else {
						return b;
					}
				}
			}
		},
	}
}

pub fn ray_trace_circle (ray: &Ray2, circle: &Circle) -> Ray2TraceResult {
	let toward_circle = circle.center - ray.start;

	let ray_dot_circle = toward_circle * ray.dir;

	if ray_dot_circle < Fx32::from_int (0) {
		// Ray is heading out of the circle's space or is already out
		return Ray2TraceResult::Miss;
	}

	// TODO: Handle ray starting inside circle

	// The following is derived from the quadratic formula and my Lua code
	let a = ray.dir.length_sq ();

	if a == Fx32::from_int (0) {
		return Ray2TraceResult::Miss;
	}

	// This part is different from the canonical quadratic formula
	// I negated it because it will save a negation later on
	// Then I also halved it
	let half_b = ray_dot_circle;

	let c = toward_circle.length_sq () - circle.radius.square_64 ();

	let quarter_determinant = half_b.square_64 () - a * c;
	if quarter_determinant < Fx32::from_int (0) {
		return Ray2TraceResult::Miss;
	}

	let t = (half_b - quarter_determinant.sqrt_64 ()) / a;

	if t >= Fx32::from_int (0) && t <= Fx32::from_int (1) {
		let ccd_pos = ray.at (t);

		let normal = (ccd_pos - circle.center).normalized ();

		return Ray2TraceResult::Hit (t, ccd_pos, normal);
	}

	Ray2TraceResult::Miss
}
<|endoftext|>


<commit_before>use std::io::Write;

use liquid_error::Result;

use compiler::LiquidOptions;
use compiler::TagBlock;
use compiler::TagTokenIter;
use interpreter::Context;
use interpreter::Renderable;

#[derive(Copy, Clone, Debug)]
struct Comment;

impl Renderable for Comment {
    fn render_to(&self, _writer: &mut Write, _context: &mut Context) -> Result<()> {
        Ok(())
    }
}

pub fn comment_block(
    _tag_name: &str,
    mut arguments: TagTokenIter,
    mut tokens: TagBlock,
    _options: &LiquidOptions,
) -> Result<Box<Renderable>> {
    // no arguments should be supplied, trying to supply them is an error
    arguments.expect_nothing()?;

    while tokens.next()?.is_some() {}
    tokens.assert_empty();
    Ok(Box::new(Comment))
}

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

    fn options() -> LiquidOptions {
        let mut options = LiquidOptions::default();
        options
            .blocks
            .insert("comment", (comment_block as compiler::FnParseBlock).into());
        options
    }

    fn unit_parse(text: &str) -> String {
        let options = options();
        let template = compiler::parse(text, &options)
            .map(interpreter::Template::new)
            .unwrap();

        let mut context = Context::new();

        template.render(&mut context).unwrap()
    }

    #[test]
    fn test_comment() {
        let output = unit_parse("{% comment %} This is a test {% endcomment %}");
        assert_eq!(output, "");
    }
}
<commit_msg>fix(comment_block): allow nesting<commit_after>use std::io::Write;

use liquid_error::Result;

use compiler::BlockElement;
use compiler::LiquidOptions;
use compiler::TagBlock;
use compiler::TagTokenIter;
use interpreter::Context;
use interpreter::Renderable;

#[derive(Copy, Clone, Debug)]
struct Comment;

impl Renderable for Comment {
    fn render_to(&self, _writer: &mut Write, _context: &mut Context) -> Result<()> {
        Ok(())
    }
}

pub fn comment_block(
    tag_name: &str,
    mut arguments: TagTokenIter,
    mut tokens: TagBlock,
    options: &LiquidOptions,
) -> Result<Box<Renderable>> {
    // no arguments should be supplied, trying to supply them is an error
    arguments.expect_nothing()?;

    while let Some(token) = tokens.next()? {
        // Only parse `{% comment %}` tags (in order to allow nesting)
        if let BlockElement::Tag(tag) = token {
            if tag.name() == tag_name {
                tag.parse(&mut tokens, options)?;
            }
        }
    }

    tokens.assert_empty();
    Ok(Box::new(Comment))
}

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

    fn options() -> LiquidOptions {
        let mut options = LiquidOptions::default();
        options
            .blocks
            .insert("comment", (comment_block as compiler::FnParseBlock).into());
        options
    }

    fn unit_parse(text: &str) -> String {
        let options = options();
        let template = compiler::parse(text, &options)
            .map(interpreter::Template::new)
            .unwrap();

        let mut context = Context::new();

        template.render(&mut context).unwrap()
    }

    #[test]
    fn test_comment() {
        let output = unit_parse("{% comment %} This is a test {% endcomment %}");
        assert_eq!(output, "");
    }
}
<|endoftext|>


<commit_before>//! Wherein are contained functions for checking the terminal's properties: its size, whether cetrain keys are pressed, mouse position, etc.
//!
//! Logical property groups are represented as modules.

pub mod mouse;

use geometry::Size;
use terminal::KeyCode;
use bear_lib_terminal_sys as ffi;

pub fn size() -> Size {
	Size::new(ffi::state(ffi::TK_WIDTH), ffi::state(ffi::TK_HEIGHT))
}

pub fn key_pressed(key: KeyCode) -> bool {
	ffi::check(match key {
		KeyCode::A            => ffi::TK_A,
		KeyCode::B            => ffi::TK_B,
		KeyCode::C            => ffi::TK_C,
		KeyCode::D            => ffi::TK_D,
		KeyCode::E            => ffi::TK_E,
		KeyCode::F            => ffi::TK_F,
		KeyCode::G            => ffi::TK_G,
		KeyCode::H            => ffi::TK_H,
		KeyCode::I            => ffi::TK_I,
		KeyCode::J            => ffi::TK_J,
		KeyCode::K            => ffi::TK_K,
		KeyCode::L            => ffi::TK_L,
		KeyCode::M            => ffi::TK_M,
		KeyCode::N            => ffi::TK_N,
		KeyCode::O            => ffi::TK_O,
		KeyCode::P            => ffi::TK_P,
		KeyCode::Q            => ffi::TK_Q,
		KeyCode::R            => ffi::TK_R,
		KeyCode::S            => ffi::TK_S,
		KeyCode::T            => ffi::TK_T,
		KeyCode::U            => ffi::TK_U,
		KeyCode::V            => ffi::TK_V,
		KeyCode::W            => ffi::TK_W,
		KeyCode::X            => ffi::TK_X,
		KeyCode::Y            => ffi::TK_Y,
		KeyCode::Z            => ffi::TK_Z,
		KeyCode::Row1         => ffi::TK_1,
		KeyCode::Row2         => ffi::TK_2,
		KeyCode::Row3         => ffi::TK_3,
		KeyCode::Row4         => ffi::TK_4,
		KeyCode::Row5         => ffi::TK_5,
		KeyCode::Row6         => ffi::TK_6,
		KeyCode::Row7         => ffi::TK_7,
		KeyCode::Row8         => ffi::TK_8,
		KeyCode::Row9         => ffi::TK_9,
		KeyCode::Row0         => ffi::TK_0,
		KeyCode::Enter        => ffi::TK_ENTER,
		KeyCode::Escape       => ffi::TK_ESCAPE,
		KeyCode::Backspace    => ffi::TK_BACKSPACE,
		KeyCode::Tab          => ffi::TK_TAB,
		KeyCode::Space        => ffi::TK_SPACE,
		KeyCode::Minus        => ffi::TK_MINUS,
		KeyCode::Equals       => ffi::TK_EQUALS,
		KeyCode::LeftBracket  => ffi::TK_LBRACKET,
		KeyCode::RightBracket => ffi::TK_RBRACKET,
		KeyCode::Backslash    => ffi::TK_BACKSLASH,
		KeyCode::Semicolon    => ffi::TK_SEMICOLON,
		KeyCode::Apostrophe   => ffi::TK_APOSTROPHE,
		KeyCode::Grave        => ffi::TK_GRAVE,
		KeyCode::Comma        => ffi::TK_COMMA,
		KeyCode::Period       => ffi::TK_PERIOD,
		KeyCode::Slash        => ffi::TK_SLASH,
		KeyCode::F1           => ffi::TK_F1,
		KeyCode::F2           => ffi::TK_F2,
		KeyCode::F3           => ffi::TK_F3,
		KeyCode::F4           => ffi::TK_F4,
		KeyCode::F5           => ffi::TK_F5,
		KeyCode::F6           => ffi::TK_F6,
		KeyCode::F7           => ffi::TK_F7,
		KeyCode::F8           => ffi::TK_F8,
		KeyCode::F9           => ffi::TK_F9,
		KeyCode::F10          => ffi::TK_F10,
		KeyCode::F11          => ffi::TK_F11,
		KeyCode::F12          => ffi::TK_F12,
		KeyCode::Pause        => ffi::TK_PAUSE,
		KeyCode::Insert       => ffi::TK_INSERT,
		KeyCode::Home         => ffi::TK_HOME,
		KeyCode::PageUp       => ffi::TK_PAGEUP,
		KeyCode::Delete       => ffi::TK_DELETE,
		KeyCode::End          => ffi::TK_END,
		KeyCode::PageDown     => ffi::TK_PAGEDOWN,
		KeyCode::Right        => ffi::TK_RIGHT,
		KeyCode::Left         => ffi::TK_LEFT,
		KeyCode::Down         => ffi::TK_DOWN,
		KeyCode::Up           => ffi::TK_UP,
		KeyCode::NumDivide    => ffi::TK_KP_DIVIDE,
		KeyCode::NumMultiply  => ffi::TK_KP_MULTIPLY,
		KeyCode::NumMinus     => ffi::TK_KP_MINUS,
		KeyCode::NumPlus      => ffi::TK_KP_PLUS,
		KeyCode::NumEnter     => ffi::TK_KP_ENTER,
		KeyCode::Num1         => ffi::TK_KP_1,
		KeyCode::Num2         => ffi::TK_KP_2,
		KeyCode::Num3         => ffi::TK_KP_3,
		KeyCode::Num4         => ffi::TK_KP_4,
		KeyCode::Num5         => ffi::TK_KP_5,
		KeyCode::Num6         => ffi::TK_KP_6,
		KeyCode::Num7         => ffi::TK_KP_7,
		KeyCode::Num8         => ffi::TK_KP_8,
		KeyCode::Num9         => ffi::TK_KP_9,
		KeyCode::Num0         => ffi::TK_KP_0,
		KeyCode::NumPeriod    => ffi::TK_KP_PERIOD,
		KeyCode::MouseLeft    => ffi::TK_MOUSE_LEFT,
		KeyCode::MouseRight   => ffi::TK_MOUSE_RIGHT,
		KeyCode::MouseMiddle  => ffi::TK_MOUSE_MIDDLE,
		KeyCode::MouseFourth  => ffi::TK_MOUSE_X1,
		KeyCode::MouseFifth   => ffi::TK_MOUSE_X2,
	})
}
<commit_msg>Add example code for terminal::state<commit_after>//! Wherein are contained functions for checking the terminal's properties: its size, whether cetrain keys are pressed, mouse position, etc.
//!
//! Logical property groups are represented as modules.
//!
//! # Examples
//!
//! ```ignore
//! # // Ignore here, because on CI all `open()` calls will fail, as there's no graphical env. there
//! use bear_lib_terminal::terminal;
//! use bear_lib_terminal::geometry::Size;
//!
//! terminal::open("terminal::state example", 60, 25);
//! assert!(terminal::state::size() == Size::new(60, 25));
//! terminal::close();
//! ```

pub mod mouse;

use geometry::Size;
use terminal::KeyCode;
use bear_lib_terminal_sys as ffi;

pub fn size() -> Size {
	Size::new(ffi::state(ffi::TK_WIDTH), ffi::state(ffi::TK_HEIGHT))
}

pub fn key_pressed(key: KeyCode) -> bool {
	ffi::check(match key {
		KeyCode::A            => ffi::TK_A,
		KeyCode::B            => ffi::TK_B,
		KeyCode::C            => ffi::TK_C,
		KeyCode::D            => ffi::TK_D,
		KeyCode::E            => ffi::TK_E,
		KeyCode::F            => ffi::TK_F,
		KeyCode::G            => ffi::TK_G,
		KeyCode::H            => ffi::TK_H,
		KeyCode::I            => ffi::TK_I,
		KeyCode::J            => ffi::TK_J,
		KeyCode::K            => ffi::TK_K,
		KeyCode::L            => ffi::TK_L,
		KeyCode::M            => ffi::TK_M,
		KeyCode::N            => ffi::TK_N,
		KeyCode::O            => ffi::TK_O,
		KeyCode::P            => ffi::TK_P,
		KeyCode::Q            => ffi::TK_Q,
		KeyCode::R            => ffi::TK_R,
		KeyCode::S            => ffi::TK_S,
		KeyCode::T            => ffi::TK_T,
		KeyCode::U            => ffi::TK_U,
		KeyCode::V            => ffi::TK_V,
		KeyCode::W            => ffi::TK_W,
		KeyCode::X            => ffi::TK_X,
		KeyCode::Y            => ffi::TK_Y,
		KeyCode::Z            => ffi::TK_Z,
		KeyCode::Row1         => ffi::TK_1,
		KeyCode::Row2         => ffi::TK_2,
		KeyCode::Row3         => ffi::TK_3,
		KeyCode::Row4         => ffi::TK_4,
		KeyCode::Row5         => ffi::TK_5,
		KeyCode::Row6         => ffi::TK_6,
		KeyCode::Row7         => ffi::TK_7,
		KeyCode::Row8         => ffi::TK_8,
		KeyCode::Row9         => ffi::TK_9,
		KeyCode::Row0         => ffi::TK_0,
		KeyCode::Enter        => ffi::TK_ENTER,
		KeyCode::Escape       => ffi::TK_ESCAPE,
		KeyCode::Backspace    => ffi::TK_BACKSPACE,
		KeyCode::Tab          => ffi::TK_TAB,
		KeyCode::Space        => ffi::TK_SPACE,
		KeyCode::Minus        => ffi::TK_MINUS,
		KeyCode::Equals       => ffi::TK_EQUALS,
		KeyCode::LeftBracket  => ffi::TK_LBRACKET,
		KeyCode::RightBracket => ffi::TK_RBRACKET,
		KeyCode::Backslash    => ffi::TK_BACKSLASH,
		KeyCode::Semicolon    => ffi::TK_SEMICOLON,
		KeyCode::Apostrophe   => ffi::TK_APOSTROPHE,
		KeyCode::Grave        => ffi::TK_GRAVE,
		KeyCode::Comma        => ffi::TK_COMMA,
		KeyCode::Period       => ffi::TK_PERIOD,
		KeyCode::Slash        => ffi::TK_SLASH,
		KeyCode::F1           => ffi::TK_F1,
		KeyCode::F2           => ffi::TK_F2,
		KeyCode::F3           => ffi::TK_F3,
		KeyCode::F4           => ffi::TK_F4,
		KeyCode::F5           => ffi::TK_F5,
		KeyCode::F6           => ffi::TK_F6,
		KeyCode::F7           => ffi::TK_F7,
		KeyCode::F8           => ffi::TK_F8,
		KeyCode::F9           => ffi::TK_F9,
		KeyCode::F10          => ffi::TK_F10,
		KeyCode::F11          => ffi::TK_F11,
		KeyCode::F12          => ffi::TK_F12,
		KeyCode::Pause        => ffi::TK_PAUSE,
		KeyCode::Insert       => ffi::TK_INSERT,
		KeyCode::Home         => ffi::TK_HOME,
		KeyCode::PageUp       => ffi::TK_PAGEUP,
		KeyCode::Delete       => ffi::TK_DELETE,
		KeyCode::End          => ffi::TK_END,
		KeyCode::PageDown     => ffi::TK_PAGEDOWN,
		KeyCode::Right        => ffi::TK_RIGHT,
		KeyCode::Left         => ffi::TK_LEFT,
		KeyCode::Down         => ffi::TK_DOWN,
		KeyCode::Up           => ffi::TK_UP,
		KeyCode::NumDivide    => ffi::TK_KP_DIVIDE,
		KeyCode::NumMultiply  => ffi::TK_KP_MULTIPLY,
		KeyCode::NumMinus     => ffi::TK_KP_MINUS,
		KeyCode::NumPlus      => ffi::TK_KP_PLUS,
		KeyCode::NumEnter     => ffi::TK_KP_ENTER,
		KeyCode::Num1         => ffi::TK_KP_1,
		KeyCode::Num2         => ffi::TK_KP_2,
		KeyCode::Num3         => ffi::TK_KP_3,
		KeyCode::Num4         => ffi::TK_KP_4,
		KeyCode::Num5         => ffi::TK_KP_5,
		KeyCode::Num6         => ffi::TK_KP_6,
		KeyCode::Num7         => ffi::TK_KP_7,
		KeyCode::Num8         => ffi::TK_KP_8,
		KeyCode::Num9         => ffi::TK_KP_9,
		KeyCode::Num0         => ffi::TK_KP_0,
		KeyCode::NumPeriod    => ffi::TK_KP_PERIOD,
		KeyCode::MouseLeft    => ffi::TK_MOUSE_LEFT,
		KeyCode::MouseRight   => ffi::TK_MOUSE_RIGHT,
		KeyCode::MouseMiddle  => ffi::TK_MOUSE_MIDDLE,
		KeyCode::MouseFourth  => ffi::TK_MOUSE_X1,
		KeyCode::MouseFifth   => ffi::TK_MOUSE_X2,
	})
}
<|endoftext|>


<commit_before>use cranelift::frontend::FunctionBuilder;
use cranelift::prelude::{FloatCC, InstBuilder, IntCC, StackSlotData, StackSlotKind, Value as CraneliftValue};

use crate::hir::{Ast, Builtin};

use super::context::{int_pointer_type, pointer_type};
use super::{CodeGen, Context, Value};

pub fn call_builtin<'ast>(builtin: &'ast Builtin, context: &mut Context<'ast>, builder: &mut FunctionBuilder) -> Value {
    let mut value = |ast: &'ast Ast| ast.eval_single(context, builder);

    let result = match builtin {
        Builtin::AddInt(a, b) => add_int(value(a), value(b), builder),
        Builtin::AddFloat(a, b) => add_float(value(a), value(b), builder),

        Builtin::SubInt(a, b) => sub_int(value(a), value(b), builder),
        Builtin::SubFloat(a, b) => sub_float(value(a), value(b), builder),

        Builtin::MulInt(a, b) => mul_int(value(a), value(b), builder),
        Builtin::MulFloat(a, b) => mul_float(value(a), value(b), builder),

        Builtin::DivSigned(a, b) => div_signed(value(a), value(b), builder),
        Builtin::DivUnsigned(a, b) => div_unsigned(value(a), value(b), builder),
        Builtin::DivFloat(a, b) => div_float(value(a), value(b), builder),

        Builtin::ModSigned(a, b) => mod_signed(value(a), value(b), builder),
        Builtin::ModUnsigned(a, b) => mod_unsigned(value(a), value(b), builder),
        Builtin::ModFloat(_, _) => unimplemented!("cranelift defines no float remainder function"),

        Builtin::LessSigned(a, b) => less_signed(value(a), value(b), builder),
        Builtin::LessUnsigned(a, b) => less_unsigned(value(a), value(b), builder),
        Builtin::LessFloat(a, b) => less_float(value(a), value(b), builder),

        Builtin::EqInt(a, b) => eq_int(value(a), value(b), builder),
        Builtin::EqFloat(a, b) => eq_float(value(a), value(b), builder),
        Builtin::EqChar(a, b) => eq_char(value(a), value(b), builder),
        Builtin::EqBool(a, b) => eq_bool(value(a), value(b), builder),

        Builtin::SignExtend(a, _typ) => sign_extend(value(a), builder),
        Builtin::ZeroExtend(a, _typ) => zero_extend(value(a), builder),

        Builtin::SignedToFloat(a, _typ) => signed_to_float(value(a), builder),
        Builtin::UnsignedToFloat(a, _typ) => unsigned_to_float(value(a), builder),
        Builtin::FloatToSigned(a, _typ) => float_to_signed(value(a), builder),
        Builtin::FloatToUnsigned(a, _typ) => float_to_unsigned(value(a), builder),

        Builtin::Truncate(a, _typ) => truncate(value(a), builder),

        Builtin::Deref(a, typ) => return deref(context, typ, a, builder),
        Builtin::Offset(a, b, elem_size) => offset(value(a), value(b), *elem_size, builder),
        Builtin::Transmute(a, _typ) => transmute(value(a), builder),
        Builtin::StackAlloc(a) => stack_alloc(a, context, builder),
    };

    Value::Normal(result)
}

fn add_int(param1: CraneliftValue, param2: CraneliftValue, builder: &mut FunctionBuilder) -> CraneliftValue {
    builder.ins().iadd(param1, param2)
}

fn add_float(param1: CraneliftValue, param2: CraneliftValue, builder: &mut FunctionBuilder) -> CraneliftValue {
    builder.ins().fadd(param1, param2)
}

fn sub_int(param1: CraneliftValue, param2: CraneliftValue, builder: &mut FunctionBuilder) -> CraneliftValue {
    builder.ins().isub(param1, param2)
}

fn sub_float(param1: CraneliftValue, param2: CraneliftValue, builder: &mut FunctionBuilder) -> CraneliftValue {
    builder.ins().fsub(param1, param2)
}

fn mul_int(param1: CraneliftValue, param2: CraneliftValue, builder: &mut FunctionBuilder) -> CraneliftValue {
    builder.ins().imul(param1, param2)
}

fn mul_float(param1: CraneliftValue, param2: CraneliftValue, builder: &mut FunctionBuilder) -> CraneliftValue {
    builder.ins().fmul(param1, param2)
}

fn div_signed(param1: CraneliftValue, param2: CraneliftValue, builder: &mut FunctionBuilder) -> CraneliftValue {
    builder.ins().sdiv(param1, param2)
}

fn div_unsigned(param1: CraneliftValue, param2: CraneliftValue, builder: &mut FunctionBuilder) -> CraneliftValue {
    builder.ins().udiv(param1, param2)
}

fn div_float(param1: CraneliftValue, param2: CraneliftValue, builder: &mut FunctionBuilder) -> CraneliftValue {
    builder.ins().fdiv(param1, param2)
}

fn mod_signed(param1: CraneliftValue, param2: CraneliftValue, builder: &mut FunctionBuilder) -> CraneliftValue {
    builder.ins().srem(param1, param2)
}

fn mod_unsigned(param1: CraneliftValue, param2: CraneliftValue, builder: &mut FunctionBuilder) -> CraneliftValue {
    builder.ins().urem(param1, param2)
}

fn less_signed(param1: CraneliftValue, param2: CraneliftValue, builder: &mut FunctionBuilder) -> CraneliftValue {
    builder.ins().icmp(IntCC::SignedLessThan, param1, param2)
}

fn less_unsigned(param1: CraneliftValue, param2: CraneliftValue, builder: &mut FunctionBuilder) -> CraneliftValue {
    builder.ins().icmp(IntCC::UnsignedLessThan, param1, param2)
}

fn less_float(param1: CraneliftValue, param2: CraneliftValue, builder: &mut FunctionBuilder) -> CraneliftValue {
    builder.ins().fcmp(FloatCC::LessThan, param1, param2)
}

fn eq_int(param1: CraneliftValue, param2: CraneliftValue, builder: &mut FunctionBuilder) -> CraneliftValue {
    builder.ins().icmp(IntCC::Equal, param1, param2)
}

fn eq_float(param1: CraneliftValue, param2: CraneliftValue, builder: &mut FunctionBuilder) -> CraneliftValue {
    builder.ins().fcmp(FloatCC::Equal, param1, param2)
}

fn eq_char(param1: CraneliftValue, param2: CraneliftValue, builder: &mut FunctionBuilder) -> CraneliftValue {
    builder.ins().icmp(IntCC::Equal, param1, param2)
}

fn eq_bool(param1: CraneliftValue, param2: CraneliftValue, builder: &mut FunctionBuilder) -> CraneliftValue {
    builder.ins().icmp(IntCC::Equal, param1, param2)
}

fn transmute(param1: CraneliftValue, builder: &mut FunctionBuilder) -> CraneliftValue {
    // TODO: struct types
    let target_type = builder.func.signature.returns[0].value_type;
    let start_type = builder.func.dfg.value_type(param1);

    if start_type != target_type {
        builder.ins().bitcast(target_type, param1)
    } else {
        param1
    }
}

fn offset(
    address: CraneliftValue, offset: CraneliftValue, elem_size: u32, builder: &mut FunctionBuilder,
) -> CraneliftValue {
    let usize_type = int_pointer_type();
    let pointer_type = pointer_type();

    let size = builder.ins().iconst(int_pointer_type(), elem_size as i64);
    let offset = builder.ins().imul(offset, size);

    let address = builder.ins().bitcast(usize_type, address);
    let new_address = builder.ins().iadd(address, offset);
    builder.ins().bitcast(pointer_type, new_address)
}

// All integers are boxed as an i64, so this is a no-op in this backend
fn sign_extend(param1: CraneliftValue, builder: &mut FunctionBuilder) -> CraneliftValue {
    let target_type = builder.func.signature.returns[0].value_type;
    let start_type = builder.func.dfg.value_type(param1);
    assert!(start_type.bytes() <= target_type.bytes());

    if start_type.bytes() < target_type.bytes() {
        builder.ins().sextend(target_type, param1)
    } else {
        param1
    }
}

// All integers are boxed as an i64, so this is a no-op in this backend
fn zero_extend(param1: CraneliftValue, builder: &mut FunctionBuilder) -> CraneliftValue {
    let target_type = builder.func.signature.returns[0].value_type;
    let start_type = builder.func.dfg.value_type(param1);
    assert!(start_type.bytes() <= target_type.bytes());

    if start_type.bytes() < target_type.bytes() {
        builder.ins().uextend(target_type, param1)
    } else {
        param1
    }
}

fn signed_to_float(param1: CraneliftValue, builder: &mut FunctionBuilder) -> CraneliftValue {
    let target_type = builder.func.signature.returns[0].value_type;
    builder.ins().fcvt_from_sint(target_type, param1)
}

fn unsigned_to_float(param1: CraneliftValue, builder: &mut FunctionBuilder) -> CraneliftValue {
    let target_type = builder.func.signature.returns[0].value_type;
    builder.ins().fcvt_from_uint(target_type, param1)
}

fn float_to_signed(param1: CraneliftValue, builder: &mut FunctionBuilder) -> CraneliftValue {
    let target_type = builder.func.signature.returns[0].value_type;
    builder.ins().fcvt_to_sint(target_type, param1)
}

fn float_to_unsigned(param1: CraneliftValue, builder: &mut FunctionBuilder) -> CraneliftValue {
    let target_type = builder.func.signature.returns[0].value_type;
    builder.ins().fcvt_to_uint(target_type, param1)
}

fn truncate(param1: CraneliftValue, builder: &mut FunctionBuilder) -> CraneliftValue {
    let target_type = builder.func.signature.returns[0].value_type;
    let start_type = builder.func.dfg.value_type(param1);
    assert!(start_type.bytes() >= target_type.bytes());

    if start_type.bytes() > target_type.bytes() {
        builder.ins().ireduce(target_type, param1)
    } else {
        param1
    }
}

fn deref<'a>(context: &mut Context<'a>, typ: &crate::hir::Type, addr: &'a Ast, builder: &mut FunctionBuilder) -> Value {
    let addr = addr.eval_single(context, builder);
    context.load_value(typ, addr, &mut 0, builder)
}

fn stack_alloc<'a>(param1: &'a Ast, context: &mut Context<'a>, builder: &mut FunctionBuilder) -> CraneliftValue {
    let values = param1.eval_all(context, builder);

    let size = values.iter().map(|value| builder.func.dfg.value_type(*value).bytes()).sum();

    let data = StackSlotData::new(StackSlotKind::ExplicitSlot, size);
    let slot = builder.create_stack_slot(data);

    let mut offset: u32 = 0;
    for value in values {
        builder.ins().stack_store(value, slot, offset as i32);
        offset += builder.func.dfg.value_type(value).bytes();
    }

    builder.ins().stack_addr(pointer_type(), slot, 0)
}
<commit_msg>Fix 'invalid bitcast from I64 to I64' error on x64<commit_after>use cranelift::frontend::FunctionBuilder;
use cranelift::prelude::{FloatCC, InstBuilder, IntCC, StackSlotData, StackSlotKind, Value as CraneliftValue};

use crate::hir::{Ast, Builtin};

use super::context::{int_pointer_type, pointer_type};
use super::{CodeGen, Context, Value};

pub fn call_builtin<'ast>(builtin: &'ast Builtin, context: &mut Context<'ast>, builder: &mut FunctionBuilder) -> Value {
    let mut value = |ast: &'ast Ast| ast.eval_single(context, builder);

    let result = match builtin {
        Builtin::AddInt(a, b) => add_int(value(a), value(b), builder),
        Builtin::AddFloat(a, b) => add_float(value(a), value(b), builder),

        Builtin::SubInt(a, b) => sub_int(value(a), value(b), builder),
        Builtin::SubFloat(a, b) => sub_float(value(a), value(b), builder),

        Builtin::MulInt(a, b) => mul_int(value(a), value(b), builder),
        Builtin::MulFloat(a, b) => mul_float(value(a), value(b), builder),

        Builtin::DivSigned(a, b) => div_signed(value(a), value(b), builder),
        Builtin::DivUnsigned(a, b) => div_unsigned(value(a), value(b), builder),
        Builtin::DivFloat(a, b) => div_float(value(a), value(b), builder),

        Builtin::ModSigned(a, b) => mod_signed(value(a), value(b), builder),
        Builtin::ModUnsigned(a, b) => mod_unsigned(value(a), value(b), builder),
        Builtin::ModFloat(_, _) => unimplemented!("cranelift defines no float remainder function"),

        Builtin::LessSigned(a, b) => less_signed(value(a), value(b), builder),
        Builtin::LessUnsigned(a, b) => less_unsigned(value(a), value(b), builder),
        Builtin::LessFloat(a, b) => less_float(value(a), value(b), builder),

        Builtin::EqInt(a, b) => eq_int(value(a), value(b), builder),
        Builtin::EqFloat(a, b) => eq_float(value(a), value(b), builder),
        Builtin::EqChar(a, b) => eq_char(value(a), value(b), builder),
        Builtin::EqBool(a, b) => eq_bool(value(a), value(b), builder),

        Builtin::SignExtend(a, _typ) => sign_extend(value(a), builder),
        Builtin::ZeroExtend(a, _typ) => zero_extend(value(a), builder),

        Builtin::SignedToFloat(a, _typ) => signed_to_float(value(a), builder),
        Builtin::UnsignedToFloat(a, _typ) => unsigned_to_float(value(a), builder),
        Builtin::FloatToSigned(a, _typ) => float_to_signed(value(a), builder),
        Builtin::FloatToUnsigned(a, _typ) => float_to_unsigned(value(a), builder),

        Builtin::Truncate(a, _typ) => truncate(value(a), builder),

        Builtin::Deref(a, typ) => return deref(context, typ, a, builder),
        Builtin::Offset(a, b, elem_size) => offset(value(a), value(b), *elem_size, builder),
        Builtin::Transmute(a, _typ) => transmute(value(a), builder),
        Builtin::StackAlloc(a) => stack_alloc(a, context, builder),
    };

    Value::Normal(result)
}

fn add_int(param1: CraneliftValue, param2: CraneliftValue, builder: &mut FunctionBuilder) -> CraneliftValue {
    builder.ins().iadd(param1, param2)
}

fn add_float(param1: CraneliftValue, param2: CraneliftValue, builder: &mut FunctionBuilder) -> CraneliftValue {
    builder.ins().fadd(param1, param2)
}

fn sub_int(param1: CraneliftValue, param2: CraneliftValue, builder: &mut FunctionBuilder) -> CraneliftValue {
    builder.ins().isub(param1, param2)
}

fn sub_float(param1: CraneliftValue, param2: CraneliftValue, builder: &mut FunctionBuilder) -> CraneliftValue {
    builder.ins().fsub(param1, param2)
}

fn mul_int(param1: CraneliftValue, param2: CraneliftValue, builder: &mut FunctionBuilder) -> CraneliftValue {
    builder.ins().imul(param1, param2)
}

fn mul_float(param1: CraneliftValue, param2: CraneliftValue, builder: &mut FunctionBuilder) -> CraneliftValue {
    builder.ins().fmul(param1, param2)
}

fn div_signed(param1: CraneliftValue, param2: CraneliftValue, builder: &mut FunctionBuilder) -> CraneliftValue {
    builder.ins().sdiv(param1, param2)
}

fn div_unsigned(param1: CraneliftValue, param2: CraneliftValue, builder: &mut FunctionBuilder) -> CraneliftValue {
    builder.ins().udiv(param1, param2)
}

fn div_float(param1: CraneliftValue, param2: CraneliftValue, builder: &mut FunctionBuilder) -> CraneliftValue {
    builder.ins().fdiv(param1, param2)
}

fn mod_signed(param1: CraneliftValue, param2: CraneliftValue, builder: &mut FunctionBuilder) -> CraneliftValue {
    builder.ins().srem(param1, param2)
}

fn mod_unsigned(param1: CraneliftValue, param2: CraneliftValue, builder: &mut FunctionBuilder) -> CraneliftValue {
    builder.ins().urem(param1, param2)
}

fn less_signed(param1: CraneliftValue, param2: CraneliftValue, builder: &mut FunctionBuilder) -> CraneliftValue {
    builder.ins().icmp(IntCC::SignedLessThan, param1, param2)
}

fn less_unsigned(param1: CraneliftValue, param2: CraneliftValue, builder: &mut FunctionBuilder) -> CraneliftValue {
    builder.ins().icmp(IntCC::UnsignedLessThan, param1, param2)
}

fn less_float(param1: CraneliftValue, param2: CraneliftValue, builder: &mut FunctionBuilder) -> CraneliftValue {
    builder.ins().fcmp(FloatCC::LessThan, param1, param2)
}

fn eq_int(param1: CraneliftValue, param2: CraneliftValue, builder: &mut FunctionBuilder) -> CraneliftValue {
    builder.ins().icmp(IntCC::Equal, param1, param2)
}

fn eq_float(param1: CraneliftValue, param2: CraneliftValue, builder: &mut FunctionBuilder) -> CraneliftValue {
    builder.ins().fcmp(FloatCC::Equal, param1, param2)
}

fn eq_char(param1: CraneliftValue, param2: CraneliftValue, builder: &mut FunctionBuilder) -> CraneliftValue {
    builder.ins().icmp(IntCC::Equal, param1, param2)
}

fn eq_bool(param1: CraneliftValue, param2: CraneliftValue, builder: &mut FunctionBuilder) -> CraneliftValue {
    builder.ins().icmp(IntCC::Equal, param1, param2)
}

fn transmute(param1: CraneliftValue, builder: &mut FunctionBuilder) -> CraneliftValue {
    // TODO: struct types
    let target_type = builder.func.signature.returns[0].value_type;
    let start_type = builder.func.dfg.value_type(param1);

    if start_type != target_type {
        builder.ins().bitcast(target_type, param1)
    } else {
        param1
    }
}

fn offset(
    address: CraneliftValue, offset: CraneliftValue, elem_size: u32, builder: &mut FunctionBuilder,
) -> CraneliftValue {
    let usize_type = int_pointer_type();
    let pointer_type = pointer_type();

    let size = builder.ins().iconst(usize_type, elem_size as i64);
    let offset = builder.ins().imul(offset, size);

    if usize_type != pointer_type {
        let address = builder.ins().bitcast(usize_type, address);
        let new_address = builder.ins().iadd(address, offset);
        builder.ins().bitcast(pointer_type, new_address)
    } else {
        builder.ins().iadd(address, offset)
    }
}

// All integers are boxed as an i64, so this is a no-op in this backend
fn sign_extend(param1: CraneliftValue, builder: &mut FunctionBuilder) -> CraneliftValue {
    let target_type = builder.func.signature.returns[0].value_type;
    let start_type = builder.func.dfg.value_type(param1);
    assert!(start_type.bytes() <= target_type.bytes());

    if start_type.bytes() < target_type.bytes() {
        builder.ins().sextend(target_type, param1)
    } else {
        param1
    }
}

// All integers are boxed as an i64, so this is a no-op in this backend
fn zero_extend(param1: CraneliftValue, builder: &mut FunctionBuilder) -> CraneliftValue {
    let target_type = builder.func.signature.returns[0].value_type;
    let start_type = builder.func.dfg.value_type(param1);
    assert!(start_type.bytes() <= target_type.bytes());

    if start_type.bytes() < target_type.bytes() {
        builder.ins().uextend(target_type, param1)
    } else {
        param1
    }
}

fn signed_to_float(param1: CraneliftValue, builder: &mut FunctionBuilder) -> CraneliftValue {
    let target_type = builder.func.signature.returns[0].value_type;
    builder.ins().fcvt_from_sint(target_type, param1)
}

fn unsigned_to_float(param1: CraneliftValue, builder: &mut FunctionBuilder) -> CraneliftValue {
    let target_type = builder.func.signature.returns[0].value_type;
    builder.ins().fcvt_from_uint(target_type, param1)
}

fn float_to_signed(param1: CraneliftValue, builder: &mut FunctionBuilder) -> CraneliftValue {
    let target_type = builder.func.signature.returns[0].value_type;
    builder.ins().fcvt_to_sint(target_type, param1)
}

fn float_to_unsigned(param1: CraneliftValue, builder: &mut FunctionBuilder) -> CraneliftValue {
    let target_type = builder.func.signature.returns[0].value_type;
    builder.ins().fcvt_to_uint(target_type, param1)
}

fn truncate(param1: CraneliftValue, builder: &mut FunctionBuilder) -> CraneliftValue {
    let target_type = builder.func.signature.returns[0].value_type;
    let start_type = builder.func.dfg.value_type(param1);
    assert!(start_type.bytes() >= target_type.bytes());

    if start_type.bytes() > target_type.bytes() {
        builder.ins().ireduce(target_type, param1)
    } else {
        param1
    }
}

fn deref<'a>(context: &mut Context<'a>, typ: &crate::hir::Type, addr: &'a Ast, builder: &mut FunctionBuilder) -> Value {
    let addr = addr.eval_single(context, builder);
    context.load_value(typ, addr, &mut 0, builder)
}

fn stack_alloc<'a>(param1: &'a Ast, context: &mut Context<'a>, builder: &mut FunctionBuilder) -> CraneliftValue {
    let values = param1.eval_all(context, builder);

    let size = values.iter().map(|value| builder.func.dfg.value_type(*value).bytes()).sum();

    let data = StackSlotData::new(StackSlotKind::ExplicitSlot, size);
    let slot = builder.create_stack_slot(data);

    let mut offset: u32 = 0;
    for value in values {
        builder.ins().stack_store(value, slot, offset as i32);
        offset += builder.func.dfg.value_type(value).bytes();
    }

    builder.ins().stack_addr(pointer_type(), slot, 0)
}
<|endoftext|>


<commit_before>//! The file transport writes the emails to the given directory. The name of the file will be
//! `message_id.eml`.
//! It can be useful for testing purposes, or if you want to keep track of sent messages.
//!
//! ## Sync example
//!
//! ```rust
//! # use std::error::Error;
//!
//! # #[cfg(all(feature = "file-transport", feature = "builder"))]
//! # fn main() -> Result<(), Box<dyn Error>> {
//! use std::env::temp_dir;
//! use lettre::{Transport, Message, FileTransport};
//!
//! // Write to the local temp directory
//! let sender = FileTransport::new(temp_dir());
//! let email = Message::builder()
//!     .from("NoBody <nobody@domain.tld>".parse()?)
//!     .reply_to("Yuin <yuin@domain.tld>".parse()?)
//!     .to("Hei <hei@domain.tld>".parse()?)
//!     .subject("Happy new year")
//!     .body("Be happy!")?;
//!
//! let result = sender.send(&email);
//! assert!(result.is_ok());
//! # Ok(())
//! # }
//!
//! # #[cfg(not(all(feature = "file-transport", feature = "builder")))]
//! # fn main() {}
//! ```
//!
//!
//! ## Async tokio 0.2
//!
//! ```rust,no_run
//! # use std::error::Error;
//!
//! # #[cfg(all(feature = "tokio02", feature = "file-transport", feature = "builder"))]
//! # async fn run() -> Result<(), Box<dyn Error>> {
//! use std::env::temp_dir;
//! use lettre::{Tokio02Transport, Message, FileTransport};
//!
//! // Write to the local temp directory
//! let sender = FileTransport::new(temp_dir());
//! let email = Message::builder()
//!     .from("NoBody <nobody@domain.tld>".parse()?)
//!     .reply_to("Yuin <yuin@domain.tld>".parse()?)
//!     .to("Hei <hei@domain.tld>".parse()?)
//!     .subject("Happy new year")
//!     .body("Be happy!")?;
//!
//! let result = sender.send(email).await;
//! assert!(result.is_ok());
//! # Ok(())
//! # }
//! ```
//!
//! ## Async async-std 1.x
//!
//! ```rust,no_run
//! # use std::error::Error;
//!
//! # #[cfg(all(feature = "async-std1", feature = "file-transport", feature = "builder"))]
//! # async fn run() -> Result<(), Box<dyn Error>> {
//! use std::env::temp_dir;
//! use lettre::{AsyncStd1Transport, Message, FileTransport};
//!
//! // Write to the local temp directory
//! let sender = FileTransport::new(temp_dir());
//! let email = Message::builder()
//!     .from("NoBody <nobody@domain.tld>".parse()?)
//!     .reply_to("Yuin <yuin@domain.tld>".parse()?)
//!     .to("Hei <hei@domain.tld>".parse()?)
//!     .subject("Happy new year")
//!     .body("Be happy!")?;
//!
//! let result = sender.send(email).await;
//! assert!(result.is_ok());
//! # Ok(())
//! # }
//! ```
//!
//! ---
//!
//! Example result
//!
//! ```eml
//! From: NoBody <nobody@domain.tld>
//! Reply-To: Yuin <yuin@domain.tld>
//! To: Hei <hei@domain.tld>
//! Subject: Happy new year
//! Date: Tue, 18 Aug 2020 22:50:17 GMT
//!
//! Be happy!
//! ```

pub use self::error::Error;
use crate::address::Envelope;
#[cfg(feature = "async-std1")]
use crate::AsyncStd1Transport;
#[cfg(feature = "tokio02")]
use crate::Tokio02Transport;
#[cfg(feature = "tokio03")]
use crate::Tokio03Transport;
use crate::Transport;
#[cfg(any(feature = "async-std1", feature = "tokio02", feature = "tokio03"))]
use async_trait::async_trait;
use std::{
    path::{Path, PathBuf},
    str,
};
use uuid::Uuid;

mod error;

type Id = String;

/// Writes the content and the envelope information to a file
#[derive(Debug)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct FileTransport {
    path: PathBuf,
    #[cfg(feature = "file-transport-envelope")]
    save_envelope: bool,
}

impl FileTransport {
    /// Creates a new transport to the given directory
    ///
    /// Writes the email content in eml format.
    pub fn new<P: AsRef<Path>>(path: P) -> FileTransport {
        FileTransport {
            path: PathBuf::from(path.as_ref()),
            #[cfg(feature = "file-transport-envelope")]
            save_envelope: false,
        }
    }

    /// Creates a new transport to the given directory
    ///
    /// Writes the email content in eml format and the envelope
    /// in json format.
    #[cfg(feature = "file-transport-envelope")]
    pub fn with_envelope<P: AsRef<Path>>(path: P) -> FileTransport {
        FileTransport {
            path: PathBuf::from(path.as_ref()),
            #[cfg(feature = "file-transport-envelope")]
            save_envelope: true,
        }
    }

    fn path(&self, email_id: &Uuid, extension: &str) -> PathBuf {
        self.path.join(format!("{}.{}", email_id, extension))
    }
}

impl Transport for FileTransport {
    type Ok = Id;
    type Error = Error;

    fn send_raw(&self, envelope: &Envelope, email: &[u8]) -> Result<Self::Ok, Self::Error> {
        use std::fs;

        let email_id = Uuid::new_v4();

        let file = self.path(&email_id, "eml");
        fs::write(file, email)?;

        #[cfg(feature = "file-transport-envelope")]
        {
            if self.save_envelope {
                let file = self.path(&email_id, "json");
                fs::write(file, serde_json::to_string(&envelope)?)?;
            }
        }
        // use envelope anyway
        let _ = envelope;

        Ok(email_id.to_string())
    }
}

#[cfg(feature = "async-std1")]
#[async_trait]
impl AsyncStd1Transport for FileTransport {
    type Ok = Id;
    type Error = Error;

    async fn send_raw(&self, envelope: &Envelope, email: &[u8]) -> Result<Self::Ok, Self::Error> {
        use async_std::fs;

        let email_id = Uuid::new_v4();

        let file = self.path(&email_id, "eml");
        fs::write(file, email).await?;

        #[cfg(feature = "file-transport-envelope")]
        {
            if self.save_envelope {
                let file = self.path(&email_id, "json");
                fs::write(file, serde_json::to_string(&envelope)?).await?;
            }
        }
        // use envelope anyway
        let _ = envelope;

        Ok(email_id.to_string())
    }
}

#[cfg(feature = "tokio02")]
#[async_trait]
impl Tokio02Transport for FileTransport {
    type Ok = Id;
    type Error = Error;

    async fn send_raw(&self, envelope: &Envelope, email: &[u8]) -> Result<Self::Ok, Self::Error> {
        use tokio02_crate::fs;

        let email_id = Uuid::new_v4();
        let file = self.path(&email_id, "eml");
        fs::write(file, email).await?;

        #[cfg(feature = "file-transport-envelope")]
        {
            if self.save_envelope {
                let file = self.path(&email_id, "json");
                fs::write(file, serde_json::to_string(&envelope)?).await?;
            }
        }
        // use envelope anyway
        let _ = envelope;

        Ok(email_id.to_string())
    }
}

#[cfg(feature = "tokio03")]
#[async_trait]
impl Tokio03Transport for FileTransport {
    type Ok = Id;
    type Error = Error;

    async fn send_raw(&self, envelope: &Envelope, email: &[u8]) -> Result<Self::Ok, Self::Error> {
        use tokio03_crate::fs;

        let email_id = Uuid::new_v4();

        let file = self.path(&email_id, "eml");
        fs::write(file, email).await?;

        #[cfg(feature = "file-transport-envelope")]
        {
            if self.save_envelope {
                let file = self.path(&email_id, "json");
                fs::write(file, serde_json::to_string(&envelope)?).await?;
            }
        }
        // use envelope anyway
        let _ = envelope;

        Ok(email_id.to_string())
    }
}
<commit_msg>add docs<commit_after>//! The file transport writes the emails to the given directory. The name of the file will be
//! `message_id.eml`.
//! It can be useful for testing purposes, or if you want to keep track of sent messages.
//!
//! ## Sync example
//!
//! ```rust
//! # use std::error::Error;
//!
//! # #[cfg(all(feature = "file-transport", feature = "builder"))]
//! # fn main() -> Result<(), Box<dyn Error>> {
//! use std::env::temp_dir;
//! use lettre::{Transport, Message, FileTransport};
//!
//! // Write to the local temp directory
//! let sender = FileTransport::new(temp_dir());
//! let email = Message::builder()
//!     .from("NoBody <nobody@domain.tld>".parse()?)
//!     .reply_to("Yuin <yuin@domain.tld>".parse()?)
//!     .to("Hei <hei@domain.tld>".parse()?)
//!     .subject("Happy new year")
//!     .body("Be happy!")?;
//!
//! let result = sender.send(&email);
//! assert!(result.is_ok());
//! # Ok(())
//! # }
//!
//! # #[cfg(not(all(feature = "file-transport", feature = "builder")))]
//! # fn main() {}
//! ```
//!
//! ## Sync example with envelope
//!
//! It is possible to also write the envelope content in a separate JSON file
//! by using the `with_envelope` builder. The JSON file will be written in the
//! target directory with same name and a `json` extension.
//!
//! ```rust
//! # use std::error::Error;
//!
//! # #[cfg(all(feature = "file-transport", feature = "builder"))]
//! # fn main() -> Result<(), Box<dyn Error>> {
//! use std::env::temp_dir;
//! use lettre::{Transport, Message, FileTransport};
//!
//! // Write to the local temp directory
//! let sender = FileTransport::with_envelope(temp_dir());
//! let email = Message::builder()
//!     .from("NoBody <nobody@domain.tld>".parse()?)
//!     .reply_to("Yuin <yuin@domain.tld>".parse()?)
//!     .to("Hei <hei@domain.tld>".parse()?)
//!     .subject("Happy new year")
//!     .body("Be happy!")?;
//!
//! let result = sender.send(&email);
//! assert!(result.is_ok());
//! # Ok(())
//! # }
//!
//! # #[cfg(not(all(feature = "file-transport", feature = "builder")))]
//! # fn main() {}
//! ```
//!
//! ## Async tokio 0.2
//!
//! ```rust,no_run
//! # use std::error::Error;
//!
//! # #[cfg(all(feature = "tokio02", feature = "file-transport", feature = "builder"))]
//! # async fn run() -> Result<(), Box<dyn Error>> {
//! use std::env::temp_dir;
//! use lettre::{Tokio02Transport, Message, FileTransport};
//!
//! // Write to the local temp directory
//! let sender = FileTransport::new(temp_dir());
//! let email = Message::builder()
//!     .from("NoBody <nobody@domain.tld>".parse()?)
//!     .reply_to("Yuin <yuin@domain.tld>".parse()?)
//!     .to("Hei <hei@domain.tld>".parse()?)
//!     .subject("Happy new year")
//!     .body("Be happy!")?;
//!
//! let result = sender.send(email).await;
//! assert!(result.is_ok());
//! # Ok(())
//! # }
//! ```
//!
//! ## Async async-std 1.x
//!
//! ```rust,no_run
//! # use std::error::Error;
//!
//! # #[cfg(all(feature = "async-std1", feature = "file-transport", feature = "builder"))]
//! # async fn run() -> Result<(), Box<dyn Error>> {
//! use std::env::temp_dir;
//! use lettre::{AsyncStd1Transport, Message, FileTransport};
//!
//! // Write to the local temp directory
//! let sender = FileTransport::new(temp_dir());
//! let email = Message::builder()
//!     .from("NoBody <nobody@domain.tld>".parse()?)
//!     .reply_to("Yuin <yuin@domain.tld>".parse()?)
//!     .to("Hei <hei@domain.tld>".parse()?)
//!     .subject("Happy new year")
//!     .body("Be happy!")?;
//!
//! let result = sender.send(email).await;
//! assert!(result.is_ok());
//! # Ok(())
//! # }
//! ```
//!
//! ---
//!
//! Example email content result
//!
//! ```eml
//! From: NoBody <nobody@domain.tld>
//! Reply-To: Yuin <yuin@domain.tld>
//! To: Hei <hei@domain.tld>
//! Subject: Happy new year
//! Date: Tue, 18 Aug 2020 22:50:17 GMT
//!
//! Be happy!
//! ```
//!
//! Example envelope result
//!
//! ```json
//! {"forward_path":["hei@domain.tld"],"reverse_path":"nobody@domain.tld"}
//! ```

pub use self::error::Error;
use crate::address::Envelope;
#[cfg(feature = "async-std1")]
use crate::AsyncStd1Transport;
#[cfg(feature = "tokio02")]
use crate::Tokio02Transport;
#[cfg(feature = "tokio03")]
use crate::Tokio03Transport;
use crate::Transport;
#[cfg(any(feature = "async-std1", feature = "tokio02", feature = "tokio03"))]
use async_trait::async_trait;
use std::{
    path::{Path, PathBuf},
    str,
};
use uuid::Uuid;

mod error;

type Id = String;

/// Writes the content and the envelope information to a file
#[derive(Debug)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct FileTransport {
    path: PathBuf,
    #[cfg(feature = "file-transport-envelope")]
    save_envelope: bool,
}

impl FileTransport {
    /// Creates a new transport to the given directory
    ///
    /// Writes the email content in eml format.
    pub fn new<P: AsRef<Path>>(path: P) -> FileTransport {
        FileTransport {
            path: PathBuf::from(path.as_ref()),
            #[cfg(feature = "file-transport-envelope")]
            save_envelope: false,
        }
    }

    /// Creates a new transport to the given directory
    ///
    /// Writes the email content in eml format and the envelope
    /// in json format.
    #[cfg(feature = "file-transport-envelope")]
    pub fn with_envelope<P: AsRef<Path>>(path: P) -> FileTransport {
        FileTransport {
            path: PathBuf::from(path.as_ref()),
            #[cfg(feature = "file-transport-envelope")]
            save_envelope: true,
        }
    }

    fn path(&self, email_id: &Uuid, extension: &str) -> PathBuf {
        self.path.join(format!("{}.{}", email_id, extension))
    }
}

impl Transport for FileTransport {
    type Ok = Id;
    type Error = Error;

    fn send_raw(&self, envelope: &Envelope, email: &[u8]) -> Result<Self::Ok, Self::Error> {
        use std::fs;

        let email_id = Uuid::new_v4();

        let file = self.path(&email_id, "eml");
        fs::write(file, email)?;

        #[cfg(feature = "file-transport-envelope")]
        {
            if self.save_envelope {
                let file = self.path(&email_id, "json");
                fs::write(file, serde_json::to_string(&envelope)?)?;
            }
        }
        // use envelope anyway
        let _ = envelope;

        Ok(email_id.to_string())
    }
}

#[cfg(feature = "async-std1")]
#[async_trait]
impl AsyncStd1Transport for FileTransport {
    type Ok = Id;
    type Error = Error;

    async fn send_raw(&self, envelope: &Envelope, email: &[u8]) -> Result<Self::Ok, Self::Error> {
        use async_std::fs;

        let email_id = Uuid::new_v4();

        let file = self.path(&email_id, "eml");
        fs::write(file, email).await?;

        #[cfg(feature = "file-transport-envelope")]
        {
            if self.save_envelope {
                let file = self.path(&email_id, "json");
                fs::write(file, serde_json::to_string(&envelope)?).await?;
            }
        }
        // use envelope anyway
        let _ = envelope;

        Ok(email_id.to_string())
    }
}

#[cfg(feature = "tokio02")]
#[async_trait]
impl Tokio02Transport for FileTransport {
    type Ok = Id;
    type Error = Error;

    async fn send_raw(&self, envelope: &Envelope, email: &[u8]) -> Result<Self::Ok, Self::Error> {
        use tokio02_crate::fs;

        let email_id = Uuid::new_v4();
        let file = self.path(&email_id, "eml");
        fs::write(file, email).await?;

        #[cfg(feature = "file-transport-envelope")]
        {
            if self.save_envelope {
                let file = self.path(&email_id, "json");
                fs::write(file, serde_json::to_string(&envelope)?).await?;
            }
        }
        // use envelope anyway
        let _ = envelope;

        Ok(email_id.to_string())
    }
}

#[cfg(feature = "tokio03")]
#[async_trait]
impl Tokio03Transport for FileTransport {
    type Ok = Id;
    type Error = Error;

    async fn send_raw(&self, envelope: &Envelope, email: &[u8]) -> Result<Self::Ok, Self::Error> {
        use tokio03_crate::fs;

        let email_id = Uuid::new_v4();

        let file = self.path(&email_id, "eml");
        fs::write(file, email).await?;

        #[cfg(feature = "file-transport-envelope")]
        {
            if self.save_envelope {
                let file = self.path(&email_id, "json");
                fs::write(file, serde_json::to_string(&envelope)?).await?;
            }
        }
        // use envelope anyway
        let _ = envelope;

        Ok(email_id.to_string())
    }
}
<|endoftext|>


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

//! Misc low level stuff

#[allow(missing_doc)];

use option::{Some, None};
use cast;
use cmp::{Eq, Ord};
use gc;
use io;
use libc;
use libc::{c_void, c_char, size_t};
use repr;
use str;
use unstable::intrinsics;

pub type FreeGlue<'self> = &'self fn(*TypeDesc, *c_void);

// Corresponds to runtime type_desc type
pub struct TypeDesc {
    size: uint,
    align: uint,
    take_glue: uint,
    drop_glue: uint,
    free_glue: uint
    // Remaining fields not listed
}

/// The representation of a Rust closure
pub struct Closure {
    code: *(),
    env: *(),
}

pub mod rustrt {
    use libc::{c_char, size_t};

    pub extern {
        #[rust_stack]
        unsafe fn rust_upcall_fail(expr: *c_char,
                                   file: *c_char,
                                   line: size_t);
    }
}

/// Compares contents of two pointers using the default method.
/// Equivalent to `*x1 == *x2`.  Useful for hashtables.
pub fn shape_eq<T:Eq>(x1: &T, x2: &T) -> bool {
    *x1 == *x2
}

pub fn shape_lt<T:Ord>(x1: &T, x2: &T) -> bool {
    *x1 < *x2
}

pub fn shape_le<T:Ord>(x1: &T, x2: &T) -> bool {
    *x1 <= *x2
}

/**
 * Returns a pointer to a type descriptor.
 *
 * Useful for calling certain function in the Rust runtime or otherwise
 * performing dark magick.
 */
#[inline(always)]
pub fn get_type_desc<T>() -> *TypeDesc {
    unsafe { intrinsics::get_tydesc::<T>() as *TypeDesc }
}

/// Returns a pointer to a type descriptor.
#[inline(always)]
pub fn get_type_desc_val<T>(_val: &T) -> *TypeDesc {
    get_type_desc::<T>()
}

/// Returns the size of a type
#[inline(always)]
pub fn size_of<T>() -> uint {
    unsafe { intrinsics::size_of::<T>() }
}

/// Returns the size of the type that `_val` points to
#[inline(always)]
pub fn size_of_val<T>(_val: &T) -> uint {
    size_of::<T>()
}

/**
 * Returns the size of a type, or 1 if the actual size is zero.
 *
 * Useful for building structures containing variable-length arrays.
 */
#[inline(always)]
pub fn nonzero_size_of<T>() -> uint {
    let s = size_of::<T>();
    if s == 0 { 1 } else { s }
}

/// Returns the size of the type of the value that `_val` points to
#[inline(always)]
pub fn nonzero_size_of_val<T>(_val: &T) -> uint {
    nonzero_size_of::<T>()
}

/**
 * Returns the ABI-required minimum alignment of a type
 *
 * This is the alignment used for struct fields. It may be smaller
 * than the preferred alignment.
 */
#[inline(always)]
pub fn min_align_of<T>() -> uint {
    unsafe { intrinsics::min_align_of::<T>() }
}

/// Returns the ABI-required minimum alignment of the type of the value that
/// `_val` points to
#[inline(always)]
pub fn min_align_of_val<T>(_val: &T) -> uint {
    min_align_of::<T>()
}

/// Returns the preferred alignment of a type
#[inline(always)]
pub fn pref_align_of<T>() -> uint {
    unsafe { intrinsics::pref_align_of::<T>() }
}

/// Returns the preferred alignment of the type of the value that
/// `_val` points to
#[inline(always)]
pub fn pref_align_of_val<T>(_val: &T) -> uint {
    pref_align_of::<T>()
}

/// Returns the refcount of a shared box (as just before calling this)
#[inline(always)]
pub fn refcount<T>(t: @T) -> uint {
    unsafe {
        let ref_ptr: *uint = cast::transmute_copy(&t);
        *ref_ptr - 1
    }
}

pub fn log_str<T>(t: &T) -> ~str {
    do io::with_str_writer |wr| {
        repr::write_repr(wr, t)
    }
}

/// Trait for initiating task failure.
pub trait FailWithCause {
    /// Fail the current task, taking ownership of `cause`
    fn fail_with(cause: Self, file: &'static str, line: uint) -> !;
}

impl FailWithCause for ~str {
    fn fail_with(cause: ~str, file: &'static str, line: uint) -> ! {
        do str::as_buf(cause) |msg_buf, _msg_len| {
            do str::as_buf(file) |file_buf, _file_len| {
                unsafe {
                    let msg_buf = cast::transmute(msg_buf);
                    let file_buf = cast::transmute(file_buf);
                    begin_unwind_(msg_buf, file_buf, line as libc::size_t)
                }
            }
        }
    }
}

impl FailWithCause for &'static str {
    fn fail_with(cause: &'static str, file: &'static str, line: uint) -> ! {
        do str::as_buf(cause) |msg_buf, _msg_len| {
            do str::as_buf(file) |file_buf, _file_len| {
                unsafe {
                    let msg_buf = cast::transmute(msg_buf);
                    let file_buf = cast::transmute(file_buf);
                    begin_unwind_(msg_buf, file_buf, line as libc::size_t)
                }
            }
        }
    }
}

// FIXME #4427: Temporary until rt::rt_fail_ goes away
pub fn begin_unwind_(msg: *c_char, file: *c_char, line: size_t) -> ! {
    use option::Option;
    use rt::{context, OldTaskContext, TaskContext};
    use rt::task::{Task, Unwinder};
    use rt::local::Local;

    let context = context();
    match context {
        OldTaskContext => {
            unsafe {
                gc::cleanup_stack_for_failure();
                rustrt::rust_upcall_fail(msg, file, line);
                cast::transmute(())
            }
        }
        _ => {
            unsafe {
                // XXX: Bad re-allocations. fail! needs some refactoring
                let msg = str::raw::from_c_str(msg);
                let file = str::raw::from_c_str(file);

                let outmsg = fmt!("%s at line %i of file %s", msg, line as int, file);

                // XXX: Logging doesn't work correctly in non-task context because it
                // invokes the local heap
                if context == TaskContext {
                    error!(outmsg);
                } else {
                    rtdebug!("%s", outmsg);
                }

                gc::cleanup_stack_for_failure();

                let task = Local::unsafe_borrow::<Task>();
                let unwinder: &mut Option<Unwinder> = &mut (*task).unwinder;
                match *unwinder {
                    Some(ref mut unwinder) => unwinder.begin_unwind(),
                    None => abort!("failure without unwinder. aborting process")
                }
            }
        }
    }
}

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

    #[test]
    fn size_of_basic() {
        assert_eq!(size_of::<u8>(), 1u);
        assert_eq!(size_of::<u16>(), 2u);
        assert_eq!(size_of::<u32>(), 4u);
        assert_eq!(size_of::<u64>(), 8u);
    }

    #[test]
    #[cfg(target_arch = "x86")]
    #[cfg(target_arch = "arm")]
    #[cfg(target_arch = "mips")]
    fn size_of_32() {
        assert_eq!(size_of::<uint>(), 4u);
        assert_eq!(size_of::<*uint>(), 4u);
    }

    #[test]
    #[cfg(target_arch = "x86_64")]
    fn size_of_64() {
        assert_eq!(size_of::<uint>(), 8u);
        assert_eq!(size_of::<*uint>(), 8u);
    }

    #[test]
    fn size_of_val_basic() {
        assert_eq!(size_of_val(&1u8), 1);
        assert_eq!(size_of_val(&1u16), 2);
        assert_eq!(size_of_val(&1u32), 4);
        assert_eq!(size_of_val(&1u64), 8);
    }

    #[test]
    fn nonzero_size_of_basic() {
        type Z = [i8, ..0];
        assert_eq!(size_of::<Z>(), 0u);
        assert_eq!(nonzero_size_of::<Z>(), 1u);
        assert_eq!(nonzero_size_of::<uint>(), size_of::<uint>());
    }

    #[test]
    fn nonzero_size_of_val_basic() {
        let z = [0u8, ..0];
        assert_eq!(size_of_val(&z), 0u);
        assert_eq!(nonzero_size_of_val(&z), 1u);
        assert_eq!(nonzero_size_of_val(&1u), size_of_val(&1u));
    }

    #[test]
    fn align_of_basic() {
        assert_eq!(pref_align_of::<u8>(), 1u);
        assert_eq!(pref_align_of::<u16>(), 2u);
        assert_eq!(pref_align_of::<u32>(), 4u);
    }

    #[test]
    #[cfg(target_arch = "x86")]
    #[cfg(target_arch = "arm")]
    #[cfg(target_arch = "mips")]
    fn align_of_32() {
        assert_eq!(pref_align_of::<uint>(), 4u);
        assert_eq!(pref_align_of::<*uint>(), 4u);
    }

    #[test]
    #[cfg(target_arch = "x86_64")]
    fn align_of_64() {
        assert_eq!(pref_align_of::<uint>(), 8u);
        assert_eq!(pref_align_of::<*uint>(), 8u);
    }

    #[test]
    fn align_of_val_basic() {
        assert_eq!(pref_align_of_val(&1u8), 1u);
        assert_eq!(pref_align_of_val(&1u16), 2u);
        assert_eq!(pref_align_of_val(&1u32), 4u);
    }

    #[test]
    fn synthesize_closure() {
        unsafe {
            let x = 10;
            let f: &fn(int) -> int = |y| x + y;

            assert_eq!(f(20), 30);

            let original_closure: Closure = cast::transmute(f);

            let actual_function_pointer = original_closure.code;
            let environment = original_closure.env;

            let new_closure = Closure {
                code: actual_function_pointer,
                env: environment
            };

            let new_f: &fn(int) -> int = cast::transmute(new_closure);
            assert_eq!(new_f(20), 30);
        }
    }

    #[test]
    #[should_fail]
    fn fail_static() { FailWithCause::fail_with("cause", file!(), line!())  }

    #[test]
    #[should_fail]
    fn fail_owned() { FailWithCause::fail_with(~"cause", file!(), line!())  }
}
<commit_msg>auto merge of #6942 : thestinger/rust/cleanup, r=catamorphism<commit_after>// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Misc low level stuff

#[allow(missing_doc)];

use option::{Some, None};
use cast;
use cmp::{Eq, Ord};
use gc;
use io;
use libc;
use libc::{c_void, c_char, size_t};
use repr;
use str;
use unstable::intrinsics;

pub type FreeGlue<'self> = &'self fn(*TypeDesc, *c_void);

// Corresponds to runtime type_desc type
pub struct TypeDesc {
    size: uint,
    align: uint,
    take_glue: uint,
    drop_glue: uint,
    free_glue: uint
    // Remaining fields not listed
}

/// The representation of a Rust closure
pub struct Closure {
    code: *(),
    env: *(),
}

pub mod rustrt {
    use libc::{c_char, size_t};

    pub extern {
        #[rust_stack]
        unsafe fn rust_upcall_fail(expr: *c_char,
                                   file: *c_char,
                                   line: size_t);
    }
}

/**
 * Returns a pointer to a type descriptor.
 *
 * Useful for calling certain function in the Rust runtime or otherwise
 * performing dark magick.
 */
#[inline(always)]
pub fn get_type_desc<T>() -> *TypeDesc {
    unsafe { intrinsics::get_tydesc::<T>() as *TypeDesc }
}

/// Returns a pointer to a type descriptor.
#[inline(always)]
pub fn get_type_desc_val<T>(_val: &T) -> *TypeDesc {
    get_type_desc::<T>()
}

/// Returns the size of a type
#[inline(always)]
pub fn size_of<T>() -> uint {
    unsafe { intrinsics::size_of::<T>() }
}

/// Returns the size of the type that `_val` points to
#[inline(always)]
pub fn size_of_val<T>(_val: &T) -> uint {
    size_of::<T>()
}

/**
 * Returns the size of a type, or 1 if the actual size is zero.
 *
 * Useful for building structures containing variable-length arrays.
 */
#[inline(always)]
pub fn nonzero_size_of<T>() -> uint {
    let s = size_of::<T>();
    if s == 0 { 1 } else { s }
}

/// Returns the size of the type of the value that `_val` points to
#[inline(always)]
pub fn nonzero_size_of_val<T>(_val: &T) -> uint {
    nonzero_size_of::<T>()
}

/**
 * Returns the ABI-required minimum alignment of a type
 *
 * This is the alignment used for struct fields. It may be smaller
 * than the preferred alignment.
 */
#[inline(always)]
pub fn min_align_of<T>() -> uint {
    unsafe { intrinsics::min_align_of::<T>() }
}

/// Returns the ABI-required minimum alignment of the type of the value that
/// `_val` points to
#[inline(always)]
pub fn min_align_of_val<T>(_val: &T) -> uint {
    min_align_of::<T>()
}

/// Returns the preferred alignment of a type
#[inline(always)]
pub fn pref_align_of<T>() -> uint {
    unsafe { intrinsics::pref_align_of::<T>() }
}

/// Returns the preferred alignment of the type of the value that
/// `_val` points to
#[inline(always)]
pub fn pref_align_of_val<T>(_val: &T) -> uint {
    pref_align_of::<T>()
}

/// Returns the refcount of a shared box (as just before calling this)
#[inline(always)]
pub fn refcount<T>(t: @T) -> uint {
    unsafe {
        let ref_ptr: *uint = cast::transmute_copy(&t);
        *ref_ptr - 1
    }
}

pub fn log_str<T>(t: &T) -> ~str {
    do io::with_str_writer |wr| {
        repr::write_repr(wr, t)
    }
}

/// Trait for initiating task failure.
pub trait FailWithCause {
    /// Fail the current task, taking ownership of `cause`
    fn fail_with(cause: Self, file: &'static str, line: uint) -> !;
}

impl FailWithCause for ~str {
    fn fail_with(cause: ~str, file: &'static str, line: uint) -> ! {
        do str::as_buf(cause) |msg_buf, _msg_len| {
            do str::as_buf(file) |file_buf, _file_len| {
                unsafe {
                    let msg_buf = cast::transmute(msg_buf);
                    let file_buf = cast::transmute(file_buf);
                    begin_unwind_(msg_buf, file_buf, line as libc::size_t)
                }
            }
        }
    }
}

impl FailWithCause for &'static str {
    fn fail_with(cause: &'static str, file: &'static str, line: uint) -> ! {
        do str::as_buf(cause) |msg_buf, _msg_len| {
            do str::as_buf(file) |file_buf, _file_len| {
                unsafe {
                    let msg_buf = cast::transmute(msg_buf);
                    let file_buf = cast::transmute(file_buf);
                    begin_unwind_(msg_buf, file_buf, line as libc::size_t)
                }
            }
        }
    }
}

// FIXME #4427: Temporary until rt::rt_fail_ goes away
pub fn begin_unwind_(msg: *c_char, file: *c_char, line: size_t) -> ! {
    use option::Option;
    use rt::{context, OldTaskContext, TaskContext};
    use rt::task::{Task, Unwinder};
    use rt::local::Local;

    let context = context();
    match context {
        OldTaskContext => {
            unsafe {
                gc::cleanup_stack_for_failure();
                rustrt::rust_upcall_fail(msg, file, line);
                cast::transmute(())
            }
        }
        _ => {
            unsafe {
                // XXX: Bad re-allocations. fail! needs some refactoring
                let msg = str::raw::from_c_str(msg);
                let file = str::raw::from_c_str(file);

                let outmsg = fmt!("%s at line %i of file %s", msg, line as int, file);

                // XXX: Logging doesn't work correctly in non-task context because it
                // invokes the local heap
                if context == TaskContext {
                    error!(outmsg);
                } else {
                    rtdebug!("%s", outmsg);
                }

                gc::cleanup_stack_for_failure();

                let task = Local::unsafe_borrow::<Task>();
                let unwinder: &mut Option<Unwinder> = &mut (*task).unwinder;
                match *unwinder {
                    Some(ref mut unwinder) => unwinder.begin_unwind(),
                    None => abort!("failure without unwinder. aborting process")
                }
            }
        }
    }
}

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

    #[test]
    fn size_of_basic() {
        assert_eq!(size_of::<u8>(), 1u);
        assert_eq!(size_of::<u16>(), 2u);
        assert_eq!(size_of::<u32>(), 4u);
        assert_eq!(size_of::<u64>(), 8u);
    }

    #[test]
    #[cfg(target_arch = "x86")]
    #[cfg(target_arch = "arm")]
    #[cfg(target_arch = "mips")]
    fn size_of_32() {
        assert_eq!(size_of::<uint>(), 4u);
        assert_eq!(size_of::<*uint>(), 4u);
    }

    #[test]
    #[cfg(target_arch = "x86_64")]
    fn size_of_64() {
        assert_eq!(size_of::<uint>(), 8u);
        assert_eq!(size_of::<*uint>(), 8u);
    }

    #[test]
    fn size_of_val_basic() {
        assert_eq!(size_of_val(&1u8), 1);
        assert_eq!(size_of_val(&1u16), 2);
        assert_eq!(size_of_val(&1u32), 4);
        assert_eq!(size_of_val(&1u64), 8);
    }

    #[test]
    fn nonzero_size_of_basic() {
        type Z = [i8, ..0];
        assert_eq!(size_of::<Z>(), 0u);
        assert_eq!(nonzero_size_of::<Z>(), 1u);
        assert_eq!(nonzero_size_of::<uint>(), size_of::<uint>());
    }

    #[test]
    fn nonzero_size_of_val_basic() {
        let z = [0u8, ..0];
        assert_eq!(size_of_val(&z), 0u);
        assert_eq!(nonzero_size_of_val(&z), 1u);
        assert_eq!(nonzero_size_of_val(&1u), size_of_val(&1u));
    }

    #[test]
    fn align_of_basic() {
        assert_eq!(pref_align_of::<u8>(), 1u);
        assert_eq!(pref_align_of::<u16>(), 2u);
        assert_eq!(pref_align_of::<u32>(), 4u);
    }

    #[test]
    #[cfg(target_arch = "x86")]
    #[cfg(target_arch = "arm")]
    #[cfg(target_arch = "mips")]
    fn align_of_32() {
        assert_eq!(pref_align_of::<uint>(), 4u);
        assert_eq!(pref_align_of::<*uint>(), 4u);
    }

    #[test]
    #[cfg(target_arch = "x86_64")]
    fn align_of_64() {
        assert_eq!(pref_align_of::<uint>(), 8u);
        assert_eq!(pref_align_of::<*uint>(), 8u);
    }

    #[test]
    fn align_of_val_basic() {
        assert_eq!(pref_align_of_val(&1u8), 1u);
        assert_eq!(pref_align_of_val(&1u16), 2u);
        assert_eq!(pref_align_of_val(&1u32), 4u);
    }

    #[test]
    fn synthesize_closure() {
        unsafe {
            let x = 10;
            let f: &fn(int) -> int = |y| x + y;

            assert_eq!(f(20), 30);

            let original_closure: Closure = cast::transmute(f);

            let actual_function_pointer = original_closure.code;
            let environment = original_closure.env;

            let new_closure = Closure {
                code: actual_function_pointer,
                env: environment
            };

            let new_f: &fn(int) -> int = cast::transmute(new_closure);
            assert_eq!(new_f(20), 30);
        }
    }

    #[test]
    #[should_fail]
    fn fail_static() { FailWithCause::fail_with("cause", file!(), line!())  }

    #[test]
    #[should_fail]
    fn fail_owned() { FailWithCause::fail_with(~"cause", file!(), line!())  }
}
<|endoftext|>


<commit_before>use types::CBytes;
use IntoBytes;
use frame::*;

#[derive(Debug)]
pub struct BodyReqAuthResponse {
    data: CBytes,
}

impl BodyReqAuthResponse {
    pub fn new(data: CBytes) -> BodyReqAuthResponse {
        BodyReqAuthResponse { data: data }
    }
}

impl IntoBytes for BodyReqAuthResponse {
    fn into_cbytes(&self) -> Vec<u8> {
        self.data.into_cbytes()
    }
}

// Frame implementation related to BodyReqStartup

impl Frame {
    /// Creates new frame of type `AuthResponse`.
    pub fn new_req_auth_response(bytes: Vec<u8>) -> Frame {
        let version = Version::Request;
        let flag = Flag::Ignore;
        // sync client
        let stream: u64 = 0;
        let opcode = Opcode::AuthResponse;
        let body = BodyReqAuthResponse::new(CBytes::new(bytes));

        Frame {
            version: version,
            flags: vec![flag],
            stream: stream,
            opcode: opcode,
            body: body.into_cbytes(),
            // for request frames it's always None
            tracing_id: None,
            warnings: vec![],
        }
    }
}

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

    #[test]
    fn body_req_auth_response() {
        let few_bytes: Vec<u8> = vec![0, 0, 0, 10, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
        let  data = CBytes::new(few_bytes);
        let body = BodyReqAuthResponse::new(data);
        assert_eq!(body.data.into_plain(), vec![0, 0, 0, 10, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9]);
    }

    #[test]
    fn body_req_auth_frame() {
        let few_bytes: Vec<u8> = vec![0, 0, 0, 10, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
        let frame = Frame::new_req_auth_response(few_bytes);
        assert_eq!(frame.version,Version::Request);
        assert_eq!(frame.flags,vec![Flag::Ignore]);
        assert_eq!(frame.stream,0);
        assert_eq!(frame.opcode,Opcode::AuthResponse);
        assert_eq!(frame.tracing_id,None);
        //assert_eq!(frame.warnings,vec![]);
        assert_eq!(frame.body,vec![0, 0, 0, 14,0, 0, 0, 10, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9]);
    }
}

<commit_msg>formated with rustfmt<commit_after>use types::CBytes;
use IntoBytes;
use frame::*;

#[derive(Debug)]
pub struct BodyReqAuthResponse {
    data: CBytes,
}

impl BodyReqAuthResponse {
    pub fn new(data: CBytes) -> BodyReqAuthResponse {
        BodyReqAuthResponse { data: data }
    }
}

impl IntoBytes for BodyReqAuthResponse {
    fn into_cbytes(&self) -> Vec<u8> {
        self.data.into_cbytes()
    }
}

// Frame implementation related to BodyReqStartup

impl Frame {
    /// Creates new frame of type `AuthResponse`.
    pub fn new_req_auth_response(bytes: Vec<u8>) -> Frame {
        let version = Version::Request;
        let flag = Flag::Ignore;
        // sync client
        let stream: u64 = 0;
        let opcode = Opcode::AuthResponse;
        let body = BodyReqAuthResponse::new(CBytes::new(bytes));

        Frame {
            version: version,
            flags: vec![flag],
            stream: stream,
            opcode: opcode,
            body: body.into_cbytes(),
            // for request frames it's always None
            tracing_id: None,
            warnings: vec![],
        }
    }
}

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

    #[test]
    fn body_req_auth_response() {
        let few_bytes: Vec<u8> = vec![0, 0, 0, 10, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
        let data = CBytes::new(few_bytes);
        let body = BodyReqAuthResponse::new(data);
        assert_eq!(body.data.into_plain(),
                   vec![0, 0, 0, 10, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9]);
    }

    #[test]
    fn body_req_auth_frame() {
        let few_bytes: Vec<u8> = vec![0, 0, 0, 10, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
        let frame = Frame::new_req_auth_response(few_bytes);
        assert_eq!(frame.version, Version::Request);
        assert_eq!(frame.flags, vec![Flag::Ignore]);
        assert_eq!(frame.stream, 0);
        assert_eq!(frame.opcode, Opcode::AuthResponse);
        assert_eq!(frame.tracing_id, None);
        //assert_eq!(frame.warnings,vec![]);
        assert_eq!(frame.body,
                   vec![0, 0, 0, 14, 0, 0, 0, 10, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9]);
    }
}
<|endoftext|>


<commit_before>use crate::text::{Attributes, Text};
use crate::widgets::{Widget, WidgetStream};
use anyhow::Result;
use byte_unit::{Byte, ByteUnit};
use nix::sys::statvfs::statvfs;
use std::time::Duration;
use tokio::time;
use tokio_stream::wrappers::IntervalStream;
use tokio_stream::StreamExt;

#[derive(Debug)]
pub struct DiskInfo {
    pub total: Byte,
    pub used: Byte,
    pub free: Byte,
}

impl DiskInfo {
    pub fn new(path: &str) -> Result<Self> {
        let stat = statvfs(path)?;
        let total_size = stat.blocks() * stat.fragment_size();
        let used = (stat.blocks() - stat.blocks_free()) * stat.fragment_size();
        let available = stat.blocks_available() * stat.fragment_size();
        let total = byte_unit::Byte::from_bytes(total_size as u128);
        let used = byte_unit::Byte::from_bytes(used as u128);
        let free: Byte = byte_unit::Byte::from_bytes(available as u128);

        let disk_info = DiskInfo {
            total: total,
            used: used,
            free: free,
        };
        Ok(disk_info)
    }
}

pub struct DiskUsage {
    attr: Attributes,
    path: String,
    render: Option<Box<dyn Fn(DiskInfo) -> String>>,
}

impl DiskUsage {
    pub fn new(
        attr: Attributes,
        path: String,
        render: Option<Box<dyn Fn(DiskInfo) -> String>>,
    ) -> Self {
        Self { attr, render, path }
    }

    fn tick(&self) -> Result<Vec<Text>> {
        let disk_info = DiskInfo::new(self.path.as_ref())?;
        let disk_default_str = format!(
            "Disk: {}/{}",
            disk_info.used.get_adjusted_unit(ByteUnit::GiB).format(0),
            disk_info.total.get_adjusted_unit(ByteUnit::GiB).format(0)
        );

        let text: String = self
            .render
            .as_ref()
            .map_or(disk_default_str, |disk| (disk)(disk_info));
        let texts = vec![Text {
            attr: self.attr.clone(),
            text,
            stretch: false,
            markup: true,
        }];
        Ok(texts)
    }
}

impl Widget for DiskUsage {
    fn into_stream(self: Box<Self>) -> Result<WidgetStream> {
        let one_hour = Duration::from_secs(3600);
        let interval = time::interval(one_hour);
        let stream = IntervalStream::new(interval).map(move |_| self.tick());

        Ok(Box::pin(stream))
    }
}
<commit_msg>Fix CI issues<commit_after>use crate::text::{Attributes, Text};
use crate::widgets::{Widget, WidgetStream};
use anyhow::Result;
use byte_unit::{Byte, ByteUnit};
use nix::sys::statvfs::statvfs;
use std::time::Duration;
use tokio::time;
use tokio_stream::wrappers::IntervalStream;
use tokio_stream::StreamExt;

#[derive(Debug)]
pub struct DiskInfo {
    pub total: Byte,
    pub used: Byte,
    pub free: Byte,
}

impl DiskInfo {
    pub fn new(path: &str) -> Result<Self> {
        let stat = statvfs(path)?;
        let total_size = stat.blocks() * stat.fragment_size();
        let used = (stat.blocks() - stat.blocks_free()) * stat.fragment_size();
        let available = stat.blocks_available() * stat.fragment_size();
        let total = byte_unit::Byte::from_bytes(total_size as u128);
        let used = byte_unit::Byte::from_bytes(used as u128);
        let free: Byte = byte_unit::Byte::from_bytes(available as u128);

        let disk_info = DiskInfo { total, used, free };
        Ok(disk_info)
    }
}

pub struct DiskUsage {
    attr: Attributes,
    path: String,
    render: Option<Box<dyn Fn(DiskInfo) -> String>>,
}

impl DiskUsage {
    pub fn new(
        attr: Attributes,
        path: String,
        render: Option<Box<dyn Fn(DiskInfo) -> String>>,
    ) -> Self {
        Self { attr, render, path }
    }

    fn tick(&self) -> Result<Vec<Text>> {
        let disk_info = DiskInfo::new(self.path.as_ref())?;
        let disk_default_str = format!(
            "Disk: {}/{}",
            disk_info.used.get_adjusted_unit(ByteUnit::GiB).format(0),
            disk_info.total.get_adjusted_unit(ByteUnit::GiB).format(0)
        );

        let text: String = self
            .render
            .as_ref()
            .map_or(disk_default_str, |disk| (disk)(disk_info));
        let texts = vec![Text {
            attr: self.attr.clone(),
            text,
            stretch: false,
            markup: true,
        }];
        Ok(texts)
    }
}

impl Widget for DiskUsage {
    fn into_stream(self: Box<Self>) -> Result<WidgetStream> {
        let one_hour = Duration::from_secs(3600);
        let interval = time::interval(one_hour);
        let stream = IntervalStream::new(interval).map(move |_| self.tick());

        Ok(Box::pin(stream))
    }
}
<|endoftext|>


<commit_before>use std::f32;
use std::num::{FloatMath, Float};

pub mod vector;
pub mod normal;
pub mod point;
pub mod ray;
pub mod matrix4;
pub mod transform;

/// Compute the cross product of two vectors
pub fn cross<A: Index<uint, f32>, B: Index<uint, f32>>(a: &A, b: &B) -> vector::Vector {
    vector::Vector::new(a[1] * b[2] - a[2] * b[1], a[2] * b[0] - a[0] * b[2],
                a[0] * b[1] - a[1] * b[0])
}
/// Compute the dot product of two vectors
pub fn dot<A: Index<uint, f32>, B: Index<uint, f32>>(a: &A, b: &B) -> f32 {
    a[0] * b[0] + a[1] * b[1] + a[2] * b[2]
}
/*
 * TODO: I don't quite understand the error here
/// Lerp between `a` and `b` at some distance `t`
pub fn lerp<T: Mul<f32, T> + Add<T, T>>(t: f32, a: &T, b: &T) -> T {
    *a * (1f32 - t) + *b * t
}
*/
/// Clamp `x` to be between `min` and `max`
pub fn clamp<T: PartialOrd>(x: T, min: T, max: T) -> T {
    if x < min { min } else if x > max { max } else { x }
}
/// Convert `d` in degrees to radians
pub fn radians(d: f32) -> f32 {
    f32::consts::PI / 180f32 * d
}
/// Convert `r` in radians to degrees
pub fn degrees(r: f32) -> f32 {
    180f32 / f32::consts::PI * r
}
/// Compute the direction specified by `theta` and `phi` in the spherical coordinate system
pub fn spherical_dir(sin_theta: f32, cos_theta: f32, phi: f32) -> vector::Vector {
    vector::Vector::new(sin_theta * FloatMath::cos(phi), sin_theta * FloatMath::sin(phi),
                cos_theta)
}
/// Compute the value of theta for the vector in the spherical coordinate system
pub fn spherical_theta(v: &vector::Vector) -> f32 {
    FloatMath::acos(clamp(v.z, -1f32, 1f32))
}
/// Compute the value of phi for the vector in the spherical coordinate system
pub fn spherical_phi(v: &vector::Vector) -> f32 {
    match FloatMath::atan2(v.y, v.x) {
        x if x < 0f32 => x + f32::consts::PI_2,
        x             => x,
    }
}
/// Try to solve the quadratic equation `a*t^2 + b*t + c = 0` and return the two
/// real roots if a solution exists
pub fn solve_quadratic(a: f32, b: f32, c: f32) -> Option<(f32, f32)> {
    let discrim = Float::sqrt(b * b - 4f32 * a * c);
    if Float::is_nan(discrim) {
        None
    } else {
        let q = if b < 0f32 { -0.5f32 * (b - discrim) } else { -0.5f32 * (b + discrim) };
        match (q / a, c / q) {
            (x, y) if x > y => Some((y, x)),
            (x, y)          => Some((x, y)),
        }
    }
}

<commit_msg>Add tests for dot and cross<commit_after>use std::f32;
use std::num::{FloatMath, Float};

pub mod vector;
pub mod normal;
pub mod point;
pub mod ray;
pub mod matrix4;
pub mod transform;

/// Compute the cross product of two vectors
pub fn cross<A: Index<uint, f32>, B: Index<uint, f32>>(a: &A, b: &B) -> vector::Vector {
    vector::Vector::new(a[1] * b[2] - a[2] * b[1], a[2] * b[0] - a[0] * b[2],
                a[0] * b[1] - a[1] * b[0])
}
/// Compute the dot product of two vectors
pub fn dot<A: Index<uint, f32>, B: Index<uint, f32>>(a: &A, b: &B) -> f32 {
    a[0] * b[0] + a[1] * b[1] + a[2] * b[2]
}
/*
 * TODO: I don't quite understand the error here
/// Lerp between `a` and `b` at some distance `t`
pub fn lerp<T: Mul<f32, T> + Add<T, T>>(t: f32, a: &T, b: &T) -> T {
    *a * (1f32 - t) + *b * t
}
*/
/// Clamp `x` to be between `min` and `max`
pub fn clamp<T: PartialOrd>(x: T, min: T, max: T) -> T {
    if x < min { min } else if x > max { max } else { x }
}
/// Convert `d` in degrees to radians
pub fn radians(d: f32) -> f32 {
    f32::consts::PI / 180f32 * d
}
/// Convert `r` in radians to degrees
pub fn degrees(r: f32) -> f32 {
    180f32 / f32::consts::PI * r
}
/// Compute the direction specified by `theta` and `phi` in the spherical coordinate system
pub fn spherical_dir(sin_theta: f32, cos_theta: f32, phi: f32) -> vector::Vector {
    vector::Vector::new(sin_theta * FloatMath::cos(phi), sin_theta * FloatMath::sin(phi),
                cos_theta)
}
/// Compute the value of theta for the vector in the spherical coordinate system
pub fn spherical_theta(v: &vector::Vector) -> f32 {
    FloatMath::acos(clamp(v.z, -1f32, 1f32))
}
/// Compute the value of phi for the vector in the spherical coordinate system
pub fn spherical_phi(v: &vector::Vector) -> f32 {
    match FloatMath::atan2(v.y, v.x) {
        x if x < 0f32 => x + f32::consts::PI_2,
        x             => x,
    }
}
/// Try to solve the quadratic equation `a*t^2 + b*t + c = 0` and return the two
/// real roots if a solution exists
pub fn solve_quadratic(a: f32, b: f32, c: f32) -> Option<(f32, f32)> {
    let discrim = Float::sqrt(b * b - 4f32 * a * c);
    if Float::is_nan(discrim) {
        None
    } else {
        let q = if b < 0f32 { -0.5f32 * (b - discrim) } else { -0.5f32 * (b + discrim) };
        match (q / a, c / q) {
            (x, y) if x > y => Some((y, x)),
            (x, y)          => Some((x, y)),
        }
    }
}

#[test]
fn test_cross() {
    let a = vector::Vector::new(1f32, 0f32, 0f32);
    let b = vector::Vector::new(0f32, 1f32, 0f32);
    let c = cross(&a, &b);
    assert!(c == vector::Vector::new(0f32, 0f32, 1f32));
}

#[test]
fn test_dot() {
    let a = vector::Vector::new(1f32, 2f32, 3f32);
    let b = vector::Vector::new(4f32, 5f32, 6f32);
    assert!(dot(&a, &b) == 1f32 * 4f32 + 2f32 * 5f32 + 3f32 * 6f32);
}

<|endoftext|>


<commit_before>use std::f32;
use std::num::{FloatMath, Float};

pub mod vector;
pub mod normal;
pub mod point;
pub mod ray;
pub mod matrix4;
pub mod transform;

/// Compute the cross product of two vectors
pub fn cross<A: Index<uint, f32>, B: Index<uint, f32>>(a: &A, b: &B) -> vector::Vector {
    vector::Vector::new(a[1] * b[2] - a[2] * b[1], a[2] * b[0] - a[0] * b[2],
                a[0] * b[1] - a[1] * b[0])
}
/// Compute the dot product of two vectors
pub fn dot<A: Index<uint, f32>, B: Index<uint, f32>>(a: &A, b: &B) -> f32 {
    a[0] * b[0] + a[1] * b[1] + a[2] * b[2]
}
/*
 * TODO: I don't quite understand the error here
/// Lerp between `a` and `b` at some distance `t`
pub fn lerp<T: Mul<f32, T> + Add<T, T>>(t: f32, a: &T, b: &T) -> T {
    *a * (1f32 - t) + *b * t
}
*/
/// Clamp `x` to be between `min` and `max`
pub fn clamp<T: PartialOrd>(x: T, min: T, max: T) -> T {
    if x < min { min } else if x > max { max } else { x }
}
/// Convert `d` in degrees to radians
pub fn radians(d: f32) -> f32 {
    f32::consts::PI / 180f32 * d
}
/// Convert `r` in radians to degrees
pub fn degrees(r: f32) -> f32 {
    180f32 / f32::consts::PI * r
}
/// Compute the direction specified by `theta` and `phi` in the spherical coordinate system
pub fn spherical_dir(sin_theta: f32, cos_theta: f32, phi: f32) -> vector::Vector {
    vector::Vector::new(sin_theta * FloatMath::cos(phi), sin_theta * FloatMath::sin(phi),
                cos_theta)
}
/// Compute the value of theta for the vector in the spherical coordinate system
pub fn spherical_theta(v: &vector::Vector) -> f32 {
    FloatMath::acos(clamp(v.z, -1f32, 1f32))
}
/// Compute the value of phi for the vector in the spherical coordinate system
pub fn spherical_phi(v: &vector::Vector) -> f32 {
    match FloatMath::atan2(v.y, v.x) {
        x if x < 0f32 => x + f32::consts::PI_2,
        x             => x,
    }
}
/// Try to solve the quadratic equation `a*t^2 + b*t + c = 0` and return the two
/// real roots if a solution exists
pub fn solve_quadratic(a: f32, b: f32, c: f32) -> Option<(f32, f32)> {
    let discrim = Float::sqrt(b * b - 4f32 * a * c);
    if Float::is_nan(discrim) {
        None
    } else {
        let q = if b < 0f32 { -0.5f32 * (b - discrim) } else { -0.5f32 * (b + discrim) };
        match (q / a, c / q) {
            (x, y) if x > y => Some((y, x)),
            (x, y)          => Some((x, y)),
        }
    }
}

#[test]
fn test_cross() {
    let a = vector::Vector::new(1f32, 0f32, 0f32);
    let b = vector::Vector::new(0f32, 1f32, 0f32);
    let c = cross(&a, &b);
    assert!(c == vector::Vector::new(0f32, 0f32, 1f32));
}

#[test]
fn test_dot() {
    let a = vector::Vector::new(1f32, 2f32, 3f32);
    let b = vector::Vector::new(4f32, 5f32, 6f32);
    assert!(dot(&a, &b) == 1f32 * 4f32 + 2f32 * 5f32 + 3f32 * 6f32);
}

<commit_msg>For lerp we just need that the type can be copied to return the result<commit_after>use std::f32;
use std::num::{FloatMath, Float};

pub mod vector;
pub mod normal;
pub mod point;
pub mod ray;
pub mod matrix4;
pub mod transform;

/// Compute the cross product of two vectors
pub fn cross<A: Index<uint, f32>, B: Index<uint, f32>>(a: &A, b: &B) -> vector::Vector {
    vector::Vector::new(a[1] * b[2] - a[2] * b[1], a[2] * b[0] - a[0] * b[2],
                a[0] * b[1] - a[1] * b[0])
}
/// Compute the dot product of two vectors
pub fn dot<A: Index<uint, f32>, B: Index<uint, f32>>(a: &A, b: &B) -> f32 {
    a[0] * b[0] + a[1] * b[1] + a[2] * b[2]
}
/// Lerp between `a` and `b` at some distance `t` where t is in [0, 1]
/// and t = 0 returns `a` and t = 1 returns `b`
pub fn lerp<T: Mul<f32, T> + Add<T, T> + Copy<T>>(t: f32, a: &T, b: &T) -> T {
    *a * (1f32 - t) + *b * t
}
/// Clamp `x` to be between `min` and `max`
pub fn clamp<T: PartialOrd>(x: T, min: T, max: T) -> T {
    if x < min { min } else if x > max { max } else { x }
}
/// Convert `d` in degrees to radians
pub fn radians(d: f32) -> f32 {
    f32::consts::PI / 180f32 * d
}
/// Convert `r` in radians to degrees
pub fn degrees(r: f32) -> f32 {
    180f32 / f32::consts::PI * r
}
/// Compute the direction specified by `theta` and `phi` in the spherical coordinate system
pub fn spherical_dir(sin_theta: f32, cos_theta: f32, phi: f32) -> vector::Vector {
    vector::Vector::new(sin_theta * FloatMath::cos(phi), sin_theta * FloatMath::sin(phi),
                cos_theta)
}
/// Compute the value of theta for the vector in the spherical coordinate system
pub fn spherical_theta(v: &vector::Vector) -> f32 {
    FloatMath::acos(clamp(v.z, -1f32, 1f32))
}
/// Compute the value of phi for the vector in the spherical coordinate system
pub fn spherical_phi(v: &vector::Vector) -> f32 {
    match FloatMath::atan2(v.y, v.x) {
        x if x < 0f32 => x + f32::consts::PI_2,
        x             => x,
    }
}
/// Try to solve the quadratic equation `a*t^2 + b*t + c = 0` and return the two
/// real roots if a solution exists
pub fn solve_quadratic(a: f32, b: f32, c: f32) -> Option<(f32, f32)> {
    let discrim = Float::sqrt(b * b - 4f32 * a * c);
    if Float::is_nan(discrim) {
        None
    } else {
        let q = if b < 0f32 { -0.5f32 * (b - discrim) } else { -0.5f32 * (b + discrim) };
        match (q / a, c / q) {
            (x, y) if x > y => Some((y, x)),
            (x, y)          => Some((x, y)),
        }
    }
}

#[test]
fn test_cross() {
    let a = vector::Vector::new(1f32, 0f32, 0f32);
    let b = vector::Vector::new(0f32, 1f32, 0f32);
    let c = cross(&a, &b);
    assert!(c == vector::Vector::new(0f32, 0f32, 1f32));
}

#[test]
fn test_dot() {
    let a = vector::Vector::new(1f32, 2f32, 3f32);
    let b = vector::Vector::new(4f32, 5f32, 6f32);
    assert!(dot(&a, &b) == 1f32 * 4f32 + 2f32 * 5f32 + 3f32 * 6f32);
}

<|endoftext|>