<commit_before>#![feature(no_panic_pow)]
#![feature(test)]

extern crate test;

use codegen::{Const, Enum, Function, Struct, Scope, Impl};
use can_dbc::{DBC, ByteOrder, Message, MessageId, Signal, ValueDescription};
use std::fmt::Write;
use heck::{CamelCase, ShoutySnakeCase};

#[cfg(test)]
mod tests {
    use test::{Bencher, black_box};
    use byteorder;
    use byteorder::{ByteOrder, LE};

    #[bench]
    fn bench_read_signal(b: &mut Bencher) {
        const byte_payload: &[u8] = &[0x4, 0x2, 0xA, 0xA, 0xF, 0xF, 0xE, 0xE, 0xD, 0xD, 0xA, 0xA, 0xF, 0xF, 0xD, 0xD];

        b.iter(|| {
            let frame_payload: u64 = LE::read_u64(byte_payload);
            let bit_msk_const = 2u64.saturating_pow(8 as u32) - 1;
            let factor: f64 = test::black_box(2.0);
            let start_bit: u64 = test::black_box(8);
            let offset: f64 = test::black_box(10.0);

            (((frame_payload >> start_bit) & bit_msk_const) as f64) * factor + offset
        });
    }
}

type Result<T> = std::result::Result<T, std::fmt::Error>;

fn to_enum_name(message_id: &MessageId, signal_name: &str) -> String {
     format!("{}{}", &signal_name.to_camel_case(), message_id.0)
}

pub fn signal_enum(val_desc: &ValueDescription) -> Option<Enum> {
    if let ValueDescription::Signal{ ref message_id, ref signal_name, ref value_descriptions } = val_desc {

        let mut sig_enum = Enum::new(&to_enum_name(message_id, signal_name));
        sig_enum.allow("dead_code");
        sig_enum.vis("pub");
        sig_enum.repr("u64");
        sig_enum.derive("Debug");
        sig_enum.derive("Clone");
        sig_enum.derive("Copy");
        sig_enum.derive("PartialEq");
        sig_enum.derive("Eq");
        for desc in value_descriptions {
            sig_enum.new_variant(&desc.b().to_camel_case());
        }
        sig_enum.new_variant("XValue(u64)");
        return Some(sig_enum);
    }
    None
}

pub fn signal_enum_impl(val_desc: &ValueDescription) -> Option<Impl> {
    if let ValueDescription::Signal{ ref message_id, ref signal_name, ref value_descriptions } = val_desc {
        let enum_name = to_enum_name(message_id, signal_name);
        let mut enum_impl = Impl::new(codegen::Type::new(&enum_name));
        enum_impl.impl_trait("From<u64>");

        let from_fn = enum_impl.new_fn("from");
        from_fn.allow("dead_code");
        from_fn.arg("val", codegen::Type::new("u64"));

        let mut matching = String::new();
        write!(&mut matching, "match val {{\n").unwrap();
        for value_description in value_descriptions {
            write!(&mut matching, "    {} => {}::{},\n", value_description.a(), enum_name, value_description.b().to_camel_case()).unwrap();
        }
        write!(&mut matching, "    value => {}::XValue(value),\n", enum_name).unwrap();
        write!(&mut matching, "}}").unwrap();

        from_fn.line(matching);
        from_fn.ret(codegen::Type::new("Self"));

        return Some(enum_impl);
    }
    None
}

pub fn signal_fn(dbc: &DBC, signal: &Signal, message_id: &MessageId) -> Result<Function> {
    let mut signal_fn = codegen::Function::new(&signal.name().to_lowercase());
    signal_fn.allow("dead_code");
    signal_fn.vis("pub");
    signal_fn.arg_ref_self();

    // Attempt to find a matching enum return type, default to `f64` otherwise
    let ret_enum_type = dbc.value_descriptions_for_signal(message_id, signal.name()).map(|_| codegen::Type::new(&to_enum_name(message_id, signal.name())));
    signal_fn.ret(ret_enum_type.clone().unwrap_or_else(|| codegen::Type::new("f64")));

    let default_signal_comment = format!("Read {} signal from can frame", signal.name());
    let signal_comment = dbc.signal_comment(message_id, signal.name()).unwrap_or(&default_signal_comment);
    signal_fn.doc(signal_comment);

    let read_byte_order = match signal.byte_order() {
        ByteOrder::LittleEndian => "let frame_payload: u64 = LE::read_u64(self.frame_payload);",
        ByteOrder::BigEndian => "let  frame_payload: u64 = BE::read_u64(self.frame_payload);",
    };
    signal_fn.line(read_byte_order);

    let bit_msk_const = 2u64.saturating_pow(*signal.signal_size() as u32) - 1;
    let mut calc = String::new();

    if ret_enum_type.is_some() {
       write!(&mut calc, "{}::from((", to_enum_name(message_id, signal.name()))?; // TODO to_valid_upper_case called multiple times
    }

    // No shift required if start_bit == 0
    let shift = if *signal.start_bit() != 0 {
        format!("(frame_payload >> {})", signal.start_bit())
    } else {
        format!("frame_payload")
    };

    write!(&mut calc, "({} & {:#X}) as f64", shift, bit_msk_const)?;

    if *signal.factor() != 1.0 {
        write!(&mut calc, " * {:.6}", signal.factor())?;
    }

    if *signal.offset() != 0.0 {
        write!(&mut calc, " + {}f64", signal.offset())?;
    }

    if ret_enum_type.is_some() {
        write!(&mut calc, ") as u64)")?;
    }

    signal_fn.line(calc);
    Ok(signal_fn)
}

fn message_const(message: &Message) -> Const {
    let const_name = format!("MESSAGE_ID_{}", message.message_name().to_shouty_snake_case());
    let mut c = Const::new(&const_name, codegen::Type::new("u32"), message.message_id().0.to_string());
    c.allow("dead_code");
    c.vis("pub");
    c
}

fn message_struct(dbc: &DBC, message: &Message) -> Struct {
    let mut message_struct = Struct::new(&message.message_name().to_camel_case());
    if let Some(message_comment) = dbc.message_comment(message.message_id()) {
        message_struct.doc(message_comment);
    }
    message_struct.allow("dead_code");
    message_struct.derive("Debug");
    message_struct.vis("pub");
    message_struct.generic("'a");
    message_struct.field("frame_payload", "&'a[u8]");
    message_struct
}

fn message_impl(dbc: &DBC, message: &Message) -> Result<Impl> {

    let mut msg_impl = Impl::new(codegen::Type::new(&message.message_name().to_camel_case()));
    msg_impl.generic("'a");
    msg_impl.target_generic("'a");
    let new_fn = msg_impl.new_fn("new");
    new_fn.allow("dead_code");
    new_fn.vis("pub");
    new_fn.arg("frame_payload", codegen::Type::new("&[u8]"));

    new_fn.line(format!("{} {{ frame_payload }}", message.message_name().to_camel_case()));
    new_fn.ret(codegen::Type::new(&message.message_name().to_camel_case()));

    for signal in message.signals() {
        msg_impl.push_fn(signal_fn(dbc, signal, message.message_id())?);
    }

    Ok(msg_impl)
}

pub fn can_reader(dbc: &DBC) -> Result<Scope> {

    let mut scope = Scope::new();
    scope.import("byteorder", "{ByteOrder, LE, BE}");

    for message in dbc.messages() {
        scope.push_const(message_const(message));
    }

    for value_description in dbc.value_descriptions() {
        if let Some(signal_enum) = signal_enum(value_description) {
            scope.push_enum(signal_enum);
        }

        if let Some(enum_impl) = signal_enum_impl(value_description) {
            scope.push_impl(enum_impl);
        }
    }

    for message in dbc.messages() {
        scope.push_struct(message_struct(&dbc, message));
        scope.push_impl(message_impl(&dbc, message)?);
    }

    Ok(scope)
}<commit_msg>Fix big endian byteorder shifting<commit_after>#![feature(no_panic_pow)]
#![feature(test)]

extern crate test;

use codegen::{Const, Enum, Function, Struct, Scope, Impl};
use can_dbc::{DBC, ByteOrder, Message, MessageId, Signal, ValueDescription};
use std::fmt::Write;
use heck::{CamelCase, ShoutySnakeCase};

#[cfg(test)]
mod tests {
    use test::{Bencher, black_box};
    use byteorder;
    use byteorder::{ByteOrder, LE};

    #[bench]
    fn bench_read_signal(b: &mut Bencher) {
        const byte_payload: &[u8] = &[0x4, 0x2, 0xA, 0xA, 0xF, 0xF, 0xE, 0xE, 0xD, 0xD, 0xA, 0xA, 0xF, 0xF, 0xD, 0xD];

        b.iter(|| {
            let frame_payload: u64 = LE::read_u64(byte_payload);
            let bit_msk_const = 2u64.saturating_pow(8 as u32) - 1;
            let factor: f64 = test::black_box(2.0);
            let start_bit: u64 = test::black_box(8);
            let offset: f64 = test::black_box(10.0);

            (((frame_payload >> start_bit) & bit_msk_const) as f64) * factor + offset
        });
    }
}

type Result<T> = std::result::Result<T, std::fmt::Error>;

fn to_enum_name(message_id: &MessageId, signal_name: &str) -> String {
     format!("{}{}", &signal_name.to_camel_case(), message_id.0)
}

pub fn signal_enum(val_desc: &ValueDescription) -> Option<Enum> {
    if let ValueDescription::Signal{ ref message_id, ref signal_name, ref value_descriptions } = val_desc {

        let mut sig_enum = Enum::new(&to_enum_name(message_id, signal_name));
        sig_enum.allow("dead_code");
        sig_enum.vis("pub");
        sig_enum.repr("u64");
        sig_enum.derive("Debug");
        sig_enum.derive("Clone");
        sig_enum.derive("Copy");
        sig_enum.derive("PartialEq");
        sig_enum.derive("Eq");
        for desc in value_descriptions {
            sig_enum.new_variant(&desc.b().to_camel_case());
        }
        sig_enum.new_variant("XValue(u64)");
        return Some(sig_enum);
    }
    None
}

pub fn signal_enum_impl(val_desc: &ValueDescription) -> Option<Impl> {
    if let ValueDescription::Signal{ ref message_id, ref signal_name, ref value_descriptions } = val_desc {
        let enum_name = to_enum_name(message_id, signal_name);
        let mut enum_impl = Impl::new(codegen::Type::new(&enum_name));
        enum_impl.impl_trait("From<u64>");

        let from_fn = enum_impl.new_fn("from");
        from_fn.allow("dead_code");
        from_fn.arg("val", codegen::Type::new("u64"));

        let mut matching = String::new();
        write!(&mut matching, "match val {{\n").unwrap();
        for value_description in value_descriptions {
            write!(&mut matching, "    {} => {}::{},\n", value_description.a(), enum_name, value_description.b().to_camel_case()).unwrap();
        }
        write!(&mut matching, "    value => {}::XValue(value),\n", enum_name).unwrap();
        write!(&mut matching, "}}").unwrap();

        from_fn.line(matching);
        from_fn.ret(codegen::Type::new("Self"));

        return Some(enum_impl);
    }
    None
}

pub fn signal_fn(dbc: &DBC, signal: &Signal, message_id: &MessageId) -> Result<Function> {
    let mut signal_fn = codegen::Function::new(&signal.name().to_lowercase());
    signal_fn.allow("dead_code");
    signal_fn.vis("pub");
    signal_fn.arg_ref_self();

    // Attempt to find a matching enum return type, default to `f64` otherwise
    let ret_enum_type = dbc.value_descriptions_for_signal(message_id, signal.name()).map(|_| codegen::Type::new(&to_enum_name(message_id, signal.name())));
    signal_fn.ret(ret_enum_type.clone().unwrap_or_else(|| codegen::Type::new("f64")));

    let default_signal_comment = format!("Read {} signal from can frame", signal.name());
    let signal_comment = dbc.signal_comment(message_id, signal.name()).unwrap_or(&default_signal_comment);
    signal_fn.doc(signal_comment);

    let read_byte_order = match signal.byte_order() {
        ByteOrder::LittleEndian => "let frame_payload: u64 = LE::read_u64(self.frame_payload);",
        ByteOrder::BigEndian => "let  frame_payload: u64 = BE::read_u64(self.frame_payload);",
    };
    signal_fn.line(read_byte_order);

    let bit_msk_const = 2u64.saturating_pow(*signal.signal_size() as u32) - 1;
    let mut calc = String::new();

    if ret_enum_type.is_some() {
       write!(&mut calc, "{}::from((", to_enum_name(message_id, signal.name()))?; // TODO to_valid_upper_case called multiple times
    }

    let signal_shift = shift_amount(*signal.byte_order(), *signal.start_bit(), *signal.signal_size());

    // No shift required if start_bit == 0
    let shift = if signal_shift != 0 {
        format!("(frame_payload >> {})", signal_shift)
    } else {
        format!("frame_payload")
    };

    write!(&mut calc, "({} & {:#X}) as f64", shift, bit_msk_const)?;

    if *signal.factor() != 1.0 {
        write!(&mut calc, " * {:.6}", signal.factor())?;
    }

    if *signal.offset() != 0.0 {
        write!(&mut calc, " + {}f64", signal.offset())?;
    }

    if ret_enum_type.is_some() {
        write!(&mut calc, ") as u64)")?;
    }

    signal_fn.line(calc);
    Ok(signal_fn)
}

fn shift_amount(byte_order: ByteOrder, start_bit: u64, signal_size: u64) -> u64 {
    match byte_order {
        ByteOrder::LittleEndian => start_bit,
        ByteOrder::BigEndian => 64 - signal_size - ((start_bit / 8) * 8 + (7 - (start_bit % 8))),
    }
}

fn message_const(message: &Message) -> Const {
    let const_name = format!("MESSAGE_ID_{}", message.message_name().to_shouty_snake_case());
    let mut c = Const::new(&const_name, codegen::Type::new("u32"), message.message_id().0.to_string());
    c.allow("dead_code");
    c.vis("pub");
    c
}

fn message_struct(dbc: &DBC, message: &Message) -> Struct {
    let mut message_struct = Struct::new(&message.message_name().to_camel_case());
    if let Some(message_comment) = dbc.message_comment(message.message_id()) {
        message_struct.doc(message_comment);
    }
    message_struct.allow("dead_code");
    message_struct.derive("Debug");
    message_struct.vis("pub");
    message_struct.generic("'a");
    message_struct.field("frame_payload", "&'a[u8]");
    message_struct
}

fn message_impl(dbc: &DBC, message: &Message) -> Result<Impl> {

    let mut msg_impl = Impl::new(codegen::Type::new(&message.message_name().to_camel_case()));
    msg_impl.generic("'a");
    msg_impl.target_generic("'a");
    let new_fn = msg_impl.new_fn("new");
    new_fn.allow("dead_code");
    new_fn.vis("pub");
    new_fn.arg("frame_payload", codegen::Type::new("&[u8]"));

    new_fn.line(format!("{} {{ frame_payload }}", message.message_name().to_camel_case()));
    new_fn.ret(codegen::Type::new(&message.message_name().to_camel_case()));

    for signal in message.signals() {
        msg_impl.push_fn(signal_fn(dbc, signal, message.message_id())?);
    }

    Ok(msg_impl)
}

pub fn can_reader(dbc: &DBC) -> Result<Scope> {

    let mut scope = Scope::new();
    scope.import("byteorder", "{ByteOrder, LE, BE}");

    for message in dbc.messages() {
        scope.push_const(message_const(message));
    }

    for value_description in dbc.value_descriptions() {
        if let Some(signal_enum) = signal_enum(value_description) {
            scope.push_enum(signal_enum);
        }

        if let Some(enum_impl) = signal_enum_impl(value_description) {
            scope.push_impl(enum_impl);
        }
    }

    for message in dbc.messages() {
        scope.push_struct(message_struct(&dbc, message));
        scope.push_impl(message_impl(&dbc, message)?);
    }

    Ok(scope)
}<|endoftext|>


<commit_before>use piston_window::*;
use opengl_graphics::GlGraphics;
use cgmath::Vector2;

use state;
use game::*;
use num_traits::Float;
use time;

pub struct App {
    state: state::GameState,
    lastUpdateTime: Option<f32>
}

impl App {
    pub fn new() -> App {
        App {
            state: state::GameState::new(),
            lastUpdateTime: None
        }
    }

    pub fn load(&mut self) {
        // Create two players
        self.state.players.push(Player::new([1.0, 0.0, 0.0, 1.0],
                                            Vector2::new(30.0, 30.0),
                                            Shape::Triangle));

        self.state.players.push(Player::new([1.0, 1.0, 0.0, 1.0],
                                            Vector2::new(1250.0, 770.0),
                                            Shape::Rectangle));
    }

    fn create_context(&mut self, args: &RenderArgs) -> Context {

        // Make sure this fits with the aspect ratio
        let width = self.state.width as f64;
        let height = self.state.height as f64;

        let x_scale = width / args.width as f64;
        let y_scale = height / args.height as f64;

        let scale = y_scale.max(x_scale);

        if y_scale < scale {
            Context::new_abs(width, args.height as f64 * scale)
                .trans(0.0, (args.height as f64 * scale - height) * 0.5)
        } else {
            Context::new_abs(args.width as f64 * scale, height)
                .trans((args.width as f64 * scale - width) * 0.5, 0.0)
        }
    }

    pub fn render(&mut self, args: &RenderArgs, gl: &mut GlGraphics) {

        let c: Context = self.create_context(args);

        let window_background = [0.0; 4];

        // Start drawing the viewport
        gl.draw(args.viewport(), |_, gl| {

            // Clear to black
            clear(window_background, gl);

            // Draw player base
            for player in self.state.players.iter() {
                polygon(player.color,
                        player.shape.as_polygon(),
                        c.transform
                            .trans(player.base.position.x as f64, player.base.position.y as f64)
                            .scale(20.0, 20.0),
                        gl);

                for goblin in player.goblins.iter() {
                    polygon(player.color,
                            player.shape.as_polygon(),
                            c.transform
                                .trans(goblin.position.x as f64, goblin.position.y as f64)
                                .scale(8.0, 8.0),
                            gl);
                }
            }
        });
    }

    pub fn update(&mut self, args: &UpdateArgs) {
        let currentTime = (time::precise_time_ns() as f64 * 1e-9) as f32;
        let delta = match self.lastUpdateTime {
            Some(val) => currentTime - val,
            None => 0.0
        };
        self.lastUpdateTime = Some(currentTime);

        // Spawn goblins
        for mut player in &mut self.state.players {
            player.base.energy += delta;
            player.spawn_goblin();
        }

        // Move goblins
        for mut player in &mut self.state.players {
            for mut goblin in &mut player.goblins {
                goblin.position.x += delta * 10.0;
            }
        }
    }
}<commit_msg>Moved based and increased goblini speed<commit_after>use piston_window::*;
use opengl_graphics::GlGraphics;
use cgmath::Vector2;

use state;
use game::*;
use num_traits::Float;
use time;

pub struct App {
    state: state::GameState,
    lastUpdateTime: Option<f32>
}

impl App {
    pub fn new() -> App {
        App {
            state: state::GameState::new(),
            lastUpdateTime: None
        }
    }

    pub fn load(&mut self) {
        // Create two players
        self.state.players.push(Player::new([1.0, 0.0, 0.0, 1.0],
                                            Vector2::new(30.0, 400.0),
                                            Shape::Triangle));

        self.state.players.push(Player::new([1.0, 1.0, 0.0, 1.0],
                                            Vector2::new(1250.0, 400.0),
                                            Shape::Rectangle));
    }

    fn create_context(&mut self, args: &RenderArgs) -> Context {

        // Make sure this fits with the aspect ratio
        let width = self.state.width as f64;
        let height = self.state.height as f64;

        let x_scale = width / args.width as f64;
        let y_scale = height / args.height as f64;

        let scale = y_scale.max(x_scale);

        if y_scale < scale {
            Context::new_abs(width, args.height as f64 * scale)
                .trans(0.0, (args.height as f64 * scale - height) * 0.5)
        } else {
            Context::new_abs(args.width as f64 * scale, height)
                .trans((args.width as f64 * scale - width) * 0.5, 0.0)
        }
    }

    pub fn render(&mut self, args: &RenderArgs, gl: &mut GlGraphics) {

        let c: Context = self.create_context(args);

        let window_background = [0.1, 0.1, 0.1, 1.0];

        // Start drawing the viewport
        gl.draw(args.viewport(), |_, gl| {

            // Clear to black
            clear(window_background, gl);

            // Draw player base
            for player in self.state.players.iter() {
                polygon(player.color,
                        player.shape.as_polygon(),
                        c.transform
                            .trans(player.base.position.x as f64, player.base.position.y as f64)
                            .scale(20.0, 20.0),
                        gl);

                for goblin in player.goblins.iter() {
                    polygon(player.color,
                            player.shape.as_polygon(),
                            c.transform
                                .trans(goblin.position.x as f64, goblin.position.y as f64)
                                .scale(8.0, 8.0),
                            gl);
                }
            }
        });
    }

    pub fn update(&mut self, args: &UpdateArgs) {
        let currentTime = (time::precise_time_ns() as f64 * 1e-9) as f32;
        let delta = match self.lastUpdateTime {
            Some(val) => currentTime - val,
            None => 0.0
        };
        self.lastUpdateTime = Some(currentTime);

        // Spawn goblins
        for mut player in &mut self.state.players {
            player.base.energy += delta;
            player.spawn_goblin();
        }

        // Move goblins
        for mut player in &mut self.state.players {
            for mut goblin in &mut player.goblins {
                goblin.position.x += delta * 30.0;
            }
        }
    }
}<|endoftext|>


<commit_before>use super::{AnimeEntry, AnimeInfo, Status};
use chrono::{Date, Datelike, Local, NaiveDate, TimeZone};

#[derive(Deserialize)]
pub struct User {
    pub id: u32,
    #[serde(rename = "mediaListOptions")]
    pub list_options: MediaListOptions,
}

impl Default for User {
    fn default() -> User {
        User {
            id: 0,
            list_options: MediaListOptions::default(),
        }
    }
}

#[derive(Deserialize)]
pub struct MediaListOptions {
    #[serde(rename = "scoreFormat")]
    pub score_format: ScoreFormat,
}

impl Default for MediaListOptions {
    fn default() -> MediaListOptions {
        MediaListOptions {
            score_format: ScoreFormat::default(),
        }
    }
}

#[derive(Serialize, Deserialize, Copy, Clone)]
pub enum ScoreFormat {
    #[serde(rename = "POINT_100")]
    Point100,
    #[serde(rename = "POINT_10_DECIMAL")]
    Point10Decimal,
    #[serde(rename = "POINT_10")]
    Point10,
    #[serde(rename = "POINT_5")]
    Point5,
    #[serde(rename = "POINT_3")]
    Point3,
}

impl ScoreFormat {
    pub fn max_score(&self) -> u8 {
        use self::ScoreFormat::*;

        match self {
            Point100 => 100,
            Point10Decimal | Point10 => 10,
            Point5 => 5,
            Point3 => 3,
        }
    }
}

impl Default for ScoreFormat {
    fn default() -> ScoreFormat {
        ScoreFormat::Point100
    }
}

#[derive(Deserialize)]
pub struct Media {
    pub id: u32,
    pub title: MediaTitle,
    pub episodes: Option<u32>,
}

#[derive(Deserialize)]
pub struct MediaTitle {
    romaji: String,
}

impl Into<AnimeInfo> for Media {
    fn into(self) -> AnimeInfo {
        AnimeInfo {
            id: self.id,
            title: self.title.romaji,
            episodes: self.episodes,
        }
    }
}

#[derive(Deserialize)]
pub struct MediaListEntry {
    pub progress: u32,
    pub status: MediaStatus,
    pub score: f32,
    #[serde(rename = "startedAt")]
    pub start_date: MediaDate,
    #[serde(rename = "completedAt")]
    pub finish_date: MediaDate,
}

impl MediaListEntry {
    pub fn into_generic_entry(self, info: AnimeInfo) -> AnimeEntry {
        // AniList uses 0.0 to represent a non-set score
        let score = if self.score >= 0.1 {
            Some(self.score)
        } else {
            None
        };

        AnimeEntry {
            info,
            watched_episodes: self.progress,
            score,
            status: self.status.into(),
            start_date: self.start_date.into_date(),
            finish_date: self.finish_date.into_date(),
        }
    }
}

#[derive(Serialize, Deserialize, Copy, Clone, PartialEq)]
pub enum MediaStatus {
    #[serde(rename = "CURRENT")]
    Current,
    #[serde(rename = "COMPLETED")]
    Completed,
    #[serde(rename = "PAUSED")]
    Paused,
    #[serde(rename = "DROPPED")]
    Dropped,
    #[serde(rename = "PLANNING")]
    Planning,
    #[serde(rename = "REPEATING")]
    Repeating,
}

impl Into<Status> for MediaStatus {
    fn into(self) -> Status {
        match self {
            MediaStatus::Current => Status::Watching,
            MediaStatus::Completed => Status::Completed,
            MediaStatus::Paused => Status::OnHold,
            MediaStatus::Dropped => Status::Dropped,
            MediaStatus::Planning => Status::PlanToWatch,
            MediaStatus::Repeating => Status::Rewatching,
        }
    }
}

impl From<Status> for MediaStatus {
    fn from(status: Status) -> MediaStatus {
        match status {
            Status::Watching => MediaStatus::Current,
            Status::Completed => MediaStatus::Completed,
            Status::OnHold => MediaStatus::Paused,
            Status::Dropped => MediaStatus::Dropped,
            Status::PlanToWatch => MediaStatus::Planning,
            Status::Rewatching => MediaStatus::Repeating,
        }
    }
}

#[derive(Serialize, Deserialize)]
pub struct MediaDate {
    pub year: Option<i32>,
    pub month: Option<u32>,
    pub day: Option<u32>,
}

impl MediaDate {
    pub fn into_date(self) -> Option<Date<Local>> {
        match (self.year, self.month, self.day) {
            (Some(year), Some(month), Some(day)) => Some(Local.ymd(year, month, day)),
            _ => None,
        }
    }

    pub fn from_date(date: Option<Date<Local>>) -> MediaDate {
        match date {
            Some(date) => MediaDate {
                year: Some(date.year()),
                month: Some(date.month()),
                day: Some(date.day()),
            },
            None => MediaDate {
                year: None,
                month: None,
                day: None,
            },
        }
    }
}

impl From<NaiveDate> for MediaDate {
    fn from(date: NaiveDate) -> MediaDate {
        MediaDate {
            year: Some(date.year()),
            month: Some(date.month()),
            day: Some(date.day()),
        }
    }
}
<commit_msg>Fix clippy warning<commit_after>use super::{AnimeEntry, AnimeInfo, Status};
use chrono::{Date, Datelike, Local, NaiveDate, TimeZone};

#[derive(Deserialize)]
pub struct User {
    pub id: u32,
    #[serde(rename = "mediaListOptions")]
    pub list_options: MediaListOptions,
}

impl Default for User {
    fn default() -> User {
        User {
            id: 0,
            list_options: MediaListOptions::default(),
        }
    }
}

#[derive(Deserialize)]
pub struct MediaListOptions {
    #[serde(rename = "scoreFormat")]
    pub score_format: ScoreFormat,
}

impl Default for MediaListOptions {
    fn default() -> MediaListOptions {
        MediaListOptions {
            score_format: ScoreFormat::default(),
        }
    }
}

#[derive(Serialize, Deserialize, Copy, Clone)]
pub enum ScoreFormat {
    #[serde(rename = "POINT_100")]
    Point100,
    #[serde(rename = "POINT_10_DECIMAL")]
    Point10Decimal,
    #[serde(rename = "POINT_10")]
    Point10,
    #[serde(rename = "POINT_5")]
    Point5,
    #[serde(rename = "POINT_3")]
    Point3,
}

impl ScoreFormat {
    pub fn max_score(self) -> u8 {
        use self::ScoreFormat::*;

        match self {
            Point100 => 100,
            Point10Decimal | Point10 => 10,
            Point5 => 5,
            Point3 => 3,
        }
    }
}

impl Default for ScoreFormat {
    fn default() -> ScoreFormat {
        ScoreFormat::Point100
    }
}

#[derive(Deserialize)]
pub struct Media {
    pub id: u32,
    pub title: MediaTitle,
    pub episodes: Option<u32>,
}

#[derive(Deserialize)]
pub struct MediaTitle {
    romaji: String,
}

impl Into<AnimeInfo> for Media {
    fn into(self) -> AnimeInfo {
        AnimeInfo {
            id: self.id,
            title: self.title.romaji,
            episodes: self.episodes,
        }
    }
}

#[derive(Deserialize)]
pub struct MediaListEntry {
    pub progress: u32,
    pub status: MediaStatus,
    pub score: f32,
    #[serde(rename = "startedAt")]
    pub start_date: MediaDate,
    #[serde(rename = "completedAt")]
    pub finish_date: MediaDate,
}

impl MediaListEntry {
    pub fn into_generic_entry(self, info: AnimeInfo) -> AnimeEntry {
        // AniList uses 0.0 to represent a non-set score
        let score = if self.score >= 0.1 {
            Some(self.score)
        } else {
            None
        };

        AnimeEntry {
            info,
            watched_episodes: self.progress,
            score,
            status: self.status.into(),
            start_date: self.start_date.into_date(),
            finish_date: self.finish_date.into_date(),
        }
    }
}

#[derive(Serialize, Deserialize, Copy, Clone, PartialEq)]
pub enum MediaStatus {
    #[serde(rename = "CURRENT")]
    Current,
    #[serde(rename = "COMPLETED")]
    Completed,
    #[serde(rename = "PAUSED")]
    Paused,
    #[serde(rename = "DROPPED")]
    Dropped,
    #[serde(rename = "PLANNING")]
    Planning,
    #[serde(rename = "REPEATING")]
    Repeating,
}

impl Into<Status> for MediaStatus {
    fn into(self) -> Status {
        match self {
            MediaStatus::Current => Status::Watching,
            MediaStatus::Completed => Status::Completed,
            MediaStatus::Paused => Status::OnHold,
            MediaStatus::Dropped => Status::Dropped,
            MediaStatus::Planning => Status::PlanToWatch,
            MediaStatus::Repeating => Status::Rewatching,
        }
    }
}

impl From<Status> for MediaStatus {
    fn from(status: Status) -> MediaStatus {
        match status {
            Status::Watching => MediaStatus::Current,
            Status::Completed => MediaStatus::Completed,
            Status::OnHold => MediaStatus::Paused,
            Status::Dropped => MediaStatus::Dropped,
            Status::PlanToWatch => MediaStatus::Planning,
            Status::Rewatching => MediaStatus::Repeating,
        }
    }
}

#[derive(Serialize, Deserialize)]
pub struct MediaDate {
    pub year: Option<i32>,
    pub month: Option<u32>,
    pub day: Option<u32>,
}

impl MediaDate {
    pub fn into_date(self) -> Option<Date<Local>> {
        match (self.year, self.month, self.day) {
            (Some(year), Some(month), Some(day)) => Some(Local.ymd(year, month, day)),
            _ => None,
        }
    }

    pub fn from_date(date: Option<Date<Local>>) -> MediaDate {
        match date {
            Some(date) => MediaDate {
                year: Some(date.year()),
                month: Some(date.month()),
                day: Some(date.day()),
            },
            None => MediaDate {
                year: None,
                month: None,
                day: None,
            },
        }
    }
}

impl From<NaiveDate> for MediaDate {
    fn from(date: NaiveDate) -> MediaDate {
        MediaDate {
            year: Some(date.year()),
            month: Some(date.month()),
            day: Some(date.day()),
        }
    }
}
<|endoftext|>


<commit_before>//! This example demonstrates how to use neovim-rs. It runs Neovim itself on the main thread, and
//! launches a separate logging thread. The logging thread connects to Neovim over an anonymous
//! pipe and asks to be notified of "bufenter" events (whenever you switch to a buffer). It then
//! writes the messages it receives from Neovim to a file called events.log in the current
//! directory. The purpose is to demonstrate how to use Neovim's msgpack-rpc protocol from Rust.

extern crate libc;
extern crate neovim;

use std::io::Write;
use std::fs::OpenOptions;
use std::path::Path;
use std::slice;
use libc::{c_int, c_uchar, c_void, pipe, read, write};
#[cfg(target_os="windows")]
use libc::{c_uint, O_BINARY};
#[cfg(not(target_os="windows"))]
use libc::size_t;

fn send_message(fd: c_int, command: &str) {
    let mut arr = neovim::Array::new();
    arr.add_string(command);
    let msg = neovim::serialize_message(1, "vim_command", &arr);
    let msg_ref: &str = msg.as_ref();
    let msg_ptr = msg_ref.as_ptr() as *const c_void;
    #[cfg(target_os="windows")]
    let len = msg.len() as c_uint;
    #[cfg(not(target_os="windows"))]
    let len = msg.len() as size_t;
    unsafe { write(fd, msg_ptr, len) };
}

fn recv_message(fd: c_int) -> Option<neovim::Array> {
    let mut buf : [c_uchar; 1024] = [0; 1024];
    let n = unsafe { read(fd, buf.as_mut_ptr() as *mut c_void, 1024) };
    if n <= 0 {
        return None;
    }
    unsafe {
        let v = slice::from_raw_parts(buf.as_ptr(), n as usize).to_vec();
        let s = String::from_utf8_unchecked(v);
        Some(neovim::deserialize_message(&s))
    }
}

fn main() {
    // two anonymous pipes for msgpack-rpc between the logger and nvim
    let mut nvim_log : [c_int; 2] = [0; 2]; // to nvim from logger
    let mut log_nvim : [c_int; 2] = [0; 2]; // to logger from nvim
    unsafe {
        #[cfg(target_os="windows")]
        pipe(nvim_log.as_mut_ptr(), 2048, O_BINARY);
        #[cfg(not(target_os="windows"))]
        pipe(nvim_log.as_mut_ptr());

        #[cfg(target_os="windows")]
        pipe(log_nvim.as_mut_ptr(), 2048, O_BINARY);
        #[cfg(not(target_os="windows"))]
        pipe(log_nvim.as_mut_ptr());
    };

    // open log file
    let mut opts = OpenOptions::new();
    opts.create(true);
    opts.write(true);
    opts.append(true);
    let mut file = opts.open(&Path::new("events.log")).unwrap();

    // listen for events in a separate thread and log them
    ::std::thread::spawn(move || {
        // listen for bufenter events
        send_message(nvim_log[1], "au BufEnter * call rpcnotify(1, 'bufenter', fnamemodify(bufname(''), ':p'))");

        // receive messages
        while let Some(recv_arr) = recv_message(log_nvim[0]) {
            if recv_arr.len() > 0 {
                let recv_str = format!("{:?}\n", recv_arr).into_bytes();
                file.write_all(recv_str.as_ref()).ok();
            }
        }
    });

    // start nvim
    let args : Vec<String> = vec!["events".to_string(), "-u".to_string(), "NONE".to_string()];
    neovim::main_setup(&args);
    neovim::channel_from_fds(nvim_log[0], log_nvim[1]);
    neovim::main_loop();
}
<commit_msg>Clean up<commit_after>//! This example demonstrates how to use neovim-rs. It runs Neovim itself on the main thread, and
//! launches a separate logging thread. The logging thread connects to Neovim over an anonymous
//! pipe and asks to be notified of "bufenter" events (whenever you switch to a buffer). It then
//! writes the messages it receives from Neovim to a file called events.log in the current
//! directory. The purpose is to demonstrate how to use Neovim's msgpack-rpc protocol from Rust.

extern crate libc;
extern crate neovim;

use std::io::Write;
use std::fs::OpenOptions;
use std::path::Path;
use std::slice;
use libc::{c_int, c_uchar, c_void, pipe, read, write};

fn send_message(fd: c_int, command: &str) {
    let mut arr = neovim::Array::new();
    arr.add_string(command);
    let msg = neovim::serialize_message(1, "vim_command", &arr);
    let msg_ref: &str = msg.as_ref();
    let msg_ptr = msg_ref.as_ptr() as *const c_void;
    #[cfg(target_os="windows")]
    let len = msg.len() as libc::c_uint;
    #[cfg(not(target_os="windows"))]
    let len = msg.len() as libc::size_t;
    unsafe { write(fd, msg_ptr, len) };
}

fn recv_message(fd: c_int) -> Option<neovim::Array> {
    let mut buf : [c_uchar; 1024] = [0; 1024];
    let n = unsafe { read(fd, buf.as_mut_ptr() as *mut c_void, 1024) };
    if n <= 0 {
        return None;
    }
    unsafe {
        let v = slice::from_raw_parts(buf.as_ptr(), n as usize).to_vec();
        let s = String::from_utf8_unchecked(v);
        Some(neovim::deserialize_message(&s))
    }
}

fn main() {
    // two anonymous pipes for msgpack-rpc between the logger and nvim
    let mut nvim_log : [c_int; 2] = [0; 2]; // to nvim from logger
    let mut log_nvim : [c_int; 2] = [0; 2]; // to logger from nvim
    unsafe {
        #[cfg(target_os="windows")]
        pipe(nvim_log.as_mut_ptr(), 2048, libc::O_BINARY);
        #[cfg(not(target_os="windows"))]
        pipe(nvim_log.as_mut_ptr());

        #[cfg(target_os="windows")]
        pipe(log_nvim.as_mut_ptr(), 2048, libc::O_BINARY);
        #[cfg(not(target_os="windows"))]
        pipe(log_nvim.as_mut_ptr());
    };

    // open log file
    let mut opts = OpenOptions::new();
    opts.create(true);
    opts.write(true);
    opts.append(true);
    let mut file = opts.open(&Path::new("events.log")).unwrap();

    // listen for events in a separate thread and log them
    ::std::thread::spawn(move || {
        // listen for bufenter events
        send_message(nvim_log[1], "au BufEnter * call rpcnotify(1, 'bufenter', fnamemodify(bufname(''), ':p'))");

        // receive messages
        while let Some(recv_arr) = recv_message(log_nvim[0]) {
            if recv_arr.len() > 0 {
                let recv_str = format!("{:?}\n", recv_arr).into_bytes();
                file.write_all(recv_str.as_ref()).ok();
            }
        }
    });

    // start nvim
    let args : Vec<String> = vec!["events".to_string(), "-u".to_string(), "NONE".to_string()];
    neovim::main_setup(&args);
    neovim::channel_from_fds(nvim_log[0], log_nvim[1]);
    neovim::main_loop();
}
<|endoftext|>


<commit_before>// The MIT License (MIT)
//
// Copyright (c) 2015 Johan Johansson
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

//! Common Version interfaces provided by D3D11
//!
//! # References
//! [Common Version Interfaces, MSDN]
//! (https://msdn.microsoft.com/en-us/library/windows/desktop/ff728662(v=vs.85).aspx)

use winapi::{ LPVOID, SIZE_T };
use dxgi::IUnknownT;

type ID3DBlob = ID3D10Blob;

#[repr(C)] pub struct ID3D10Blob { pub vtable: *mut ID3DBlobVtbl }
#[repr(C)] pub struct ID3DInclude { pub vtable: *mut ID3DIncludeVtbl }
#[repr(C)] pub struct ID3DUserDefinedAnnotation { pub vtable: *mut ID3DUserDefinedAnnotationVtbl }

c_vtable!{
	_ of (), trait IUnknownT {
		fn QueryInterface(riid: REFIID, object: *mut *mut c_void) -> HRESULT,
		fn AddRef() -> ULONG,
		fn Release() -> ULONG,
	} with heirs [
		pub ID3D10BlobVtbl of ID3D10Blob, pub trait ID3D10BlobT {
			fn GetBufferPointer() -> LPVOID,
			fn GetBufferSize() -> SIZE_T,
		}
		pub ID3DUserDefinedAnnotationVtbl of ID3DUserDefinedAnnotation, pub trait ID3DUserDefinedAnnotationT {
			fn BeginEvent(Name: LPCWSTR) -> INT,
			fn EndEvent() -> INT,
			fn SetMarker(Name: LPCWSTR) -> void,
			fn GetStatus() -> BOOL,
		}
	]
	pub ID3DIncludeVtbl of ID3DInclude, pub trait ID3DIncludeT {
		fn Open(IncludeType: D3D_INCLUDE_TYPE, pFileName: LPCSTR, pParentData: LPCVOID, ppData: *mut *mut LPCVOID, pBytes: *mut ppData) -> HRESULT,
		fn Close(pData: LPCVOID) -> HRESULT,
	}
}<commit_msg>Fix imports in common_version::interfaces<commit_after>// The MIT License (MIT)
//
// Copyright (c) 2015 Johan Johansson
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

//! Common Version interfaces provided by D3D11
//!
//! # References
//! [Common Version Interfaces, MSDN]
//! (https://msdn.microsoft.com/en-us/library/windows/desktop/ff728662(v=vs.85).aspx)

use libc::c_void;
use winapi::{ LPVOID, SIZE_T, LPCVOID, LPCSTR, HRESULT,
	REFIID, ULONG, INT, BOOL, LPCWSTR,
	UINT };
use dxgi::IUnknownT;

use common_version::enumerations::{ D3D_INCLUDE_TYPE };

type ID3DBlob = ID3D10Blob;

#[repr(C)] pub struct ID3D10Blob { pub vtable: *mut ID3DBlobVtbl }
#[repr(C)] pub struct ID3DInclude { pub vtable: *mut ID3DIncludeVtbl }
#[repr(C)] pub struct ID3DUserDefinedAnnotation { pub vtable: *mut ID3DUserDefinedAnnotationVtbl }

c_vtable!{
	_ of (), trait IUnknownT {
		fn QueryInterface(riid: REFIID, object: *mut *mut c_void) -> HRESULT,
		fn AddRef() -> ULONG,
		fn Release() -> ULONG,
	} with heirs [
		pub ID3D10BlobVtbl of ID3D10Blob, pub trait ID3D10BlobT {
			fn GetBufferPointer() -> LPVOID,
			fn GetBufferSize() -> SIZE_T,
		}
		pub ID3DUserDefinedAnnotationVtbl of ID3DUserDefinedAnnotation, pub trait ID3DUserDefinedAnnotationT {
			fn BeginEvent(Name: LPCWSTR) -> INT,
			fn EndEvent() -> INT,
			fn SetMarker(Name: LPCWSTR) -> (),
			fn GetStatus() -> BOOL,
		}
	]
	pub ID3DIncludeVtbl of ID3DInclude, pub trait ID3DIncludeT {
		fn Open(IncludeType: D3D_INCLUDE_TYPE, pFileName: LPCSTR, pParentData: LPCVOID, ppData: *mut LPCVOID, pBytes: *mut UINT) -> HRESULT,
		fn Close(pData: LPCVOID) -> HRESULT,
	}
}<|endoftext|>


<commit_before>
use super::DocBuilder;
use super::crates::crates_from_path;
use DocBuilderError;
use utils::{get_package, source_path, copy_dir, copy_doc_dir, update_sources};
use db::{connect_db, add_package_into_database, add_build_into_database, add_path_into_database};
use cargo::core::Package;
use std::process::{Command, Output};
use std::path::PathBuf;
use postgres::Connection;

use regex::Regex;

type CommandResult = Result<String, String>;

#[derive(Debug)]
pub struct ChrootBuilderResult {
    pub output: String,
    pub build_success: bool,
    pub have_doc: bool,
    pub have_examples: bool,
    pub rustc_version: String,
    pub cratesfyi_version: String,
}

impl DocBuilder {
    /// Builds every package documentation in chroot environment
    pub fn build_world(&mut self) -> Result<(), DocBuilderError> {
        try!(update_sources());

        let mut count = 0;

        crates(self.options.crates_io_index_path.clone(), |name, version| {
            match self.build_package(name, version) {
                Ok(status) => {
                    count += 1;
                    if status && count % 10 == 0 {
                        let _ = self.save_cache();
                    }
                }
                Err(err) => warn!("Failed to build package {}-{}: {}", name, version, err),
            }
            self.cache.insert(format!("{}-{}", name, version));
        })
    }

    /// Builds package documentation in chroot environment and adds into cratesfyi database
    pub fn build_package(&mut self, name: &str, version: &str) -> Result<bool, DocBuilderError> {
        info!("Building package {}-{}", name, version);

        // Database connection
        let conn = try!(connect_db());

        // Skip crates according to options
        if (self.options.skip_if_log_exists &&
            self.cache.contains(&format!("{}-{}", name, version)[..])) ||
           (self.options.skip_if_exists &&
            self.db_cache.contains(&format!("{}-{}", name, version)[..])) {
            info!("Skipping");
            return Ok(false);
        }

        // get_package (and cargo) is using semver, add '=' in front of version.
        let pkg = try!(get_package(name, Some(&format!("={}", version)[..])));
        let res = self.build_package_in_chroot(&pkg);

        // copy sources and documentation
        try!(self.add_sources_into_database(&conn, &pkg));
        if res.have_doc {
            try!(self.copy_documentation(&pkg, &res.rustc_version));
            try!(self.add_documentation_into_database(&conn, &pkg));
        }

        let release_id = try!(add_package_into_database(&conn, &pkg, &res));
        try!(add_build_into_database(&conn, &release_id, &res));

        // remove documentation, source and build directory after we are done
        try!(self.clean(&pkg));

        // add package into build cache
        self.cache.insert(format!("{}-{}", name, version));

        Ok(res.build_success)
    }

    /// Builds documentation of a package with cratesfyi in chroot environment
    fn build_package_in_chroot(&self, package: &Package) -> ChrootBuilderResult {
        debug!("Building package in chroot");
        let (rustc_version, cratesfyi_version) = self.get_versions();
        let cmd = format!("cratesfyi doc {} ={}",
                          package.manifest().name(),
                          package.manifest().version());
        match self.chroot_command(cmd) {
            Ok(o) => {
                ChrootBuilderResult {
                    output: o,
                    build_success: true,
                    have_doc: self.have_documentation(&package),
                    have_examples: self.have_examples(&package),
                    rustc_version: rustc_version,
                    cratesfyi_version: cratesfyi_version,
                }
            }
            Err(e) => {
                ChrootBuilderResult {
                    output: e,
                    build_success: false,
                    have_doc: false,
                    have_examples: self.have_examples(&package),
                    rustc_version: rustc_version,
                    cratesfyi_version: cratesfyi_version,
                }
            }
        }
    }

    /// Copies source files of a package into source_path
    #[allow(dead_code)]  // I've been using this function before storing files in database
    fn copy_sources(&self, package: &Package) -> Result<(), DocBuilderError> {
        debug!("Copying sources");
        let destination = PathBuf::from(&self.options.sources_path).join(format!("{}/{}",
                          package.manifest().name(),
                          package.manifest().version()));
        // unwrap is safe here, this function will be always called after get_package
        match copy_dir(source_path(&package).unwrap(), &destination) {
            Ok(_) => Ok(()),
            Err(e) => Err(DocBuilderError::Io(e)),
        }
    }

    /// Copies documentation to destination directory
    fn copy_documentation(&self,
                          package: &Package,
                          rustc_version: &str)
                          -> Result<(), DocBuilderError> {
        debug!("Copying codumentation");
        let crate_doc_path = PathBuf::from(&self.options.chroot_path)
                                 .join("home")
                                 .join(&self.options.chroot_user)
                                 .join(canonical_name(&package));
        let destination = PathBuf::from(&self.options.destination).join(format!("{}/{}",
                          package.manifest().name(),
                          package.manifest().version()));
        copy_doc_dir(crate_doc_path,
                     destination,
                     parse_rustc_version(rustc_version).trim())
            .map_err(DocBuilderError::Io)
    }

    /// Removes build directory of a package in chroot
    fn remove_build_dir(&self, package: &Package) -> Result<(), DocBuilderError> {
        let _ = self.chroot_command(format!("rm -rf {}", canonical_name(&package)));
        Ok(())
    }

    /// Remove documentation, build directory and sources directory of a package
    fn clean(&self, package: &Package) -> Result<(), DocBuilderError> {
        debug!("Cleaning package");
        use std::fs::remove_dir_all;
        let documentation_path = PathBuf::from(&self.options.destination).join(format!("{}/{}",
                          package.manifest().name(),
                          package.manifest().version()));
        let source_path = source_path(&package).unwrap();
        // Some crates don't have documentation, so we don't care if removing_dir_all fails
        let _ = self.remove_build_dir(&package);
        let _ = remove_dir_all(documentation_path);
        let _ = remove_dir_all(source_path);
        Ok(())
    }

    /// Runs a command in a chroot environment
    fn chroot_command<T: AsRef<str>>(&self, cmd: T) -> CommandResult {
        command_result(Command::new("sudo")
                           .arg("lxc-attach")
                           .arg("-n")
                           .arg(&self.options.container_name)
                           .arg("--")
                           .arg("su")
                           .arg("-")
                           .arg(&self.options.chroot_user)
                           .arg("-c")
                           .arg(cmd.as_ref())
                           .output()
                           .unwrap())
    }

    /// Checks a package build directory to determine if package have docs
    ///
    /// This function is checking first target in targets to see if documentation exists for a
    /// crate. Package must be successfully built in chroot environment first.
    fn have_documentation(&self, package: &Package) -> bool {
        let crate_doc_path = PathBuf::from(&self.options.chroot_path)
                                 .join("home")
                                 .join(&self.options.chroot_user)
                                 .join(canonical_name(&package))
                                 .join("doc")
                                 .join(package.targets()[0].name().to_string());
        crate_doc_path.exists()
    }

    /// Checks if package have examples
    fn have_examples(&self, package: &Package) -> bool {
        let path = source_path(&package).unwrap().join("examples");
        path.exists() && path.is_dir()
    }

    /// Gets rustc and cratesfyi version from chroot environment
    fn get_versions(&self) -> (String, String) {
        // It is safe to use expect here
        // chroot environment must always have rustc and cratesfyi installed
        (String::from(self.chroot_command("rustc --version")
                          .expect("Failed to get rustc version")
                          .trim()),
         String::from(self.chroot_command("cratesfyi --version")
                          .expect("Failed to get cratesfyi version")
                          .trim()))
    }

    /// Adds sources into database
    fn add_sources_into_database(&self,
                                 conn: &Connection,
                                 package: &Package)
                                 -> Result<(), DocBuilderError> {
        debug!("Adding sources into database");
        let prefix = format!("sources/{}/{}",
                             package.manifest().name(),
                             package.manifest().version());
        add_path_into_database(conn, &prefix, source_path(&package).unwrap())
    }

    /// Adds documentations into database
    fn add_documentation_into_database(&self,
                                       conn: &Connection,
                                       package: &Package)
                                       -> Result<(), DocBuilderError> {
        debug!("Adding documentation into database");
        let prefix = format!("rustdoc/{}/{}",
                             package.manifest().name(),
                             package.manifest().version());
        let crate_doc_path = PathBuf::from(&self.options.chroot_path)
                                 .join("home")
                                 .join(&self.options.chroot_user)
                                 .join(canonical_name(&package));
        add_path_into_database(conn, &prefix, crate_doc_path)
    }
}

/// Simple function to capture command output
fn command_result(output: Output) -> CommandResult {
    let mut command_out = String::from_utf8_lossy(&output.stdout).into_owned();
    command_out.push_str(&String::from_utf8_lossy(&output.stderr).into_owned()[..]);
    match output.status.success() {
        true => Ok(command_out),
        false => Err(command_out),
    }
}

/// Returns canonical name of a package.
///
/// It's just package-version. All directory structure used in cratesfyi is
/// following this naming scheme.
fn canonical_name(package: &Package) -> String {
    format!("{}-{}",
            package.manifest().name(),
            package.manifest().version())
}

/// Parses rustc commit hash from rustc version string
fn parse_rustc_version<S: AsRef<str>>(version: S) -> String {
    let version_regex = Regex::new(r" ([\w-.]+) \((\w+) (\d+)-(\d+)-(\d+)\)").unwrap();
    let captures = version_regex.captures(version.as_ref()).expect("Failed to parse rustc version");

    format!("{}{}{}-{}-{}",
            captures.at(3).unwrap(),
            captures.at(4).unwrap(),
            captures.at(5).unwrap(),
            captures.at(1).unwrap(),
            captures.at(2).unwrap())
}

/// Runs `func` with the all crates from crates-io.index repository path.
///
/// First argument of func is the name of crate and
/// second argument is the version of crate. Func will be run for every crate.
fn crates<F>(path: PathBuf, mut func: F) -> Result<(), DocBuilderError>
    where F: FnMut(&str, &str) -> ()
{
    crates_from_path(&path, &mut func)
}

#[cfg(test)]
mod test {
    extern crate env_logger;
    use super::parse_rustc_version;
    use std::path::PathBuf;
    use {DocBuilder, DocBuilderOptions};

    #[test]
    #[ignore]
    fn test_build_world() {
        let _ = env_logger::init();
        let options = DocBuilderOptions::from_prefix(PathBuf::from("../cratesfyi-prefix"));
        let mut docbuilder = DocBuilder::new(options);
        // This test is building WHOLE WORLD and may take forever
        assert!(docbuilder.build_world().is_ok());
    }

    #[test]
    #[ignore]
    fn test_build_package() {
        let _ = env_logger::init();
        let options = DocBuilderOptions::from_prefix(PathBuf::from("../cratesfyi-prefix"));
        let mut docbuilder = DocBuilder::new(options);
        let res = docbuilder.build_package("rand", "0.3.14");
        assert!(res.is_ok());
    }

    #[test]
    fn test_parse_rustc_version() {
        assert_eq!(parse_rustc_version("rustc 1.10.0-nightly (57ef01513 2016-05-23)"),
                   "20160523-1.10.0-nightly-57ef01513");
        assert_eq!(parse_rustc_version("cratesfyi 0.2.0 (ba9ae23 2016-05-26)"),
                   "20160526-0.2.0-ba9ae23");
    }
}
<commit_msg>Fix documentation path<commit_after>
use super::DocBuilder;
use super::crates::crates_from_path;
use DocBuilderError;
use utils::{get_package, source_path, copy_dir, copy_doc_dir, update_sources};
use db::{connect_db, add_package_into_database, add_build_into_database, add_path_into_database};
use cargo::core::Package;
use std::process::{Command, Output};
use std::path::PathBuf;
use postgres::Connection;

use regex::Regex;

type CommandResult = Result<String, String>;

#[derive(Debug)]
pub struct ChrootBuilderResult {
    pub output: String,
    pub build_success: bool,
    pub have_doc: bool,
    pub have_examples: bool,
    pub rustc_version: String,
    pub cratesfyi_version: String,
}

impl DocBuilder {
    /// Builds every package documentation in chroot environment
    pub fn build_world(&mut self) -> Result<(), DocBuilderError> {
        try!(update_sources());

        let mut count = 0;

        crates(self.options.crates_io_index_path.clone(), |name, version| {
            match self.build_package(name, version) {
                Ok(status) => {
                    count += 1;
                    if status && count % 10 == 0 {
                        let _ = self.save_cache();
                    }
                }
                Err(err) => warn!("Failed to build package {}-{}: {}", name, version, err),
            }
            self.cache.insert(format!("{}-{}", name, version));
        })
    }

    /// Builds package documentation in chroot environment and adds into cratesfyi database
    pub fn build_package(&mut self, name: &str, version: &str) -> Result<bool, DocBuilderError> {
        info!("Building package {}-{}", name, version);

        // Database connection
        let conn = try!(connect_db());

        // Skip crates according to options
        if (self.options.skip_if_log_exists &&
            self.cache.contains(&format!("{}-{}", name, version)[..])) ||
           (self.options.skip_if_exists &&
            self.db_cache.contains(&format!("{}-{}", name, version)[..])) {
            info!("Skipping");
            return Ok(false);
        }

        // get_package (and cargo) is using semver, add '=' in front of version.
        let pkg = try!(get_package(name, Some(&format!("={}", version)[..])));
        let res = self.build_package_in_chroot(&pkg);

        // copy sources and documentation
        try!(self.add_sources_into_database(&conn, &pkg));
        if res.have_doc {
            try!(self.copy_documentation(&pkg, &res.rustc_version));
            try!(self.add_documentation_into_database(&conn, &pkg));
        }

        let release_id = try!(add_package_into_database(&conn, &pkg, &res));
        try!(add_build_into_database(&conn, &release_id, &res));

        // remove documentation, source and build directory after we are done
        try!(self.clean(&pkg));

        // add package into build cache
        self.cache.insert(format!("{}-{}", name, version));

        Ok(res.build_success)
    }

    /// Builds documentation of a package with cratesfyi in chroot environment
    fn build_package_in_chroot(&self, package: &Package) -> ChrootBuilderResult {
        debug!("Building package in chroot");
        let (rustc_version, cratesfyi_version) = self.get_versions();
        let cmd = format!("cratesfyi doc {} ={}",
                          package.manifest().name(),
                          package.manifest().version());
        match self.chroot_command(cmd) {
            Ok(o) => {
                ChrootBuilderResult {
                    output: o,
                    build_success: true,
                    have_doc: self.have_documentation(&package),
                    have_examples: self.have_examples(&package),
                    rustc_version: rustc_version,
                    cratesfyi_version: cratesfyi_version,
                }
            }
            Err(e) => {
                ChrootBuilderResult {
                    output: e,
                    build_success: false,
                    have_doc: false,
                    have_examples: self.have_examples(&package),
                    rustc_version: rustc_version,
                    cratesfyi_version: cratesfyi_version,
                }
            }
        }
    }

    /// Copies source files of a package into source_path
    #[allow(dead_code)]  // I've been using this function before storing files in database
    fn copy_sources(&self, package: &Package) -> Result<(), DocBuilderError> {
        debug!("Copying sources");
        let destination = PathBuf::from(&self.options.sources_path).join(format!("{}/{}",
                          package.manifest().name(),
                          package.manifest().version()));
        // unwrap is safe here, this function will be always called after get_package
        match copy_dir(source_path(&package).unwrap(), &destination) {
            Ok(_) => Ok(()),
            Err(e) => Err(DocBuilderError::Io(e)),
        }
    }

    /// Copies documentation to destination directory
    fn copy_documentation(&self,
                          package: &Package,
                          rustc_version: &str)
                          -> Result<(), DocBuilderError> {
        debug!("Copying documentation");
        let crate_doc_path = PathBuf::from(&self.options.chroot_path)
                                 .join("home")
                                 .join(&self.options.chroot_user)
                                 .join(canonical_name(&package));
        let destination = PathBuf::from(&self.options.destination).join(format!("{}/{}",
                          package.manifest().name(),
                          package.manifest().version()));
        copy_doc_dir(crate_doc_path,
                     destination,
                     parse_rustc_version(rustc_version).trim())
            .map_err(DocBuilderError::Io)
    }

    /// Removes build directory of a package in chroot
    fn remove_build_dir(&self, package: &Package) -> Result<(), DocBuilderError> {
        let _ = self.chroot_command(format!("rm -rf {}", canonical_name(&package)));
        Ok(())
    }

    /// Remove documentation, build directory and sources directory of a package
    fn clean(&self, package: &Package) -> Result<(), DocBuilderError> {
        debug!("Cleaning package");
        use std::fs::remove_dir_all;
        let documentation_path = PathBuf::from(&self.options.destination).join(format!("{}/{}",
                          package.manifest().name(),
                          package.manifest().version()));
        let source_path = source_path(&package).unwrap();
        // Some crates don't have documentation, so we don't care if removing_dir_all fails
        let _ = self.remove_build_dir(&package);
        let _ = remove_dir_all(documentation_path);
        let _ = remove_dir_all(source_path);
        Ok(())
    }

    /// Runs a command in a chroot environment
    fn chroot_command<T: AsRef<str>>(&self, cmd: T) -> CommandResult {
        command_result(Command::new("sudo")
                           .arg("lxc-attach")
                           .arg("-n")
                           .arg(&self.options.container_name)
                           .arg("--")
                           .arg("su")
                           .arg("-")
                           .arg(&self.options.chroot_user)
                           .arg("-c")
                           .arg(cmd.as_ref())
                           .output()
                           .unwrap())
    }

    /// Checks a package build directory to determine if package have docs
    ///
    /// This function is checking first target in targets to see if documentation exists for a
    /// crate. Package must be successfully built in chroot environment first.
    fn have_documentation(&self, package: &Package) -> bool {
        let crate_doc_path = PathBuf::from(&self.options.chroot_path)
                                 .join("home")
                                 .join(&self.options.chroot_user)
                                 .join(canonical_name(&package))
                                 .join("doc")
                                 .join(package.targets()[0].name().to_string());
        crate_doc_path.exists()
    }

    /// Checks if package have examples
    fn have_examples(&self, package: &Package) -> bool {
        let path = source_path(&package).unwrap().join("examples");
        path.exists() && path.is_dir()
    }

    /// Gets rustc and cratesfyi version from chroot environment
    fn get_versions(&self) -> (String, String) {
        // It is safe to use expect here
        // chroot environment must always have rustc and cratesfyi installed
        (String::from(self.chroot_command("rustc --version")
                          .expect("Failed to get rustc version")
                          .trim()),
         String::from(self.chroot_command("cratesfyi --version")
                          .expect("Failed to get cratesfyi version")
                          .trim()))
    }

    /// Adds sources into database
    fn add_sources_into_database(&self,
                                 conn: &Connection,
                                 package: &Package)
                                 -> Result<(), DocBuilderError> {
        debug!("Adding sources into database");
        let prefix = format!("sources/{}/{}",
                             package.manifest().name(),
                             package.manifest().version());
        add_path_into_database(conn, &prefix, source_path(&package).unwrap())
    }

    /// Adds documentations into database
    fn add_documentation_into_database(&self,
                                       conn: &Connection,
                                       package: &Package)
                                       -> Result<(), DocBuilderError> {
        debug!("Adding documentation into database");
        let prefix = format!("rustdoc/{}/{}",
                             package.manifest().name(),
                             package.manifest().version());
        let crate_doc_path = PathBuf::from(&self.options.destination).join(format!("{}/{}",
                          package.manifest().name(),
                          package.manifest().version()));
        add_path_into_database(conn, &prefix, crate_doc_path)
    }
}

/// Simple function to capture command output
fn command_result(output: Output) -> CommandResult {
    let mut command_out = String::from_utf8_lossy(&output.stdout).into_owned();
    command_out.push_str(&String::from_utf8_lossy(&output.stderr).into_owned()[..]);
    match output.status.success() {
        true => Ok(command_out),
        false => Err(command_out),
    }
}

/// Returns canonical name of a package.
///
/// It's just package-version. All directory structure used in cratesfyi is
/// following this naming scheme.
fn canonical_name(package: &Package) -> String {
    format!("{}-{}",
            package.manifest().name(),
            package.manifest().version())
}

/// Parses rustc commit hash from rustc version string
fn parse_rustc_version<S: AsRef<str>>(version: S) -> String {
    let version_regex = Regex::new(r" ([\w-.]+) \((\w+) (\d+)-(\d+)-(\d+)\)").unwrap();
    let captures = version_regex.captures(version.as_ref()).expect("Failed to parse rustc version");

    format!("{}{}{}-{}-{}",
            captures.at(3).unwrap(),
            captures.at(4).unwrap(),
            captures.at(5).unwrap(),
            captures.at(1).unwrap(),
            captures.at(2).unwrap())
}

/// Runs `func` with the all crates from crates-io.index repository path.
///
/// First argument of func is the name of crate and
/// second argument is the version of crate. Func will be run for every crate.
fn crates<F>(path: PathBuf, mut func: F) -> Result<(), DocBuilderError>
    where F: FnMut(&str, &str) -> ()
{
    crates_from_path(&path, &mut func)
}

#[cfg(test)]
mod test {
    extern crate env_logger;
    use super::parse_rustc_version;
    use std::path::PathBuf;
    use {DocBuilder, DocBuilderOptions};

    #[test]
    #[ignore]
    fn test_build_world() {
        let _ = env_logger::init();
        let options = DocBuilderOptions::from_prefix(PathBuf::from("../cratesfyi-prefix"));
        let mut docbuilder = DocBuilder::new(options);
        // This test is building WHOLE WORLD and may take forever
        assert!(docbuilder.build_world().is_ok());
    }

    #[test]
    #[ignore]
    fn test_build_package() {
        let _ = env_logger::init();
        let options = DocBuilderOptions::from_prefix(PathBuf::from("../cratesfyi-prefix"));
        let mut docbuilder = DocBuilder::new(options);
        let res = docbuilder.build_package("rand", "0.3.14");
        assert!(res.is_ok());
    }

    #[test]
    fn test_parse_rustc_version() {
        assert_eq!(parse_rustc_version("rustc 1.10.0-nightly (57ef01513 2016-05-23)"),
                   "20160523-1.10.0-nightly-57ef01513");
        assert_eq!(parse_rustc_version("cratesfyi 0.2.0 (ba9ae23 2016-05-26)"),
                   "20160526-0.2.0-ba9ae23");
    }
}
<|endoftext|>


<commit_before>// Copyright 2014 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.

use std::mem::size_of;

trait Trait {}

fn main() {
    // Closures - ||
    assert_eq!(size_of::<||>(), size_of::<Option<||>>());

    // Functions
    assert_eq!(size_of::<fn(int)>(), size_of::<Option<fn(int)>>());
    assert_eq!(size_of::<extern "C" fn(int)>(), size_of::<Option<extern "C" fn(int)>>());

    // Slices - &str / &[T] / &mut [T]
    assert_eq!(size_of::<&str>(), size_of::<Option<&str>>());
    assert_eq!(size_of::<&[int]>(), size_of::<Option<&[int]>>());
    assert_eq!(size_of::<&mut [int]>(), size_of::<Option<&mut [int]>>());

    // Traits - Box<Trait> / &Trait / &mut Trait
    assert_eq!(size_of::<Box<Trait>>(), size_of::<Option<Box<Trait>>>());
    assert_eq!(size_of::<&Trait>(), size_of::<Option<&Trait>>());
    assert_eq!(size_of::<&mut Trait>(), size_of::<Option<&mut Trait>>());

    // Pointers - Box<T>
    assert_eq!(size_of::<Box<int>>(), size_of::<Option<Box<int>>>());

    // The optimization can't apply to raw pointers
    assert!(size_of::<Option<*const int>>() != size_of::<*const int>());
    assert!(Some(0 as *const int).is_some()); // Can't collapse None to null

}
<commit_msg>Add tests.<commit_after>// Copyright 2014 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.

use std::mem::size_of;

trait Trait {}

fn main() {
    // Closures - ||
    assert_eq!(size_of::<||>(), size_of::<Option<||>>());

    // Functions
    assert_eq!(size_of::<fn(int)>(), size_of::<Option<fn(int)>>());
    assert_eq!(size_of::<extern "C" fn(int)>(), size_of::<Option<extern "C" fn(int)>>());

    // Slices - &str / &[T] / &mut [T]
    assert_eq!(size_of::<&str>(), size_of::<Option<&str>>());
    assert_eq!(size_of::<&[int]>(), size_of::<Option<&[int]>>());
    assert_eq!(size_of::<&mut [int]>(), size_of::<Option<&mut [int]>>());

    // Traits - Box<Trait> / &Trait / &mut Trait
    assert_eq!(size_of::<Box<Trait>>(), size_of::<Option<Box<Trait>>>());
    assert_eq!(size_of::<&Trait>(), size_of::<Option<&Trait>>());
    assert_eq!(size_of::<&mut Trait>(), size_of::<Option<&mut Trait>>());

    // Pointers - Box<T>
    assert_eq!(size_of::<Box<int>>(), size_of::<Option<Box<int>>>());

    // The optimization can't apply to raw pointers
    assert!(size_of::<Option<*const int>>() != size_of::<*const int>());
    assert!(Some(0 as *const int).is_some()); // Can't collapse None to null

    struct Foo {
        _a: Box<int>
    }
    struct Bar(Box<int>);

    // Should apply through structs
    assert_eq!(size_of::<Foo>(), size_of::<Option<Foo>>());
    assert_eq!(size_of::<Bar>(), size_of::<Option<Bar>>());
    // and tuples
    assert_eq!(size_of::<(u8, Box<int>)>(), size_of::<Option<(u8, Box<int>)>>());
    // and fixed-size arrays
    assert_eq!(size_of::<[Box<int>, ..1]>(), size_of::<Option<[Box<int>, ..1]>>());

}
<|endoftext|>


<commit_before>// Copyright 2014 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.

#![feature(optin_builtin_traits)]

use std::marker::Send;

struct TestType;

impl TestType {}

trait TestTrait {}

impl !Send for TestType {}
impl !TestTrait for TestType {}

struct TestType2<T>;

impl<T> TestType2<T> {}

impl<T> !Send for TestType2<T> {}
impl<T> !TestTrait for TestType2<T> {}

fn main() {}
<commit_msg>fix latest changes fallout<commit_after>// Copyright 2014 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.

#![feature(optin_builtin_traits)]

use std::marker::Send;

struct TestType;

impl TestType {}

trait TestTrait {}

impl !Send for TestType {}

struct TestType2<T>;

impl<T> TestType2<T> {}

impl<T> !Send for TestType2<T> {}

fn main() {}
<|endoftext|>


<commit_before>extern mod png;

use std::num::{sqrt, min, max, cos, sin};

static WIDTH: int = 800;
static HEIGHT: int = 800;

struct Color {
  r: u8,
  g: u8,
  b: u8
}

static Red: Color = Color { r: 255, g: 0, b: 0 };
static Green: Color = Color { r: 0, g: 255, b: 0 };
static Blue: Color = Color { r: 0, g: 0, b: 255 };
static White: Color = Color { r: 255, g: 255, b: 255 };
static Black: Color = Color { r: 0, g: 0, b: 0 };

struct Point {
  x: f64,
  y: f64,
  z: f64
}

struct Spot {
  pos: Point,
  color: Color,
}

struct Scene {
  eye: Point,
  spot: Spot,
  objects: ~[Shape]
}

fn solve_poly(a: f64, b: f64, c: f64) -> f64 {
  let delta = b.pow(&2.0) - 4. * a * c;

  if delta < 0. {
    return 0.;
  }

  let sign = match c {
    _ if c < 0. => 1.,
    _ => -1.
  };
  let k = (-b + sign * sqrt(delta)) / (2. * a);
  return match k {
    _ if k > 0. => k,
    _ => 0.
  }
}

trait Drawable {
  fn hit(&self, eye: &Point, vector: &Point) -> f64;
  fn perp(&self, inter: &Point) -> ~Point;
}

struct Shape {
  pos: Point,
  shininess: f64,
  color: Color,
  shape: ~Drawable
}

impl Shape {
  fn get_light(&self, spot: &Spot, inter: &Point, light: &Point) -> Color {
    let perp = self.shape.perp(inter);
    let norme_l = sqrt(light.x.pow(&2.) + light.y.pow(&2.) + light.z.pow(&2.));
    let norme_n = sqrt(perp.x.pow(&2.) + perp.y.pow(&2.) + perp.z.pow(&2.));
    let cos_a = (light.x * perp.x + light.y * perp.y + light.z * perp.z) / (norme_l * norme_n);

    if cos_a <= 0. {
      return Black;
    }

    Color {
      r: ((self.color.r as f64) * cos_a * (1. - self.shininess) + (spot.color.r as f64) * cos_a * self.shininess) as u8,
      g: ((self.color.g as f64) * cos_a * (1. - self.shininess) + (spot.color.g as f64) * cos_a * self.shininess) as u8,
      b: ((self.color.b as f64) * cos_a * (1. - self.shininess) + (spot.color.b as f64) * cos_a * self.shininess) as u8
    }
  }
}

struct Sphere {
  radius: f64,
}

impl Drawable for Sphere {
  fn hit(&self, eye: &Point, vector: &Point) -> f64 {
    let a = vector.x.pow(&2.) + vector.y.pow(&2.) + vector.z.pow(&2.);
    let b = 2. * (eye.x * vector.x + eye.y * vector.y + eye.z * vector.z);
    let c = eye.x.pow(&2.) + eye.y.pow(&2.) + eye.z.pow(&2.) - self.radius.pow(&2.);
    return solve_poly(a, b, c);
  }

  fn perp(&self, inter: &Point) -> ~Point {
    ~Point { x: inter.x, y: inter.y, z: inter.z }
  }
}

impl Scene {
  fn get_closest<'a>(&'a self, vector: &'a Point) -> (Option<&'a Shape>, f64) {
    let mut min: f64 = 0.;
    let mut closest: Option<&'a Shape> = None;

    for obj in self.objects.iter() {
      let e = Point { x: self.eye.x - obj.pos.x, y: self.eye.y - obj.pos.y, z: self.eye.z - obj.pos.z };
      let v = Point { x: vector.x, y: vector.y, z: vector.z };
      let k = obj.shape.hit(&e, &v);
      if k != 0. && (min == 0. || k < min) {
        min = k;
        closest = Some(obj);
      }
    }

    return (closest, min);
  }
}

fn main() {
  let mut pixels = ~[Black, ..((WIDTH * HEIGHT) as uint)];

  let scene = ~Scene {
    eye: Point { x: -300., y: 0., z: 200. },
    spot: Spot {
      pos: Point { x: -300., y: 100., z: 200. },
      color: White
    },
    objects: ~[
      Shape {
        pos: Point { x: 0., y: 0., z: 100. },
        shininess: 0.2,
        color: Red,
        shape: ~Sphere { radius: 160. }
      },
    ]
  };

  for x in range(0, WIDTH) {
    for y in range(0, HEIGHT) {
      let vector = ~Point {
        x: 100.,
        y: (WIDTH / 2 - x) as f64,
        z: (HEIGHT / 2 - y) as f64
      };

      let (obj, k) = scene.get_closest(vector);

      if obj.is_none() {
        pixels[y * WIDTH + x] = Black;
      }
      else {
        let closest = obj.unwrap();

        // // Shadow
        // let inter = Point {
        //   x: eye.x + closest * vector.x,
        //   y: eye.y + closest * vector.y,
        //   z: eye.z + closest * vector.z
        // };
        // let light = Point {
        //   x: spot.pos.x - inter.x,
        //   y: spot.pos.y - inter.y,
        //   z: spot.pos.z - inter.z
        // };

        let inter = ~Point {
          x: (scene.eye.x - closest.pos.x) + k * vector.x,
          y: (scene.eye.y - closest.pos.y) + k * vector.y,
          z: (scene.eye.z - closest.pos.z) + k * vector.z
        };
        let light = ~Point {
          x: scene.spot.pos.x - inter.x,
          y: scene.spot.pos.y - inter.y,
          z: scene.spot.pos.z - inter.z
        };

        pixels[y * WIDTH + x] = match k {
          0. => Black,
          _ => closest.get_light(&scene.spot, inter, light)
        }
      }
    }
  }

  let img = png::Image {
    width: WIDTH as u32,
    height: HEIGHT as u32,
    color_type: png::RGB8,
    pixels: pixels.flat_map(|&Color { r, g, b }| { ~[r, g, b] })
  };

  png::store_png(&img, &Path::new("out.png"));
}
<commit_msg>Add plane<commit_after>extern mod png;

use std::num::{sqrt, min, max, cos, sin};

static WIDTH: int = 800;
static HEIGHT: int = 800;

struct Color {
  r: u8,
  g: u8,
  b: u8
}

static Red: Color = Color { r: 255, g: 0, b: 0 };
static Green: Color = Color { r: 0, g: 255, b: 0 };
static Blue: Color = Color { r: 0, g: 0, b: 255 };
static White: Color = Color { r: 255, g: 255, b: 255 };
static Black: Color = Color { r: 0, g: 0, b: 0 };

struct Point {
  x: f64,
  y: f64,
  z: f64
}

struct Spot {
  pos: Point,
  color: Color,
}

struct Scene {
  eye: Point,
  spot: Spot,
  objects: ~[Shape]
}

fn solve_poly(a: f64, b: f64, c: f64) -> f64 {
  let delta = b.pow(&2.0) - 4. * a * c;

  if delta < 0. {
    return 0.;
  }

  let sign = match c {
    _ if c < 0. => 1.,
    _ => -1.
  };
  let k = (-b + sign * sqrt(delta)) / (2. * a);
  return match k {
    _ if k > 0. => k,
    _ => 0.
  }
}

trait Drawable {
  fn hit(&self, eye: &Point, vector: &Point) -> f64;
  fn perp(&self, inter: &Point) -> ~Point;
}

struct Shape {
  pos: Point,
  shininess: f64,
  color: Color,
  shape: ~Drawable
}

impl Shape {
  fn get_light(&self, spot: &Spot, inter: &Point, light: &Point) -> Color {
    let perp = self.shape.perp(inter);
    let norme_l = sqrt(light.x.pow(&2.) + light.y.pow(&2.) + light.z.pow(&2.));
    let norme_n = sqrt(perp.x.pow(&2.) + perp.y.pow(&2.) + perp.z.pow(&2.));
    let cos_a = (light.x * perp.x + light.y * perp.y + light.z * perp.z) / (norme_l * norme_n);

    if cos_a <= 0. {
      return Black;
    }

    Color {
      r: ((self.color.r as f64) * cos_a * (1. - self.shininess) + (spot.color.r as f64) * cos_a * self.shininess) as u8,
      g: ((self.color.g as f64) * cos_a * (1. - self.shininess) + (spot.color.g as f64) * cos_a * self.shininess) as u8,
      b: ((self.color.b as f64) * cos_a * (1. - self.shininess) + (spot.color.b as f64) * cos_a * self.shininess) as u8
    }
  }
}

struct Sphere {
  radius: f64,
}

impl Drawable for Sphere {
  fn hit(&self, eye: &Point, vector: &Point) -> f64 {
    let a = vector.x.pow(&2.) + vector.y.pow(&2.) + vector.z.pow(&2.);
    let b = 2. * (eye.x * vector.x + eye.y * vector.y + eye.z * vector.z);
    let c = eye.x.pow(&2.) + eye.y.pow(&2.) + eye.z.pow(&2.) - self.radius.pow(&2.);
    return solve_poly(a, b, c);
  }

  fn perp(&self, inter: &Point) -> ~Point {
    ~Point { x: inter.x, y: inter.y, z: inter.z }
  }
}

struct Plane;

impl Drawable for Plane {
  fn hit(&self, eye: &Point, vector: &Point) -> f64 {
    match -eye.z / vector.z {
      k if k > 0. => k,
      _ => 0.
    }
  }

  fn perp(&self, inter: &Point) -> ~Point {
    ~Point { x: 0., y: 0., z: 100. }
  }
}

impl Scene {
  fn get_closest<'a>(&'a self, vector: &'a Point) -> (Option<&'a Shape>, f64) {
    let mut min: f64 = 0.;
    let mut closest: Option<&'a Shape> = None;

    for obj in self.objects.iter() {
      let e = Point { x: self.eye.x - obj.pos.x, y: self.eye.y - obj.pos.y, z: self.eye.z - obj.pos.z };
      let v = Point { x: vector.x, y: vector.y, z: vector.z };
      let k = obj.shape.hit(&e, &v);
      if k != 0. && (min == 0. || k < min) {
        min = k;
        closest = Some(obj);
      }
    }

    return (closest, min);
  }
}

fn main() {
  let mut pixels = ~[Black, ..((WIDTH * HEIGHT) as uint)];

  let scene = ~Scene {
    eye: Point { x: -300., y: 0., z: 200. },
    spot: Spot {
      pos: Point { x: -300., y: 100., z: 200. },
      color: White
    },
    objects: ~[
      // Shape {
      //   pos: Point { x: 0., y: 0., z: 100. },
      //   shininess: 0.2,
      //   color: Red,
      //   shape: ~Sphere { radius: 160. }
      // },
      Shape {
        pos: Point { x: 0., y: 0., z: 0.},
        shininess: 0.1,
        color: Green,
        shape: ~Plane
      },
    ]
  };

  for x in range(0, WIDTH) {
    for y in range(0, HEIGHT) {
      let vector = ~Point {
        x: 100.,
        y: (WIDTH / 2 - x) as f64,
        z: (HEIGHT / 2 - y) as f64
      };

      let (obj, k) = scene.get_closest(vector);

      if obj.is_none() {
        pixels[y * WIDTH + x] = Black;
      }
      else {
        let closest = obj.unwrap();

        // // Shadow
        // let inter = Point {
        //   x: eye.x + closest * vector.x,
        //   y: eye.y + closest * vector.y,
        //   z: eye.z + closest * vector.z
        // };
        // let light = Point {
        //   x: spot.pos.x - inter.x,
        //   y: spot.pos.y - inter.y,
        //   z: spot.pos.z - inter.z
        // };

        let inter = ~Point {
          x: (scene.eye.x - closest.pos.x) + k * vector.x,
          y: (scene.eye.y - closest.pos.y) + k * vector.y,
          z: (scene.eye.z - closest.pos.z) + k * vector.z
        };
        let light = ~Point {
          x: scene.spot.pos.x - inter.x,
          y: scene.spot.pos.y - inter.y,
          z: scene.spot.pos.z - inter.z
        };

        pixels[y * WIDTH + x] = match k {
          0. => Black,
          _ => closest.get_light(&scene.spot, inter, light)
        }
      }
    }
  }

  let img = png::Image {
    width: WIDTH as u32,
    height: HEIGHT as u32,
    color_type: png::RGB8,
    pixels: pixels.flat_map(|&Color { r, g, b }| { ~[r, g, b] })
  };

  png::store_png(&img, &Path::new("out.png"));
}
<|endoftext|>


<commit_before>use ffi;
use std::os::raw::c_int;
use std::ptr;
use types::*;
use ffi::MaybeError;
use device::DeviceInfo;

/// Represents the input port of a PortMidi device.
pub struct InputPort {
    stream: *const ffi::PortMidiStream,
    device: ffi::PmDeviceId,
    buffer_size: usize,
}
impl InputPort {
    /// Construct a new `InputPort` for the given device and buffer size.
    ///
    /// If the `device` is not an input device an `Error::NotAnInputDevice` is returned.
    pub fn new(device: DeviceInfo, buffer_size: usize) -> Result<InputPort> {
        if device.is_output() {
            return Err(Error::NotAnInputDevice);
        }
        let raw_stream: *const ffi::PortMidiStream = ptr::null();
        try!(Result::from(unsafe {
            ffi::Pm_OpenInput(&raw_stream as *const *const _,
                              device.id(),
                              ptr::null(), // *inputDriverInfo, not needed for normal operation
                              buffer_size as c_int,
                              ptr::null(), // PmTimeProcPtr, a procedure that returns time in ms
                              ptr::null()) // time_info, a pointer passed to the time procedure
        }));

        Ok(InputPort {
            stream: raw_stream,
            device: device.id(),
            buffer_size: buffer_size,
        })
    }

    /// Returns a `Vec<MidiEvent>` with at most `cnt` elements.
    /// If there was no Midi event available, `None` is returned.
    /// If PortMidi fails to read from the device an `Error::PortMidi(_)` is returned.
    pub fn read_n(&self, cnt: usize) -> Result<Option<Vec<MidiEvent>>> {
        let read_cnt = if cnt > self.buffer_size {
            self.buffer_size as c_int
        } else {
            cnt as c_int
        };
        let mut event_buffer = vec![ffi::PmEvent::default(); self.buffer_size];
        let res = unsafe { ffi::Pm_Read(self.stream, event_buffer.as_mut_ptr(), read_cnt) };
        match ffi::PmError::try_from(res) {
            Ok(event_cnt) => {
                let events = (0..event_cnt as usize)
                                 .map(|i| MidiEvent::from(event_buffer[i].clone()))
                                 .collect::<Vec<MidiEvent>>();
                Ok(Some(events))
            }
            err @ Err(ffi::PmError::PmNoError) => Ok(None),
            Err(err) => return Err(Error::PortMidi(err)),
        }
    }

    /// Reads a single `MidiEvent` if one is avaible.
    ///
    /// A `Result` of `None` means no event was available.
    pub fn read(&mut self) -> Result<Option<MidiEvent>> {
        match self.read_n(1) {
            Ok(Some(mut vec)) => Ok(vec.pop()),
            Ok(_) => Ok(None),
            Err(e) => Err(e),
        }
    }

    /// Polls for available Midi events.
    /// Returns `true` if there are events available, otherwise `false` is returned.
    /// If the polling fails an `Error::PortMidi(_)` is returned.
    pub fn poll(&self) -> Result<bool> {
        let pm_error = unsafe { ffi::Pm_Poll(self.stream) };
        match pm_error {
            ffi::PmError::PmNoError => Ok(false),
            ffi::PmError::PmGotData => Ok(true),
            err @ _ => Err(Error::PortMidi(err)),
        }
    }
}
impl Drop for InputPort {
    fn drop(&mut self) {
        if let Err(err) = Result::from(unsafe { ffi::Pm_Close(self.stream) }) {
            println!("{}", err);
        }
    }
}

/// Representation the output port of a PortMidi device.
pub struct OutputPort {
    stream: *const ffi::PortMidiStream,
    device: ffi::PmDeviceId,
    buffer_size: usize,
}
impl OutputPort {
    /// Construct a new `OutputPort` for the given device and buffer size.
    ///
    /// If the `device` is not an output device an `Error::NotAnOutputDevice` is returned.
    pub fn new(device: DeviceInfo, buffer_size: usize) -> Result<OutputPort> {
        if device.is_input() {
            return Err(Error::NotAnOutputDevice);
        }
        let raw_stream: *const ffi::PortMidiStream = ptr::null();
        try!(Result::from(unsafe {
            ffi::Pm_OpenOutput(&raw_stream as *const *const _,
                               device.id(),
                               ptr::null(), // *inputDriverInfo, not needed for normal operation
                               buffer_size as c_int,
                               ptr::null(), // PmTimeProcPtr, a procedure that returns time in ms,
                               ptr::null(), // time_info, a pointer passed to the time procedure
                               0) //latency
        }));

        Ok(OutputPort {
            stream: raw_stream,
            device: device.id(),
            buffer_size: buffer_size,
        })
    }

    /// Terminates outgoing messages immediately.
    ///
    /// The caller should immediately close the output port, this may
    /// result in transmission of a partial midi message. Note, not all platforms
    /// support abort.
    ///
    /// NOTE: This is unsafe, either mark the device as invalid or try to reopen it afterwards.
    fn abort(&mut self) -> Result<()> {
        Result::from(unsafe { ffi::Pm_Abort(self.stream) })
    }

    /// Write a single `MidiEvent`.
    /// Returns an `Error::PortMidi(_)` if something went wrong.
    pub fn write_event<T: Into<MidiEvent>>(&mut self, midi_event: T) -> Result<()> {
        self.write_events(vec![midi_event])
    }

    /// Write a buffer of midi events to the output port.
    /// Returns an `Error::PortMidi(_)` if something went wrong.
    pub fn write_events<T: Into<MidiEvent>>(&mut self, midi_events: Vec<T>) -> Result<()> {
        let events: Vec<ffi::PmEvent> = midi_events.into_iter()
                                                   .map(|event| event.into().into())
                                                   .collect();
        Result::from(unsafe { ffi::Pm_Write(self.stream, events.as_ptr(), events.len() as c_int) })
    }

    /// Write a single `MidiMessage`.
    /// Returns an `Error::PortMidi(_)` if something went wrong.
    pub fn write_message(&mut self, midi_message: MidiMessage) -> Result<()> {
        Result::from(unsafe { ffi::Pm_WriteShort(self.stream, 0, midi_message.into()) })
    }
}
impl Drop for OutputPort {
    fn drop(&mut self) {
        if let Err(err) = Result::from(unsafe { ffi::Pm_Close(self.stream) }) {
            println!("{}", err);
        }
    }
}
<commit_msg>Remove `abort` function<commit_after>use ffi;
use std::os::raw::c_int;
use std::ptr;
use types::*;
use ffi::MaybeError;
use device::DeviceInfo;

/// Represents the input port of a PortMidi device.
pub struct InputPort {
    stream: *const ffi::PortMidiStream,
    device: ffi::PmDeviceId,
    buffer_size: usize,
}
impl InputPort {
    /// Construct a new `InputPort` for the given device and buffer size.
    ///
    /// If the `device` is not an input device an `Error::NotAnInputDevice` is returned.
    pub fn new(device: DeviceInfo, buffer_size: usize) -> Result<InputPort> {
        if device.is_output() {
            return Err(Error::NotAnInputDevice);
        }
        let raw_stream: *const ffi::PortMidiStream = ptr::null();
        try!(Result::from(unsafe {
            ffi::Pm_OpenInput(&raw_stream as *const *const _,
                              device.id(),
                              ptr::null(), // *inputDriverInfo, not needed for normal operation
                              buffer_size as c_int,
                              ptr::null(), // PmTimeProcPtr, a procedure that returns time in ms
                              ptr::null()) // time_info, a pointer passed to the time procedure
        }));

        Ok(InputPort {
            stream: raw_stream,
            device: device.id(),
            buffer_size: buffer_size,
        })
    }

    /// Returns a `Vec<MidiEvent>` with at most `cnt` elements.
    /// If there was no Midi event available, `None` is returned.
    /// If PortMidi fails to read from the device an `Error::PortMidi(_)` is returned.
    pub fn read_n(&self, cnt: usize) -> Result<Option<Vec<MidiEvent>>> {
        let read_cnt = if cnt > self.buffer_size {
            self.buffer_size as c_int
        } else {
            cnt as c_int
        };
        let mut event_buffer = vec![ffi::PmEvent::default(); self.buffer_size];
        let res = unsafe { ffi::Pm_Read(self.stream, event_buffer.as_mut_ptr(), read_cnt) };
        match ffi::PmError::try_from(res) {
            Ok(event_cnt) => {
                let events = (0..event_cnt as usize)
                                 .map(|i| MidiEvent::from(event_buffer[i].clone()))
                                 .collect::<Vec<MidiEvent>>();
                Ok(Some(events))
            }
            err @ Err(ffi::PmError::PmNoError) => Ok(None),
            Err(err) => return Err(Error::PortMidi(err)),
        }
    }

    /// Reads a single `MidiEvent` if one is avaible.
    ///
    /// A `Result` of `None` means no event was available.
    pub fn read(&mut self) -> Result<Option<MidiEvent>> {
        match self.read_n(1) {
            Ok(Some(mut vec)) => Ok(vec.pop()),
            Ok(_) => Ok(None),
            Err(e) => Err(e),
        }
    }

    /// Polls for available Midi events.
    /// Returns `true` if there are events available, otherwise `false` is returned.
    /// If the polling fails an `Error::PortMidi(_)` is returned.
    pub fn poll(&self) -> Result<bool> {
        let pm_error = unsafe { ffi::Pm_Poll(self.stream) };
        match pm_error {
            ffi::PmError::PmNoError => Ok(false),
            ffi::PmError::PmGotData => Ok(true),
            err @ _ => Err(Error::PortMidi(err)),
        }
    }
}
impl Drop for InputPort {
    fn drop(&mut self) {
        if let Err(err) = Result::from(unsafe { ffi::Pm_Close(self.stream) }) {
            println!("{}", err);
        }
    }
}

/// Representation the output port of a PortMidi device.
pub struct OutputPort {
    stream: *const ffi::PortMidiStream,
    device: ffi::PmDeviceId,
    buffer_size: usize,
}
impl OutputPort {
    /// Construct a new `OutputPort` for the given device and buffer size.
    ///
    /// If the `device` is not an output device an `Error::NotAnOutputDevice` is returned.
    pub fn new(device: DeviceInfo, buffer_size: usize) -> Result<OutputPort> {
        if device.is_input() {
            return Err(Error::NotAnOutputDevice);
        }
        let raw_stream: *const ffi::PortMidiStream = ptr::null();
        try!(Result::from(unsafe {
            ffi::Pm_OpenOutput(&raw_stream as *const *const _,
                               device.id(),
                               ptr::null(), // *inputDriverInfo, not needed for normal operation
                               buffer_size as c_int,
                               ptr::null(), // PmTimeProcPtr, a procedure that returns time in ms,
                               ptr::null(), // time_info, a pointer passed to the time procedure
                               0) //latency
        }));

        Ok(OutputPort {
            stream: raw_stream,
            device: device.id(),
            buffer_size: buffer_size,
        })
    }

    /// Write a single `MidiEvent`.
    /// Returns an `Error::PortMidi(_)` if something went wrong.
    pub fn write_event<T: Into<MidiEvent>>(&mut self, midi_event: T) -> Result<()> {
        self.write_events(vec![midi_event])
    }

    /// Write a buffer of midi events to the output port.
    /// Returns an `Error::PortMidi(_)` if something went wrong.
    pub fn write_events<T: Into<MidiEvent>>(&mut self, midi_events: Vec<T>) -> Result<()> {
        let events: Vec<ffi::PmEvent> = midi_events.into_iter()
                                                   .map(|event| event.into().into())
                                                   .collect();
        Result::from(unsafe { ffi::Pm_Write(self.stream, events.as_ptr(), events.len() as c_int) })
    }

    /// Write a single `MidiMessage`.
    /// Returns an `Error::PortMidi(_)` if something went wrong.
    pub fn write_message(&mut self, midi_message: MidiMessage) -> Result<()> {
        Result::from(unsafe { ffi::Pm_WriteShort(self.stream, 0, midi_message.into()) })
    }
}
impl Drop for OutputPort {
    fn drop(&mut self) {
        if let Err(err) = Result::from(unsafe { ffi::Pm_Close(self.stream) }) {
            println!("{}", err);
        }
    }
}
<|endoftext|>