<commit_before>#[phase(plugin, link)] extern crate log;
extern crate std;

use std::io;
use std::io::fs::PathExtensions;
use std::str;

const MESSAGE_SIZE: uint = 4096;
const LINE_END: u8 = '\n' as u8;

/// Result of PeekCommand, when it was successful
/// Contains message and new offset to specify to peek command
/// for continuous peeking
pub struct PeekResult {
    /// Contains message
    pub message: String,
    /// Contains next offset to be specified to read next message from river
    pub offset: uint
}

impl Clone for PeekResult {
    fn clone(&self) -> PeekResult {
        PeekResult {
            message: self.message.clone(),
            offset: self.offset.clone()
        }
    }

    fn clone_from(&mut self, source: &PeekResult) {
        self.message = source.message.clone();
        self.offset = source.offset.clone();
    }
}

pub struct River {
    path: Path,
    name: String
}

impl River {
    pub fn new(river: &str) -> River {
        River {
            name: river.to_string(),
            path: Path::new(format!("./tmp/rivers/{}", river))
        }
    }

    pub fn push(&self, message: &str) {
        let mut file = self.get_file_for_append();
        let bytes = message.as_bytes();

        match file.write(bytes) {
            Ok(_) => self.write_abundant_bytes(&mut file, bytes.len()),
            Err(err) => self.error("Unable to push message", &err)
        }
    }

    pub fn create_unless_exists(&self) {
        if ! self.path.exists() {
            match io::File::create(&self.path) {
                Ok(_) => {},
                Err(err) => self.error("Unable to create river", &err)
            }
        }
    }

    pub fn peek_at(&self, offset: Option < uint >) -> Option < PeekResult > {
        match self.get_line(offset) {
            Some((actual_offset, message)) => self.form_peek_result(message, actual_offset, offset),
            _ => None
        }
    }

    pub fn destroy(&self) {
        match io::fs::unlink(&self.path) {
            Ok(_) => {},
            Err(err) => self.error(format!("Unable to clear river {}", self.name).as_slice(), &err)
        }
    }

    fn form_peek_result(&self, message: String, actual_offset: uint, offset: Option < uint >) -> Option < PeekResult > {
        match self.are_offsets_match(actual_offset, offset) {
            true => Some(PeekResult {
                message: message.replace("\n", ""),
                offset: actual_offset + 2
            }),
            false => None
        }
    }

    fn get_file_for_append(&self) -> io::IoResult < io::File > {
        self.create_unless_exists();
        io::File::open_mode(&self.path, io::Append, io::Write)
    }

    fn get_file_for_peek(&self) -> io::IoResult < io::File > {
        self.create_unless_exists();
        io::File::open(&self.path)
    }

    fn get_line(&self, offset: Option < uint >) -> Option < (uint, String) > {
        let mut file = self.get_file_for_peek();

        match self.seek_and_read_line(&mut file, offset) {
            Some(string) => Some((self.get_actual_offset(offset).unwrap(), string)),
            _ => None
        }
    }

    fn read_line(&self, file: &mut io::IoResult < io::File >) -> Option < String > {
        let mut buf: Vec < u8 > = vec![];

        self.read_to_buf_until_eol(file, &mut buf);
        self.convert_buf_to_string(buf)
    }

    fn are_offsets_match(&self, actual_offset: uint, offset: Option < uint >) -> bool {
        match offset {
            Some(offset) => actual_offset == offset - 1,
            None => true
        }
    }

    fn abundant_bytes(&self, count: uint) -> Vec < u8 > {
        let mut abundant_bytes: Vec < u8 > = range(0, MESSAGE_SIZE - count).map(|_| { 0 }).collect();
        abundant_bytes[0] = '\n' as u8;
        abundant_bytes
    }

    fn write_abundant_bytes(&self, file: &mut io::IoResult < io::File >, count: uint) {
        match file.write(self.abundant_bytes(count).as_slice()) {
            Ok(_) => {},
            Err(err) => self.error("Unable to push message", &err)
        }
    }

    fn size(&self) -> uint {
        match self.path.stat() {
            Ok(stat) => (stat.size.to_uint().unwrap() + MESSAGE_SIZE - 1) / MESSAGE_SIZE,
            Err(err) => { self.error("unable to get size of river", &err); 0 }
        }
    }

    fn get_actual_offset(&self, offset: Option < uint >) -> Option < uint > {
        let size = self.size();
        let adjusted_offset = match offset {
            Some(offset) => std::cmp::min(size, offset),
            None => size
        };

        match adjusted_offset {
            0 => None,
            offset => Some(offset - 1)
        }
    }

    fn get_seek_offset(&self, offset: Option < uint >) -> Option < i64 > {
        match self.get_actual_offset(offset) {
            Some(offset) => match (offset * MESSAGE_SIZE).to_i64() {
                Some(seek_offset) => Some(seek_offset),
                _ => None
            },
            _ => None
        }
    }

    fn seek_and_read_line(&self, file: &mut io::IoResult < io::File >, offset: Option < uint >) -> Option < String > {
        match self.get_seek_offset(offset) {
            Some(seek_offset) => match file.seek(seek_offset, io::SeekSet) {
                Ok(_) => self.read_line(file),
                _ => None
            },
            _ => None
        }
    }

    fn read_to_buf_until_eol(&self, file: &mut io::IoResult < io::File >, buf: &mut Vec < u8 >) {
        loop {
            if ! self.read_one_byte_to_buf(file, buf) {
                break
            }
        }
    }

    fn read_one_byte_to_buf(&self, file: &mut io::IoResult < io::File >, buf: &mut Vec < u8 >) -> bool {
        match file.read_byte() {
            Ok(LINE_END) => false,
            Ok(byte) => {
                buf.push(byte);
                true
            },
            _ => false
        }
    }

    fn convert_buf_to_string(&self, buf: Vec < u8 >) -> Option < String > {
        match str::from_utf8(buf.as_slice()) {
            Some(string) => Some(string.to_string()),
            _ => None
        }
    }

    #[allow(unused_variables)]
    fn error(&self, message: &str, err: &std::fmt::Show) {
        ()
    }

    #[allow(dead_code)]
    #[allow(unused_variables)]
    fn debug(&self, message: &std::fmt::Show) {
        ()
    }
}
<commit_msg>cleanup: remove dead code<commit_after>#[phase(plugin, link)] extern crate log;
extern crate std;

use std::io;
use std::io::fs::PathExtensions;
use std::str;

const MESSAGE_SIZE: uint = 4096;
const LINE_END: u8 = '\n' as u8;

/// Result of PeekCommand, when it was successful
/// Contains message and new offset to specify to peek command
/// for continuous peeking
pub struct PeekResult {
    /// Contains message
    pub message: String,
    /// Contains next offset to be specified to read next message from river
    pub offset: uint
}

impl Clone for PeekResult {
    fn clone(&self) -> PeekResult {
        PeekResult {
            message: self.message.clone(),
            offset: self.offset.clone()
        }
    }

    fn clone_from(&mut self, source: &PeekResult) {
        self.message = source.message.clone();
        self.offset = source.offset.clone();
    }
}

pub struct River {
    path: Path,
    name: String
}

impl River {
    pub fn new(river: &str) -> River {
        River {
            name: river.to_string(),
            path: Path::new(format!("./tmp/rivers/{}", river))
        }
    }

    pub fn push(&self, message: &str) {
        let mut file = self.get_file_for_append();
        let bytes = message.as_bytes();

        match file.write(bytes) {
            Ok(_) => self.write_abundant_bytes(&mut file, bytes.len()),
            Err(err) => self.error("Unable to push message", &err)
        }
    }

    pub fn create_unless_exists(&self) {
        if ! self.path.exists() {
            match io::File::create(&self.path) {
                Ok(_) => {},
                Err(err) => self.error("Unable to create river", &err)
            }
        }
    }

    pub fn peek_at(&self, offset: Option < uint >) -> Option < PeekResult > {
        match self.get_line(offset) {
            Some((actual_offset, message)) => self.form_peek_result(message, actual_offset, offset),
            _ => None
        }
    }

    pub fn destroy(&self) {
        match io::fs::unlink(&self.path) {
            Ok(_) => {},
            Err(err) => self.error(format!("Unable to clear river {}", self.name).as_slice(), &err)
        }
    }

    fn form_peek_result(&self, message: String, actual_offset: uint, offset: Option < uint >) -> Option < PeekResult > {
        match self.are_offsets_match(actual_offset, offset) {
            true => Some(PeekResult {
                message: message.replace("\n", ""),
                offset: actual_offset + 2
            }),
            false => None
        }
    }

    fn get_file_for_append(&self) -> io::IoResult < io::File > {
        self.create_unless_exists();
        io::File::open_mode(&self.path, io::Append, io::Write)
    }

    fn get_file_for_peek(&self) -> io::IoResult < io::File > {
        self.create_unless_exists();
        io::File::open(&self.path)
    }

    fn get_line(&self, offset: Option < uint >) -> Option < (uint, String) > {
        let mut file = self.get_file_for_peek();

        match self.seek_and_read_line(&mut file, offset) {
            Some(string) => Some((self.get_actual_offset(offset).unwrap(), string)),
            _ => None
        }
    }

    fn read_line(&self, file: &mut io::IoResult < io::File >) -> Option < String > {
        let mut buf: Vec < u8 > = vec![];

        self.read_to_buf_until_eol(file, &mut buf);
        self.convert_buf_to_string(buf)
    }

    fn are_offsets_match(&self, actual_offset: uint, offset: Option < uint >) -> bool {
        match offset {
            Some(offset) => actual_offset == offset - 1,
            None => true
        }
    }

    fn abundant_bytes(&self, count: uint) -> Vec < u8 > {
        let mut abundant_bytes: Vec < u8 > = range(0, MESSAGE_SIZE - count).map(|_| { 0 }).collect();
        abundant_bytes[0] = '\n' as u8;
        abundant_bytes
    }

    fn write_abundant_bytes(&self, file: &mut io::IoResult < io::File >, count: uint) {
        match file.write(self.abundant_bytes(count).as_slice()) {
            Ok(_) => {},
            Err(err) => self.error("Unable to push message", &err)
        }
    }

    fn size(&self) -> uint {
        match self.path.stat() {
            Ok(stat) => (stat.size.to_uint().unwrap() + MESSAGE_SIZE - 1) / MESSAGE_SIZE,
            Err(err) => { self.error("unable to get size of river", &err); 0 }
        }
    }

    fn get_actual_offset(&self, offset: Option < uint >) -> Option < uint > {
        let size = self.size();
        let adjusted_offset = match offset {
            Some(offset) => std::cmp::min(size, offset),
            None => size
        };

        match adjusted_offset {
            0 => None,
            offset => Some(offset - 1)
        }
    }

    fn get_seek_offset(&self, offset: Option < uint >) -> Option < i64 > {
        match self.get_actual_offset(offset) {
            Some(offset) => match (offset * MESSAGE_SIZE).to_i64() {
                Some(seek_offset) => Some(seek_offset),
                _ => None
            },
            _ => None
        }
    }

    fn seek_and_read_line(&self, file: &mut io::IoResult < io::File >, offset: Option < uint >) -> Option < String > {
        match self.get_seek_offset(offset) {
            Some(seek_offset) => match file.seek(seek_offset, io::SeekSet) {
                Ok(_) => self.read_line(file),
                _ => None
            },
            _ => None
        }
    }

    fn read_to_buf_until_eol(&self, file: &mut io::IoResult < io::File >, buf: &mut Vec < u8 >) {
        loop {
            if ! self.read_one_byte_to_buf(file, buf) {
                break
            }
        }
    }

    fn read_one_byte_to_buf(&self, file: &mut io::IoResult < io::File >, buf: &mut Vec < u8 >) -> bool {
        match file.read_byte() {
            Ok(LINE_END) => false,
            Ok(byte) => {
                buf.push(byte);
                true
            },
            _ => false
        }
    }

    fn convert_buf_to_string(&self, buf: Vec < u8 >) -> Option < String > {
        match str::from_utf8(buf.as_slice()) {
            Some(string) => Some(string.to_string()),
            _ => None
        }
    }

    #[allow(unused_variables)]
    fn error(&self, message: &str, err: &std::fmt::Show) {
        ()
    }
}
<|endoftext|>


<commit_before>use std::fmt;
use std::ptr;

pub struct Room {
    pub name: String,
    pub description: String,
    north: *mut Room,
    south: *mut Room,
    east: *mut Room,
    west: *mut Room,
}

fn optional_room<'a>(room: *const Room) -> Option<&'a Room> {
    if room.is_null() {
        None
    } else {
        unsafe {
            Some(&*room)
        }
    }
}

impl Room {
    pub fn new(name: &str, description: &str) -> Room {
        Room {
            name: name.to_string(),
            description: description.to_string(),
            north: ptr::null_mut(),
            south: ptr::null_mut(),
            east: ptr::null_mut(),
            west: ptr::null_mut(),
        }
    }

    pub fn north(&self) -> Option<&Room> {
        optional_room(self.north)
    }

    pub fn south(&self) -> Option<&Room> {
        optional_room(self.south)
    }

    pub fn east(&self) -> Option<&Room> {
        optional_room(self.east)
    }

    pub fn west(&self) -> Option<&Room> {
        optional_room(self.west)
    }

    pub fn doors_description(&self) -> String {
        let mut doors: Vec<&str> = Vec::new();
        if ! self.north.is_null() { doors.push("north"); }
        if ! self.south.is_null() { doors.push("south"); }
        if ! self.east.is_null() { doors.push("east"); }
        if ! self.west.is_null() { doors.push("west"); }

        match doors.len() {
            1 => format!("There is a door to the {}.", doors[0]),
            2 => format!("There are doors to the {} and {}.", doors[0], doors[1]),
            3 => format!("There are doors to the {}, {} and {}.",
                         doors[0], doors[1], doors[2]),
            4 => format!("There are doors in all directions."),
            _ => panic!("Found {} doors in {}!", doors.len(), self.name),
        }
    }

    pub fn print_description_on_entrance(&self) {
        println!("You find yourself in {}.", self.description);
        println!("{}", self.doors_description());
    }

    unsafe fn door_north_leads_to(&mut self, room: *mut Room) {
        self.north = room;
        (*room).south = self;
    }

    unsafe fn door_south_leads_to(&mut self, room: *mut Room) {
        self.south = room;
        (*room).north = self;
    }

    unsafe fn door_east_leads_to(&mut self, room: *mut Room) {
        self.east = room;
        (*room).west = self;
    }

    unsafe fn door_west_leads_to(&mut self, room: *mut Room) {
        self.west = room;
        (*room).east = self;
    }
}

impl fmt::Display for Room {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        write!(formatter, "{}", self.name)
    }
}

pub struct Rooms {
    pub vec: Vec<Box<Room>>,
}

impl Rooms {
    pub fn new() -> Box<Rooms> {
        let mut timmys_bedroom = Box::new(
            Room::new("Timmy's bedroom", "a young boy's bedroom"));
        let mut upstairs_hallway = Box::new(
            Room::new("upstairs hallway", "a hallway"));
        let mut sallys_bedroom = Box::new(
            Room::new("Sally's bedroom", "a teenage girl's bedroom"));
        let mut master_bedroom = Box::new(
            Room::new("master bedroom", "a bedroom with a king sized bed"));
        let mut kids_bathroom = Box::new(
            Room::new("kid's bathroom", "a messy bathroom with towels on the floor"));
        let mut parents_bathroom = Box::new(
            Room::new("parent's bathroom", "a bathroom with a shower"));

        let mut stairway = Box::new(
            Room::new("stairway", "a stairway"));

        let mut downstairs_hallway = Box::new(
            Room::new("downstairs hallway", "a hallway"));
        let mut livingroom = Box::new(
            Room::new("livingroom", "a large room with a comfy sofa and a big TV"));
        let mut kitchen = Box::new(
            Room::new("kitchen", "a large room with a tile floor that smells like food"));

        unsafe {
            timmys_bedroom.door_north_leads_to(&mut *upstairs_hallway);
            timmys_bedroom.door_east_leads_to(&mut *kids_bathroom);
            sallys_bedroom.door_west_leads_to(&mut *upstairs_hallway);
            sallys_bedroom.door_south_leads_to(&mut *kids_bathroom);
            master_bedroom.door_south_leads_to(&mut *upstairs_hallway);
            master_bedroom.door_west_leads_to(&mut *parents_bathroom);
            upstairs_hallway.door_west_leads_to(&mut *stairway);

            stairway.door_north_leads_to(&mut *downstairs_hallway);
            downstairs_hallway.door_north_leads_to(&mut *livingroom);
            downstairs_hallway.door_east_leads_to(&mut *kitchen);
        }

        Box::new(Rooms {
            vec: vec!(timmys_bedroom, upstairs_hallway, sallys_bedroom, master_bedroom,
                      kids_bathroom, parents_bathroom, stairway, downstairs_hallway,
                      livingroom, kitchen),
        })
    }

    pub fn len(&self) -> usize {
        self.vec.len()
    }

    pub fn first_room(&self) -> &Room {
        match self.vec.first() {
            None => panic!("First room is missing!"),
            Some(room) => room,
        }
    }
}

<commit_msg>Nicer code to build up the room graph.<commit_after>use std::fmt;
use std::ptr;
use std::collections::HashMap;

pub struct Room {
    pub name: String,
    pub description: String,
    north: *mut Room,
    south: *mut Room,
    east: *mut Room,
    west: *mut Room,
}

fn optional_room<'a>(room: *const Room) -> Option<&'a Room> {
    if room.is_null() {
        None
    } else {
        unsafe {
            Some(&*room)
        }
    }
}

impl Room {
    pub fn new(name: &str, description: &str) -> Room {
        Room {
            name: name.to_string(),
            description: description.to_string(),
            north: ptr::null_mut(),
            south: ptr::null_mut(),
            east: ptr::null_mut(),
            west: ptr::null_mut(),
        }
    }

    pub fn north(&self) -> Option<&Room> {
        optional_room(self.north)
    }

    pub fn south(&self) -> Option<&Room> {
        optional_room(self.south)
    }

    pub fn east(&self) -> Option<&Room> {
        optional_room(self.east)
    }

    pub fn west(&self) -> Option<&Room> {
        optional_room(self.west)
    }

    pub fn doors_description(&self) -> String {
        let mut doors: Vec<&str> = Vec::new();
        if ! self.north.is_null() { doors.push("north"); }
        if ! self.south.is_null() { doors.push("south"); }
        if ! self.east.is_null() { doors.push("east"); }
        if ! self.west.is_null() { doors.push("west"); }

        match doors.len() {
            1 => format!("There is a door to the {}.", doors[0]),
            2 => format!("There are doors to the {} and {}.", doors[0], doors[1]),
            3 => format!("There are doors to the {}, {} and {}.",
                         doors[0], doors[1], doors[2]),
            4 => format!("There are doors in all directions."),
            _ => panic!("Found {} doors in {}!", doors.len(), self.name),
        }
    }

    pub fn print_description_on_entrance(&self) {
        println!("You find yourself in {}.", self.description);
        println!("{}", self.doors_description());
    }

    unsafe fn door_north_leads_to(&mut self, room: *mut Room) {
        self.north = room;
        (*room).south = self;
    }

    unsafe fn door_south_leads_to(&mut self, room: *mut Room) {
        self.south = room;
        (*room).north = self;
    }

    unsafe fn door_east_leads_to(&mut self, room: *mut Room) {
        self.east = room;
        (*room).west = self;
    }

    unsafe fn door_west_leads_to(&mut self, room: *mut Room) {
        self.west = room;
        (*room).east = self;
    }
}

impl fmt::Display for Room {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        write!(formatter, "{}", self.name)
    }
}

pub struct Rooms {
    pub vec: Vec<Box<Room>>,
}

impl Rooms {
    pub fn new() -> Box<Rooms> {
        let mut rooms = Rooms {
            vec: Vec::new(),
        };

        unsafe {
            let timmys_bedroom = rooms.add_room("Timmy's bedroom", "a young boy's bedroom");
            let upstairs_hallway = rooms.add_room("upstairs hallway", "a hallway");
            (*timmys_bedroom).door_north_leads_to(upstairs_hallway);

            let sallys_bedroom = rooms.add_room("Sally's bedroom",
                                                "a teenage girl's bedroom");
            (*sallys_bedroom).door_west_leads_to(upstairs_hallway);

            let kids_bathroom = rooms.add_room("kid's bathroom",
                                               "a messy bathroom with towels on the floor");
            (*kids_bathroom).door_west_leads_to(timmys_bedroom);
            (*kids_bathroom).door_north_leads_to(sallys_bedroom);

            let master_bedroom = rooms.add_room("master bedroom",
                                                "a bedroom with a king sized bed");
            (*master_bedroom).door_south_leads_to(upstairs_hallway);

            let parents_bathroom = rooms.add_room("parent's bathroom",
                                                  "a bathroom with a shower");
            (*parents_bathroom).door_east_leads_to(master_bedroom);

            let stairway = rooms.add_room("stairway", "a stairway");
            (*stairway).door_east_leads_to(upstairs_hallway);

            let downstairs_hallway = rooms.add_room("downstairs hallway", "a hallway");
            (*downstairs_hallway).door_south_leads_to(stairway);

            let livingroom = rooms.add_room("livingroom",
                                            "a large room with a comfy sofa and a big TV");
            (*livingroom).door_south_leads_to(downstairs_hallway);

            let kitchen = rooms.add_room("kitchen",
                                         "a large room with a tile floor that smells like food");
            (*kitchen).door_west_leads_to(downstairs_hallway);
        }
        Box::new(rooms)
    }

    fn add_room(&mut self, name: &str, description: &str) -> *mut Room {
        self.vec.push(Box::new(Room::new(name, description)));
        &mut **self.vec.last_mut().unwrap()
    }

    pub fn len(&self) -> usize {
        self.vec.len()
    }

    pub fn first_room(&self) -> &Room {
        self.vec.first().expect("first room")
    }
}

<|endoftext|>


<commit_before>extern crate iron;
extern crate serde_json;
extern crate reqwest;
use self::iron::prelude::*;
use self::iron::{status, Request, Response, IronResult};

use util::{EnvVar, read_env_var};
use util::telegram::{register, unregister, send, send_with_reply_markup};
use util::twitter;
use model::telegram;

use std::io::Read;

pub fn telegram(req: &mut Request) -> IronResult<Response> {
    let mut body = String::new();
    req.body
        .read_to_string(&mut body)
        .map_err(|e| IronError::new(e, (status::BadRequest, "Error reading request")))?;
    let update: telegram::Update = serde_json::from_str(&body).unwrap();
    if let Some(msg) = update.message {
        if let Some(txt) = msg.text {
            let is_private = msg.chat.chat_type == "private";
            let identifier = format!("@{}", read_env_var(&EnvVar::Name));
            let has_identifier = txt.find(&identifier).is_some();
            let txt = strip_identifier(&txt);
            if is_private || has_identifier {
                let id = msg.chat.id;
                match txt.as_str() {
                    "/start" => respond_start(id),
                    "/help" => respond_help(id),
                    "/unsubscribe" => respond_unsubscribe(id),
                    "/delays" => respond_delays(id),
                    txt => {
                        if let Ok(num) = txt.parse::<u32>() {
                            respond_num_delays(id, num)
                        } else if is_private {
                            respond_unknown(id)
                        } else {
                            Ok(())
                        }
                    }
                }?;
            }
        }
    }
    Ok(Response::with((status::Ok, "ok")))
}

fn strip_identifier(msg: &str) -> String {
    let identifier = format!("@{}", read_env_var(&EnvVar::Name));
    let msg = if let Some(pos) = msg.find(&identifier) {
        let end = pos + identifier.len();
        msg[..pos].to_owned() + &msg[end..]
    } else {
        msg.to_owned()
    };
    msg.trim().to_owned()
}

fn respond_start(chat_id: i32) -> IronResult<()> {
    let new_registration = register(chat_id).unwrap();
    let msg = if new_registration {
        let acc = read_env_var(&EnvVar::TwitterAcc);
        let tweet = twitter::user_last_tweet(&acc).unwrap();
        format!("Successfully registered!\nLast delay:\n\n{}", tweet)
    } else {
        "This chat has already been registered".to_owned()
    };
    send(chat_id, &msg)?;
    Ok(())
}

fn respond_help(chat_id: i32) -> IronResult<()> {
    send(chat_id,
         "Available commands:\n\
        /start: Subscribes this chat to be notified of SBB delays\n\
        /unsubscribe - Unsubscribes this chat from the delay notifications\n\
        /delays - Shows the last n delays.\n\
        /help: Shows this window")?;
    Ok(())
}

fn respond_unsubscribe(chat_id: i32) -> IronResult<()> {
    let unsubscribed = unregister(chat_id).unwrap();
    let msg = if unsubscribed {
        "Successfully unsubscribed from the delay notifications.\n\
        Use /start to subscribe again"
    } else {
        "This chat was not subscribed to be notified of delays in the first place, silly!\n\
        Use /start if you want to subscribe"
    };
    send(chat_id, msg)?;
    Ok(())
}

fn respond_delays(chat_id: i32) -> IronResult<()> {
    use model::telegram::{InlineKeyboardMarkup, InlineKeyboardButton};
    let mut buttons = Vec::new();
    let mut count = 1;
    for _ in 0..3 {
        let mut row = Vec::new();
        for _ in 0..3 {
            let count_str = format!("{}", count);
            let button = InlineKeyboardButton {
                text: count_str.clone(),
                switch_inline_query_current_chat: Some(count_str),
            };
            row.push(button);
            count += 1;
        }
        buttons.push(row);
    }
    let markup = InlineKeyboardMarkup { inline_keyboard: buttons };
    let msg = "How many of the last delays to you want to look up?";
    let mut s = String::new();
    send_with_reply_markup(chat_id, msg, Some(markup))?.read_to_string(&mut s).unwrap();
    Ok(())
}

fn respond_num_delays(chat_id: i32, delay_count: u32) -> IronResult<()> {
    const MIN: u32 = 1;
    const MAX: u32 = 9;
    if delay_count < MIN || delay_count > MAX {
        let msg = format!("Invalid number of delays selected, \
            please enter a number between {} and {}.",
                          MIN,
                          MAX);
        send(chat_id, &msg)?;
        return Ok(());
    }
    let acc = read_env_var(&EnvVar::TwitterAcc);
    let tweets = twitter::user_timeline(&acc, delay_count).unwrap();
    let mut msg = format!("Showing last {} delays:\n\n", delay_count);
    for (i, tweet) in tweets.iter().enumerate() {
        msg += &format!("{}. {}\n", i + 1, tweet);
    }
    send(chat_id, &msg)?;
    Ok(())
}

fn respond_unknown(chat_id: i32) -> IronResult<()> {
    send(chat_id, "Unknown command. Try using /help")?;
    Ok(())
}
<commit_msg>Text optimization<commit_after>extern crate iron;
extern crate serde_json;
extern crate reqwest;
use self::iron::prelude::*;
use self::iron::{status, Request, Response, IronResult};

use util::{EnvVar, read_env_var};
use util::telegram::{register, unregister, send, send_with_reply_markup};
use util::twitter;
use model::telegram;

use std::io::Read;

pub fn telegram(req: &mut Request) -> IronResult<Response> {
    let mut body = String::new();
    req.body
        .read_to_string(&mut body)
        .map_err(|e| IronError::new(e, (status::BadRequest, "Error reading request")))?;
    let update: telegram::Update = serde_json::from_str(&body).unwrap();
    if let Some(msg) = update.message {
        if let Some(txt) = msg.text {
            let is_private = msg.chat.chat_type == "private";
            let identifier = format!("@{}", read_env_var(&EnvVar::Name));
            let has_identifier = txt.find(&identifier).is_some();
            let txt = strip_identifier(&txt);
            if is_private || has_identifier {
                let id = msg.chat.id;
                match txt.as_str() {
                    "/start" => respond_start(id),
                    "/help" => respond_help(id),
                    "/unsubscribe" => respond_unsubscribe(id),
                    "/delays" => respond_delays(id),
                    txt => {
                        if let Ok(num) = txt.parse::<u32>() {
                            respond_num_delays(id, num)
                        } else if is_private {
                            respond_unknown(id)
                        } else {
                            Ok(())
                        }
                    }
                }?;
            }
        }
    }
    Ok(Response::with((status::Ok, "ok")))
}

fn strip_identifier(msg: &str) -> String {
    let identifier = format!("@{}", read_env_var(&EnvVar::Name));
    let msg = if let Some(pos) = msg.find(&identifier) {
        let end = pos + identifier.len();
        msg[..pos].to_owned() + &msg[end..]
    } else {
        msg.to_owned()
    };
    msg.trim().to_owned()
}

fn respond_start(chat_id: i32) -> IronResult<()> {
    let new_registration = register(chat_id).unwrap();
    let msg = if new_registration {
        let acc = read_env_var(&EnvVar::TwitterAcc);
        let tweet = twitter::user_last_tweet(&acc).unwrap();
        format!("Successfully registered!\nLast delay:\n\n{}", tweet)
    } else {
        "This chat has already been registered".to_owned()
    };
    send(chat_id, &msg)?;
    Ok(())
}

fn respond_help(chat_id: i32) -> IronResult<()> {
    send(chat_id,
         "Available commands:\n\n\
        /start - Subscribes this chat to be notified of SBB delays\n\
        /unsubscribe - Unsubscribes this chat from the delay notifications\n\
        /delays - Shows the last `n` delays\n\
        /help - Shows this window")?;
    Ok(())
}

fn respond_unsubscribe(chat_id: i32) -> IronResult<()> {
    let unsubscribed = unregister(chat_id).unwrap();
    let msg = if unsubscribed {
        "Successfully unsubscribed from the delay notifications.\n\
        Use /start to subscribe again"
    } else {
        "This chat was not subscribed to be notified of delays in the first place, silly!\n\
        Use /start if you want to subscribe"
    };
    send(chat_id, msg)?;
    Ok(())
}

fn respond_delays(chat_id: i32) -> IronResult<()> {
    use model::telegram::{InlineKeyboardMarkup, InlineKeyboardButton};
    let mut buttons = Vec::new();
    let mut count = 1;
    for _ in 0..3 {
        let mut row = Vec::new();
        for _ in 0..3 {
            let count_str = format!("{}", count);
            let button = InlineKeyboardButton {
                text: count_str.clone(),
                switch_inline_query_current_chat: Some(count_str),
            };
            row.push(button);
            count += 1;
        }
        buttons.push(row);
    }
    let markup = InlineKeyboardMarkup { inline_keyboard: buttons };
    let msg = "How many of the last delays to you want to look up?";
    let mut s = String::new();
    send_with_reply_markup(chat_id, msg, Some(markup))?.read_to_string(&mut s).unwrap();
    Ok(())
}

fn respond_num_delays(chat_id: i32, delay_count: u32) -> IronResult<()> {
    const MIN: u32 = 1;
    const MAX: u32 = 9;
    if delay_count < MIN || delay_count > MAX {
        let msg = format!("Invalid number of delays selected, \
            please enter a number between {} and {}.",
                          MIN,
                          MAX);
        send(chat_id, &msg)?;
        return Ok(());
    }
    let acc = read_env_var(&EnvVar::TwitterAcc);
    let tweets = twitter::user_timeline(&acc, delay_count).unwrap();
    let mut msg = format!("Showing last {} delays:\n\n", delay_count);
    for (i, tweet) in tweets.iter().enumerate() {
        msg += &format!("{}. {}\n", i + 1, tweet);
    }
    send(chat_id, &msg)?;
    Ok(())
}

fn respond_unknown(chat_id: i32) -> IronResult<()> {
    send(chat_id, "Unknown command. Try using /help")?;
    Ok(())
}
<|endoftext|>


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

use crate::num::One;

use crate::{Point2D, Rect, Size2D, Vector2D};
use core::cmp::Ordering;
use core::fmt;
use core::hash::{Hash, Hasher};
use core::marker::PhantomData;
use core::ops::{Add, Div, Mul, Neg, Sub};
use num_traits::NumCast;
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};

/// A scaling factor between two different units of measurement.
///
/// This is effectively a type-safe float, intended to be used in combination with other types like
/// `length::Length` to enforce conversion between systems of measurement at compile time.
///
/// `Src` and `Dst` represent the units before and after multiplying a value by a `Scale`. They
/// may be types without values, such as empty enums.  For example:
///
/// ```rust
/// use euclid::Scale;
/// use euclid::Length;
/// enum Mm {};
/// enum Inch {};
///
/// let mm_per_inch: Scale<f32, Inch, Mm> = Scale::new(25.4);
///
/// let one_foot: Length<f32, Inch> = Length::new(12.0);
/// let one_foot_in_mm: Length<f32, Mm> = one_foot * mm_per_inch;
/// ```
#[repr(C)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(
    feature = "serde",
    serde(bound(
        serialize = "T: serde::Serialize",
        deserialize = "T: serde::Deserialize<'de>"
    ))
)]
pub struct Scale<T, Src, Dst>(pub T, #[doc(hidden)] pub PhantomData<(Src, Dst)>);

impl<T, Src, Dst> Scale<T, Src, Dst> {
    #[inline]
    pub const fn new(x: T) -> Self {
        Scale(x, PhantomData)
    }

    /// Returns the given point transformed by this scale.
    ///
    /// # Example
    ///
    /// ```rust
    /// use euclid::{Scale, point2};
    /// enum Mm {};
    /// enum Cm {};
    ///
    /// let to_mm: Scale<i32, Cm, Mm> = Scale::new(10);
    ///
    /// assert_eq!(to_mm.transform_point(point2(42, -42)), point2(420, -420));
    /// ```
    #[inline]
    pub fn transform_point(&self, point: Point2D<T, Src>) -> Point2D<T::Output, Dst>
    where
        T: Clone + Mul,
    {
        Point2D::new(point.x * self.get(), point.y * self.get())
    }

    /// Returns the given vector transformed by this scale.
    ///
    /// # Example
    ///
    /// ```rust
    /// use euclid::{Scale, vec2};
    /// enum Mm {};
    /// enum Cm {};
    ///
    /// let to_mm: Scale<i32, Cm, Mm> = Scale::new(10);
    ///
    /// assert_eq!(to_mm.transform_vector(vec2(42, -42)), vec2(420, -420));
    /// ```
    #[inline]
    pub fn transform_vector(&self, vec: Vector2D<T, Src>) -> Vector2D<T::Output, Dst>
    where
        T: Clone + Mul,
    {
        Vector2D::new(vec.x * self.get(), vec.y * self.get())
    }

    /// Returns the given vector transformed by this scale.
    ///
    /// # Example
    ///
    /// ```rust
    /// use euclid::{Scale, size2};
    /// enum Mm {};
    /// enum Cm {};
    ///
    /// let to_mm: Scale<i32, Cm, Mm> = Scale::new(10);
    ///
    /// assert_eq!(to_mm.transform_size(size2(42, -42)), size2(420, -420));
    /// ```
    #[inline]
    pub fn transform_size(&self, size: Size2D<T, Src>) -> Size2D<T::Output, Dst>
    where
        T: Clone + Mul,
    {
        Size2D::new(size.width * self.get(), size.height * self.get())
    }

    /// Returns the given rect transformed by this scale.
    ///
    /// # Example
    ///
    /// ```rust
    /// use euclid::{Scale, rect};
    /// enum Mm {};
    /// enum Cm {};
    ///
    /// let to_mm: Scale<i32, Cm, Mm> = Scale::new(10);
    ///
    /// assert_eq!(to_mm.transform_rect(&rect(1, 2, 42, -42)), rect(10, 20, 420, -420));
    /// ```
    #[inline]
    pub fn transform_rect(&self, rect: &Rect<T, Src>) -> Rect<T::Output, Dst>
    where
        T: Copy + Mul,
    {
        Rect::new(
            self.transform_point(rect.origin),
            self.transform_size(rect.size),
        )
    }

    /// Returns the inverse of this scale.
    #[inline]
    pub fn inverse(&self) -> Scale<T::Output, Dst, Src>
    where
        T: Clone + Neg,
    {
        Scale::new(-self.get())
    }

    /// Returns `true` if this scale has no effect.
    ///
    /// # Example
    ///
    /// ```rust
    /// use euclid::Scale;
    /// use euclid::num::One;
    /// enum Mm {};
    /// enum Cm {};
    ///
    /// let cm_per_mm: Scale<f32, Mm, Cm> = Scale::new(0.1);
    /// let mm_per_mm: Scale<f32, Mm, Mm> = Scale::new(1.0);
    ///
    /// assert_eq!(cm_per_mm.is_identity(), false);
    /// assert_eq!(mm_per_mm.is_identity(), true);
    /// assert_eq!(mm_per_mm, Scale::one());
    /// ```
    #[inline]
    pub fn is_identity(&self) -> bool
    where
        T: PartialEq + One,
    {
        self.0 == T::one()
    }
}

impl<T: Clone, Src, Dst> Scale<T, Src, Dst> {
    #[inline]
    pub fn get(&self) -> T {
        self.0.clone()
    }

    /// The inverse Scale (1.0 / self).
    ///
    /// # Example
    ///
    /// ```rust
    /// use euclid::Scale;
    /// enum Mm {};
    /// enum Cm {};
    ///
    /// let cm_per_mm: Scale<f32, Cm, Mm> = Scale::new(0.1);
    ///
    /// assert_eq!(cm_per_mm.inv(), Scale::new(10.0));
    /// ```
    pub fn inv(&self) -> Scale<T::Output, Dst, Src>
    where
        T: One + Div,
    {
        let one: T = One::one();
        Scale::new(one / self.0.clone())
    }
}

impl<T: NumCast + Clone, Src, Dst> Scale<T, Src, Dst> {
    /// Cast from one numeric representation to another, preserving the units.
    ///
    /// # Panics
    ///
    /// If the source value cannot be represented by the target type `NewT`, then
    /// method panics. Use `try_cast` if that must be case.
    ///
    /// # Example
    ///
    /// ```rust
    /// use euclid::Scale;
    /// enum Mm {};
    /// enum Cm {};
    ///
    /// let to_mm: Scale<i32, Cm, Mm> = Scale::new(10);
    ///
    /// assert_eq!(to_mm.cast::<f32>(), Scale::new(10.0));
    /// ```
    /// That conversion will panic, because `i32` not enough to store such big numbers:
    /// ```rust,should_panic
    /// use euclid::Scale;
    /// enum Mm {};// millimeter = 10^-2 meters
    /// enum Em {};// exameter   = 10^18 meters
    ///
    /// // Panics
    /// let to_em: Scale<i32, Mm, Em> = Scale::new(10e20).cast();
    /// ```
    #[inline]
    pub fn cast<NewT: NumCast>(&self) -> Scale<NewT, Src, Dst> {
        self.try_cast().unwrap()
    }

    /// Fallible cast from one numeric representation to another, preserving the units.
    /// If the source value cannot be represented by the target type `NewT`, then `None`
    /// is returned.
    ///
    /// # Example
    ///
    /// ```rust
    /// use euclid::Scale;
    /// enum Mm {};
    /// enum Cm {};
    /// enum Em {};// Exameter = 10^18 meters
    ///
    /// let to_mm: Scale<i32, Cm, Mm> = Scale::new(10);
    /// let to_em: Scale<f32, Mm, Em> = Scale::new(10e20);
    ///
    /// assert_eq!(to_mm.try_cast::<f32>(), Some(Scale::new(10.0)));
    /// // Integer to small to store that number
    /// assert_eq!(to_em.try_cast::<i32>(), None);
    /// ```
    pub fn try_cast<NewT: NumCast>(&self) -> Option<Scale<NewT, Src, Dst>> {
        NumCast::from(self.get()).map(Scale::new)
    }
}

impl<Src, Dst> Scale<f32, Src, Dst> {
    /// Identity scaling, could be used to safely transit from one space to another.
    pub const ONE: Self = Scale(1.0, PhantomData);
}

// scale0 * scale1
// (A,B) * (B,C) = (A,C)
impl<T: Mul, A, B, C> Mul<Scale<T, B, C>> for Scale<T, A, B> {
    type Output = Scale<T::Output, A, C>;

    #[inline]
    fn mul(self, other: Scale<T, B, C>) -> Self::Output {
        Scale::new(self.0 * other.0)
    }
}

// scale0 + scale1
impl<T: Add, Src, Dst> Add for Scale<T, Src, Dst> {
    type Output = Scale<T::Output, Src, Dst>;

    #[inline]
    fn add(self, other: Scale<T, Src, Dst>) -> Self::Output {
        Scale::new(self.0 + other.0)
    }
}

// scale0 - scale1
impl<T: Sub, Src, Dst> Sub for Scale<T, Src, Dst> {
    type Output = Scale<T::Output, Src, Dst>;

    #[inline]
    fn sub(self, other: Scale<T, Src, Dst>) -> Self::Output {
        Scale::new(self.0 - other.0)
    }
}

// FIXME: Switch to `derive(PartialEq, Clone)` after this Rust issue is fixed:
// https://github.com/rust-lang/rust/issues/26925

impl<T: PartialEq, Src, Dst> PartialEq for Scale<T, Src, Dst> {
    fn eq(&self, other: &Scale<T, Src, Dst>) -> bool {
        self.0 == other.0
    }
}

impl<T: Eq, Src, Dst> Eq for Scale<T, Src, Dst> {}

impl<T: PartialOrd, Src, Dst> PartialOrd for Scale<T, Src, Dst> {
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        self.0.partial_cmp(&other.0)
    }
}

impl<T: Ord, Src, Dst> Ord for Scale<T, Src, Dst> {
    fn cmp(&self, other: &Self) -> Ordering {
        self.0.cmp(&other.0)
    }
}

impl<T: Clone, Src, Dst> Clone for Scale<T, Src, Dst> {
    fn clone(&self) -> Scale<T, Src, Dst> {
        Scale::new(self.get())
    }
}

impl<T: Copy, Src, Dst> Copy for Scale<T, Src, Dst> {}

impl<T: fmt::Debug, Src, Dst> fmt::Debug for Scale<T, Src, Dst> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.0.fmt(f)
    }
}

impl<T: Default, Src, Dst> Default for Scale<T, Src, Dst> {
    fn default() -> Self {
        Self::new(T::default())
    }
}

impl<T: Hash, Src, Dst> Hash for Scale<T, Src, Dst> {
    fn hash<H: Hasher>(&self, state: &mut H) {
        self.0.hash(state)
    }
}

impl<T: One, Src, Dst> One for Scale<T, Src, Dst> {
    #[inline]
    fn one() -> Self {
        Scale::new(T::one())
    }
}

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

    enum Inch {}
    enum Cm {}
    enum Mm {}

    #[test]
    fn test_scale() {
        let mm_per_inch: Scale<f32, Inch, Mm> = Scale::new(25.4);
        let cm_per_mm: Scale<f32, Mm, Cm> = Scale::new(0.1);

        let mm_per_cm: Scale<f32, Cm, Mm> = cm_per_mm.inv();
        assert_eq!(mm_per_cm.get(), 10.0);

        let one: Scale<f32, Mm, Mm> = cm_per_mm * mm_per_cm;
        assert_eq!(one.get(), 1.0);

        let one: Scale<f32, Cm, Cm> = mm_per_cm * cm_per_mm;
        assert_eq!(one.get(), 1.0);

        let cm_per_inch: Scale<f32, Inch, Cm> = mm_per_inch * cm_per_mm;
        //  mm     cm     cm
        // ---- x ---- = ----
        // inch    mm    inch
        assert_eq!(cm_per_inch, Scale::new(2.54));

        let a: Scale<isize, Inch, Inch> = Scale::new(2);
        let b: Scale<isize, Inch, Inch> = Scale::new(3);
        assert_ne!(a, b);
        assert_eq!(a, a.clone());
        assert_eq!(a.clone() + b.clone(), Scale::new(5));
        assert_eq!(a - b, Scale::new(-1));
    }
}
<commit_msg>Auto merge of #445 - nical:inverse, r=kvark<commit_after>// Copyright 2014 The Servo Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//! A type-checked scaling factor between units.

use crate::num::One;

use crate::{Point2D, Rect, Size2D, Vector2D};
use core::cmp::Ordering;
use core::fmt;
use core::hash::{Hash, Hasher};
use core::marker::PhantomData;
use core::ops::{Add, Div, Mul, Sub};
use num_traits::NumCast;
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};

/// A scaling factor between two different units of measurement.
///
/// This is effectively a type-safe float, intended to be used in combination with other types like
/// `length::Length` to enforce conversion between systems of measurement at compile time.
///
/// `Src` and `Dst` represent the units before and after multiplying a value by a `Scale`. They
/// may be types without values, such as empty enums.  For example:
///
/// ```rust
/// use euclid::Scale;
/// use euclid::Length;
/// enum Mm {};
/// enum Inch {};
///
/// let mm_per_inch: Scale<f32, Inch, Mm> = Scale::new(25.4);
///
/// let one_foot: Length<f32, Inch> = Length::new(12.0);
/// let one_foot_in_mm: Length<f32, Mm> = one_foot * mm_per_inch;
/// ```
#[repr(C)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(
    feature = "serde",
    serde(bound(
        serialize = "T: serde::Serialize",
        deserialize = "T: serde::Deserialize<'de>"
    ))
)]
pub struct Scale<T, Src, Dst>(pub T, #[doc(hidden)] pub PhantomData<(Src, Dst)>);

impl<T, Src, Dst> Scale<T, Src, Dst> {
    #[inline]
    pub const fn new(x: T) -> Self {
        Scale(x, PhantomData)
    }

    /// Returns the given point transformed by this scale.
    ///
    /// # Example
    ///
    /// ```rust
    /// use euclid::{Scale, point2};
    /// enum Mm {};
    /// enum Cm {};
    ///
    /// let to_mm: Scale<i32, Cm, Mm> = Scale::new(10);
    ///
    /// assert_eq!(to_mm.transform_point(point2(42, -42)), point2(420, -420));
    /// ```
    #[inline]
    pub fn transform_point(&self, point: Point2D<T, Src>) -> Point2D<T::Output, Dst>
    where
        T: Clone + Mul,
    {
        Point2D::new(point.x * self.get(), point.y * self.get())
    }

    /// Returns the given vector transformed by this scale.
    ///
    /// # Example
    ///
    /// ```rust
    /// use euclid::{Scale, vec2};
    /// enum Mm {};
    /// enum Cm {};
    ///
    /// let to_mm: Scale<i32, Cm, Mm> = Scale::new(10);
    ///
    /// assert_eq!(to_mm.transform_vector(vec2(42, -42)), vec2(420, -420));
    /// ```
    #[inline]
    pub fn transform_vector(&self, vec: Vector2D<T, Src>) -> Vector2D<T::Output, Dst>
    where
        T: Clone + Mul,
    {
        Vector2D::new(vec.x * self.get(), vec.y * self.get())
    }

    /// Returns the given vector transformed by this scale.
    ///
    /// # Example
    ///
    /// ```rust
    /// use euclid::{Scale, size2};
    /// enum Mm {};
    /// enum Cm {};
    ///
    /// let to_mm: Scale<i32, Cm, Mm> = Scale::new(10);
    ///
    /// assert_eq!(to_mm.transform_size(size2(42, -42)), size2(420, -420));
    /// ```
    #[inline]
    pub fn transform_size(&self, size: Size2D<T, Src>) -> Size2D<T::Output, Dst>
    where
        T: Clone + Mul,
    {
        Size2D::new(size.width * self.get(), size.height * self.get())
    }

    /// Returns the given rect transformed by this scale.
    ///
    /// # Example
    ///
    /// ```rust
    /// use euclid::{Scale, rect};
    /// enum Mm {};
    /// enum Cm {};
    ///
    /// let to_mm: Scale<i32, Cm, Mm> = Scale::new(10);
    ///
    /// assert_eq!(to_mm.transform_rect(&rect(1, 2, 42, -42)), rect(10, 20, 420, -420));
    /// ```
    #[inline]
    pub fn transform_rect(&self, rect: &Rect<T, Src>) -> Rect<T::Output, Dst>
    where
        T: Copy + Mul,
    {
        Rect::new(
            self.transform_point(rect.origin),
            self.transform_size(rect.size),
        )
    }

    /// Returns `true` if this scale has no effect.
    ///
    /// # Example
    ///
    /// ```rust
    /// use euclid::Scale;
    /// use euclid::num::One;
    /// enum Mm {};
    /// enum Cm {};
    ///
    /// let cm_per_mm: Scale<f32, Mm, Cm> = Scale::new(0.1);
    /// let mm_per_mm: Scale<f32, Mm, Mm> = Scale::new(1.0);
    ///
    /// assert_eq!(cm_per_mm.is_identity(), false);
    /// assert_eq!(mm_per_mm.is_identity(), true);
    /// assert_eq!(mm_per_mm, Scale::one());
    /// ```
    #[inline]
    pub fn is_identity(&self) -> bool
    where
        T: PartialEq + One,
    {
        self.0 == T::one()
    }
}

impl<T: Clone, Src, Dst> Scale<T, Src, Dst> {
    #[inline]
    pub fn get(&self) -> T {
        self.0.clone()
    }

    /// The inverse Scale (1.0 / self).
    ///
    /// # Example
    ///
    /// ```rust
    /// use euclid::Scale;
    /// enum Mm {};
    /// enum Cm {};
    ///
    /// let cm_per_mm: Scale<f32, Cm, Mm> = Scale::new(0.1);
    ///
    /// assert_eq!(cm_per_mm.inverse(), Scale::new(10.0));
    /// ```
    pub fn inverse(&self) -> Scale<T::Output, Dst, Src>
    where
        T: One + Div,
    {
        let one: T = One::one();
        Scale::new(one / self.0.clone())
    }
}

impl<T: NumCast + Clone, Src, Dst> Scale<T, Src, Dst> {
    /// Cast from one numeric representation to another, preserving the units.
    ///
    /// # Panics
    ///
    /// If the source value cannot be represented by the target type `NewT`, then
    /// method panics. Use `try_cast` if that must be case.
    ///
    /// # Example
    ///
    /// ```rust
    /// use euclid::Scale;
    /// enum Mm {};
    /// enum Cm {};
    ///
    /// let to_mm: Scale<i32, Cm, Mm> = Scale::new(10);
    ///
    /// assert_eq!(to_mm.cast::<f32>(), Scale::new(10.0));
    /// ```
    /// That conversion will panic, because `i32` not enough to store such big numbers:
    /// ```rust,should_panic
    /// use euclid::Scale;
    /// enum Mm {};// millimeter = 10^-2 meters
    /// enum Em {};// exameter   = 10^18 meters
    ///
    /// // Panics
    /// let to_em: Scale<i32, Mm, Em> = Scale::new(10e20).cast();
    /// ```
    #[inline]
    pub fn cast<NewT: NumCast>(&self) -> Scale<NewT, Src, Dst> {
        self.try_cast().unwrap()
    }

    /// Fallible cast from one numeric representation to another, preserving the units.
    /// If the source value cannot be represented by the target type `NewT`, then `None`
    /// is returned.
    ///
    /// # Example
    ///
    /// ```rust
    /// use euclid::Scale;
    /// enum Mm {};
    /// enum Cm {};
    /// enum Em {};// Exameter = 10^18 meters
    ///
    /// let to_mm: Scale<i32, Cm, Mm> = Scale::new(10);
    /// let to_em: Scale<f32, Mm, Em> = Scale::new(10e20);
    ///
    /// assert_eq!(to_mm.try_cast::<f32>(), Some(Scale::new(10.0)));
    /// // Integer to small to store that number
    /// assert_eq!(to_em.try_cast::<i32>(), None);
    /// ```
    pub fn try_cast<NewT: NumCast>(&self) -> Option<Scale<NewT, Src, Dst>> {
        NumCast::from(self.get()).map(Scale::new)
    }
}

impl<Src, Dst> Scale<f32, Src, Dst> {
    /// Identity scaling, could be used to safely transit from one space to another.
    pub const ONE: Self = Scale(1.0, PhantomData);
}

// scale0 * scale1
// (A,B) * (B,C) = (A,C)
impl<T: Mul, A, B, C> Mul<Scale<T, B, C>> for Scale<T, A, B> {
    type Output = Scale<T::Output, A, C>;

    #[inline]
    fn mul(self, other: Scale<T, B, C>) -> Self::Output {
        Scale::new(self.0 * other.0)
    }
}

// scale0 + scale1
impl<T: Add, Src, Dst> Add for Scale<T, Src, Dst> {
    type Output = Scale<T::Output, Src, Dst>;

    #[inline]
    fn add(self, other: Scale<T, Src, Dst>) -> Self::Output {
        Scale::new(self.0 + other.0)
    }
}

// scale0 - scale1
impl<T: Sub, Src, Dst> Sub for Scale<T, Src, Dst> {
    type Output = Scale<T::Output, Src, Dst>;

    #[inline]
    fn sub(self, other: Scale<T, Src, Dst>) -> Self::Output {
        Scale::new(self.0 - other.0)
    }
}

// FIXME: Switch to `derive(PartialEq, Clone)` after this Rust issue is fixed:
// https://github.com/rust-lang/rust/issues/26925

impl<T: PartialEq, Src, Dst> PartialEq for Scale<T, Src, Dst> {
    fn eq(&self, other: &Scale<T, Src, Dst>) -> bool {
        self.0 == other.0
    }
}

impl<T: Eq, Src, Dst> Eq for Scale<T, Src, Dst> {}

impl<T: PartialOrd, Src, Dst> PartialOrd for Scale<T, Src, Dst> {
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        self.0.partial_cmp(&other.0)
    }
}

impl<T: Ord, Src, Dst> Ord for Scale<T, Src, Dst> {
    fn cmp(&self, other: &Self) -> Ordering {
        self.0.cmp(&other.0)
    }
}

impl<T: Clone, Src, Dst> Clone for Scale<T, Src, Dst> {
    fn clone(&self) -> Scale<T, Src, Dst> {
        Scale::new(self.get())
    }
}

impl<T: Copy, Src, Dst> Copy for Scale<T, Src, Dst> {}

impl<T: fmt::Debug, Src, Dst> fmt::Debug for Scale<T, Src, Dst> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.0.fmt(f)
    }
}

impl<T: Default, Src, Dst> Default for Scale<T, Src, Dst> {
    fn default() -> Self {
        Self::new(T::default())
    }
}

impl<T: Hash, Src, Dst> Hash for Scale<T, Src, Dst> {
    fn hash<H: Hasher>(&self, state: &mut H) {
        self.0.hash(state)
    }
}

impl<T: One, Src, Dst> One for Scale<T, Src, Dst> {
    #[inline]
    fn one() -> Self {
        Scale::new(T::one())
    }
}

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

    enum Inch {}
    enum Cm {}
    enum Mm {}

    #[test]
    fn test_scale() {
        let mm_per_inch: Scale<f32, Inch, Mm> = Scale::new(25.4);
        let cm_per_mm: Scale<f32, Mm, Cm> = Scale::new(0.1);

        let mm_per_cm: Scale<f32, Cm, Mm> = cm_per_mm.inverse();
        assert_eq!(mm_per_cm.get(), 10.0);

        let one: Scale<f32, Mm, Mm> = cm_per_mm * mm_per_cm;
        assert_eq!(one.get(), 1.0);

        let one: Scale<f32, Cm, Cm> = mm_per_cm * cm_per_mm;
        assert_eq!(one.get(), 1.0);

        let cm_per_inch: Scale<f32, Inch, Cm> = mm_per_inch * cm_per_mm;
        //  mm     cm     cm
        // ---- x ---- = ----
        // inch    mm    inch
        assert_eq!(cm_per_inch, Scale::new(2.54));

        let a: Scale<isize, Inch, Inch> = Scale::new(2);
        let b: Scale<isize, Inch, Inch> = Scale::new(3);
        assert_ne!(a, b);
        assert_eq!(a, a.clone());
        assert_eq!(a.clone() + b.clone(), Scale::new(5));
        assert_eq!(a - b, Scale::new(-1));
    }
}
<|endoftext|>


<commit_before>use main::{WINDOW_WIDTH, WINDOW_HEIGHT, RGB};
use opencl;
use opencl::mem::CLBuffer;

pub struct Scene {
  pub center: [f32; 3],
  pub radius: f32,
  pub camera: [f32; 3],
}

impl Scene {
  pub fn render(&self) -> Vec<RGB> {
    let (device, ctx, queue) = opencl::util::create_compute_context().unwrap();

    let len = WINDOW_WIDTH as usize * WINDOW_HEIGHT as usize;

    let output_buffer: CLBuffer<RGB> = ctx.create_buffer(len, opencl::cl::CL_MEM_WRITE_ONLY);

    let program = {
      let ker = format!("
        float toi(
          const float3 eye,
          const float3 look,

          const float3 sphere,
          const float radius)
        {{
          float a = dot(radius, radius);
          float b = 2 * dot(eye - sphere, look);
          float c = dot(sphere, sphere) + dot(eye, eye) - dot(eye, sphere) - radius * radius;

          float d = b*b - 4*a*c;

          if (d < 0) {{
            return -1;
          }}

          return (-sqrt(d) - b) / (2 * a);
        }}

        __kernel void render(
          const float3 obj_center,
          const float obj_radius,

          const float3 eye,

          __global float * output)
        {{
          int W = {};
          int H = {};

          float fov_x = 3.14 / 2;
          float fov_y = 3.14 / 2;

          int i = get_global_id(0);

          float x_pix = i % W;
          float y_pix = i / W;

          float t_x = fov_x * (x_pix / W - 0.5);
          float t_y = fov_y * (y_pix / H - 0.5);

          float c = cos(t_y);
          float3 ray = {{c*sin(t_x), sin(t_y), -c*cos(t_x)}};

          i = i * 3;
          if (toi(eye, ray, obj_center, obj_radius) >= 0) {{
            output[i+0] = 1;
            output[i+1] = 0;
            output[i+2] = 0;
          }} else {{
            output[i+0] = 0;
            output[i+1] = 0;
            output[i+2] = 0;
          }}
        }}",
        WINDOW_WIDTH,
        WINDOW_HEIGHT,
      );
      ctx.create_program_from_source(ker.as_slice())
    };
    program.build(&device).unwrap();

    let kernel = program.create_kernel("render");
    kernel.set_arg(0, &self.center);
    kernel.set_arg(1, &self.radius);
    kernel.set_arg(2, &self.camera);

    // This is sketchy; we "implicitly cast" output_buffer from a CLBuffer<RGB> to a CLBuffer<f32>.
    kernel.set_arg(3, &output_buffer);

    let event = queue.enqueue_async_kernel(&kernel, len, None, ());

    queue.get(&output_buffer, &event)
  }
}
<commit_msg>TOI returns infinity on no intersection.<commit_after>use main::{WINDOW_WIDTH, WINDOW_HEIGHT, RGB};
use opencl;
use opencl::mem::CLBuffer;

pub struct Scene {
  pub center: [f32; 3],
  pub radius: f32,
  pub camera: [f32; 3],
}

impl Scene {
  pub fn render(&self) -> Vec<RGB> {
    let (device, ctx, queue) = opencl::util::create_compute_context().unwrap();

    let len = WINDOW_WIDTH as usize * WINDOW_HEIGHT as usize;

    let output_buffer: CLBuffer<RGB> = ctx.create_buffer(len, opencl::cl::CL_MEM_WRITE_ONLY);

    let program = {
      let ker = format!("
        float toi(
          const float3 eye,
          const float3 look,

          const float3 sphere,
          const float radius)
        {{
          float a = dot(radius, radius);
          float b = 2 * dot(eye - sphere, look);
          float c = dot(sphere, sphere) + dot(eye, eye) - dot(eye, sphere) - radius * radius;

          float d = b*b - 4*a*c;

          if (d < 0) {{
            return HUGE_VALF;
          }}

          return (-sqrt(d) - b) / (2 * a);
        }}

        __kernel void render(
          const float3 obj_center,
          const float obj_radius,

          const float3 eye,

          __global float * output)
        {{
          int W = {};
          int H = {};

          float fov_x = 3.14 / 2;
          float fov_y = 3.14 / 2;

          int i = get_global_id(0);

          float x_pix = i % W;
          float y_pix = i / W;

          float t_x = fov_x * (x_pix / W - 0.5);
          float t_y = fov_y * (y_pix / H - 0.5);

          float c = cos(t_y);
          float3 ray = {{c*sin(t_x), sin(t_y), -c*cos(t_x)}};

          float t = toi(eye, ray, obj_center, obj_radius);

          i = i * 3;
          if (t == HUGE_VALF) {{
            output[i+0] = 0;
            output[i+1] = 0;
            output[i+2] = 0;
            return;
          }}

          output[i+0] = 1;
          output[i+1] = 0;
          output[i+2] = 0;
        }}",
        WINDOW_WIDTH,
        WINDOW_HEIGHT,
      );
      ctx.create_program_from_source(ker.as_slice())
    };
    program.build(&device).unwrap();

    let kernel = program.create_kernel("render");
    kernel.set_arg(0, &self.center);
    kernel.set_arg(1, &self.radius);
    kernel.set_arg(2, &self.camera);

    // This is sketchy; we "implicitly cast" output_buffer from a CLBuffer<RGB> to a CLBuffer<f32>.
    kernel.set_arg(3, &output_buffer);

    let event = queue.enqueue_async_kernel(&kernel, len, None, ());

    queue.get(&output_buffer, &event)
  }
}
<|endoftext|>


<commit_before>//! Defines the scene struct which contains the various objects defining the scene.
//! This includes the geometry, instances of the geometry, the camera and so on.

use std::sync::Arc;

use linalg::{Transform, Point, Vector, Ray};
use film::{Camera, Colorf};
use geometry::{Sphere, Plane, Instance};
use material::{Matte, SpecularMetal, Glass, Material};
use geometry::{Geometry, Intersection};
use integrator::{Whitted, Integrator};
use light;
use light::Light;

/// The scene containing the objects and camera configuration we'd like to render,
/// shared immutably among the ray tracing threads
pub struct Scene {
    pub camera: Arc<Camera>,
    /// TODO: Only one instance for now
    pub instances: Arc<Vec<Instance>>,
    pub integrator: Arc<Box<Integrator + Send + Sync>>,
    /// TODO: Only one light for now
    pub light: Arc<Box<Light + Send + Sync>>,
    sphere: Arc<Box<Geometry + Send + Sync>>,
}

impl Scene {
    /// Create our (currently) hard-coded scene, passing in the render target
    /// dimensions so we can set the projection matrix for the camera
    pub fn new(w: usize, h: usize) -> Scene {
        let sphere = Arc::new(Box::new(Sphere::new(1.0)) as Box<Geometry + Send + Sync>);
        let plane = Arc::new(Box::new(Plane) as Box<Geometry + Send + Sync>);
        let white_wall = Arc::new(Box::new(Matte::new(&Colorf::new(1.0, 1.0, 1.0), 1.0)) as Box<Material + Send + Sync>);
        let red_wall = Arc::new(Box::new(Matte::new(&Colorf::new(1.0, 0.2, 0.2), 1.0)) as Box<Material + Send + Sync>);
        let blue_wall = Arc::new(Box::new(Matte::new(&Colorf::new(0.2, 0.2, 1.0), 1.0)) as Box<Material + Send + Sync>);
        let instances = vec![
            // The reflective sphere
            Instance::new(sphere.clone(),
            Arc::new(Box::new(SpecularMetal::new(&Colorf::new(0.155, 0.116, 0.138),
                                                 &Colorf::new(4.828, 3.122, 2.146)))
                     as Box<Material + Send + Sync>), Transform::translate(&Vector::new(-6.0, 8.0, 5.0))
                    * Transform::scale(&Vector::broadcast(5.0))),
            // The glass sphere
            Instance::new(sphere.clone(),
            Arc::new(Box::new(Glass::new(&Colorf::broadcast(1.0), &Colorf::broadcast(1.0), 1.52))
                     as Box<Material + Send + Sync>), Transform::translate(&Vector::new(6.0, -2.0, 5.0))
                    * Transform::scale(&Vector::broadcast(5.0))),
            // The back wall
            Instance::new(plane.clone(), white_wall.clone(), Transform::translate(&Vector::new(0.0, 20.0, 12.0))
                          * Transform::scale(&Vector::broadcast(32.0)) * Transform::rotate_x(90.0)),
            // The left wall
            Instance::new(plane.clone(), red_wall.clone(), Transform::translate(&Vector::new(-15.0, 0.0, 12.0))
                          * Transform::scale(&Vector::broadcast(32.0)) * Transform::rotate_y(90.0)),
            // The right wall
            Instance::new(plane.clone(), blue_wall.clone(), Transform::translate(&Vector::new(15.0, 0.0, 12.0))
                          * Transform::scale(&Vector::broadcast(32.0)) * Transform::rotate_y(-90.0)),
            // The top wall
            Instance::new(plane.clone(), white_wall.clone(), Transform::translate(&Vector::new(0.0, 0.0, 24.0))
                          * Transform::scale(&Vector::broadcast(32.0)) * Transform::rotate_x(180.0)),
            // The bottom wall
            Instance::new(plane.clone(), white_wall.clone(), Transform::translate(&Vector::new(0.0, 0.0, 0.0))
                          * Transform::scale(&Vector::broadcast(32.0)))
        ];
        Scene {
            camera: Arc::new(Camera::new(Transform::look_at(&Point::new(0.0, -60.0, 12.0),
                &Point::new(0.0, 0.0, 12.0), &Vector::new(0.0, 0.0, 1.0)), 30.0, (w, h))),
            instances: Arc::new(instances),
            integrator: Arc::new(Box::new(Whitted::new(8)) as Box<Integrator + Send + Sync>),
            light: Arc::new(Box::new(light::Point::new(&Point::new(0.0, 0.0, 22.0), &Colorf::broadcast(150.0)))
                            as Box<Light + Send + Sync>),
            sphere: sphere.clone(),
        }
    }
    /// Test the ray for intersections against the objects in the scene.
    /// Returns Some(Intersection) if an intersection was found and None if not.
    pub fn intersect(&self, ray: &mut Ray) -> Option<Intersection> {
        // We can always return the next hit found since the ray's max_t value is updated
        // after an intersection is found. Thus if we find another hit we know that one
        // occured before any previous ones. TODO: Replace with a BVH
        self.instances.iter().fold(None, |p, ref i|
                                    match i.intersect(ray) {
                                        Some(h) => Some(h),
                                        None => p,
                                    })
    }
}

<commit_msg>We actually support multiple instances now<commit_after>//! Defines the scene struct which contains the various objects defining the scene.
//! This includes the geometry, instances of the geometry, the camera and so on.

use std::sync::Arc;

use linalg::{Transform, Point, Vector, Ray};
use film::{Camera, Colorf};
use geometry::{Sphere, Plane, Instance};
use material::{Matte, SpecularMetal, Glass, Material};
use geometry::{Geometry, Intersection};
use integrator::{Whitted, Integrator};
use light;
use light::Light;

/// The scene containing the objects and camera configuration we'd like to render,
/// shared immutably among the ray tracing threads
pub struct Scene {
    pub camera: Arc<Camera>,
    pub instances: Arc<Vec<Instance>>,
    pub integrator: Arc<Box<Integrator + Send + Sync>>,
    /// TODO: Only one light for now
    pub light: Arc<Box<Light + Send + Sync>>,
    sphere: Arc<Box<Geometry + Send + Sync>>,
}

impl Scene {
    /// Create our (currently) hard-coded scene, passing in the render target
    /// dimensions so we can set the projection matrix for the camera
    pub fn new(w: usize, h: usize) -> Scene {
        let sphere = Arc::new(Box::new(Sphere::new(1.0)) as Box<Geometry + Send + Sync>);
        let plane = Arc::new(Box::new(Plane) as Box<Geometry + Send + Sync>);
        let white_wall = Arc::new(Box::new(Matte::new(&Colorf::new(1.0, 1.0, 1.0), 1.0)) as Box<Material + Send + Sync>);
        let red_wall = Arc::new(Box::new(Matte::new(&Colorf::new(1.0, 0.2, 0.2), 1.0)) as Box<Material + Send + Sync>);
        let blue_wall = Arc::new(Box::new(Matte::new(&Colorf::new(0.2, 0.2, 1.0), 1.0)) as Box<Material + Send + Sync>);
        let instances = vec![
            // The reflective sphere
            Instance::new(sphere.clone(),
            Arc::new(Box::new(SpecularMetal::new(&Colorf::new(0.155, 0.116, 0.138),
                                                 &Colorf::new(4.828, 3.122, 2.146)))
                     as Box<Material + Send + Sync>), Transform::translate(&Vector::new(-6.0, 8.0, 5.0))
                    * Transform::scale(&Vector::broadcast(5.0))),
            // The glass sphere
            Instance::new(sphere.clone(),
            Arc::new(Box::new(Glass::new(&Colorf::broadcast(1.0), &Colorf::broadcast(1.0), 1.52))
                     as Box<Material + Send + Sync>), Transform::translate(&Vector::new(6.0, -2.0, 5.0))
                    * Transform::scale(&Vector::broadcast(5.0))),
            // The back wall
            Instance::new(plane.clone(), white_wall.clone(), Transform::translate(&Vector::new(0.0, 20.0, 12.0))
                          * Transform::scale(&Vector::broadcast(32.0)) * Transform::rotate_x(90.0)),
            // The left wall
            Instance::new(plane.clone(), red_wall.clone(), Transform::translate(&Vector::new(-15.0, 0.0, 12.0))
                          * Transform::scale(&Vector::broadcast(32.0)) * Transform::rotate_y(90.0)),
            // The right wall
            Instance::new(plane.clone(), blue_wall.clone(), Transform::translate(&Vector::new(15.0, 0.0, 12.0))
                          * Transform::scale(&Vector::broadcast(32.0)) * Transform::rotate_y(-90.0)),
            // The top wall
            Instance::new(plane.clone(), white_wall.clone(), Transform::translate(&Vector::new(0.0, 0.0, 24.0))
                          * Transform::scale(&Vector::broadcast(32.0)) * Transform::rotate_x(180.0)),
            // The bottom wall
            Instance::new(plane.clone(), white_wall.clone(), Transform::translate(&Vector::new(0.0, 0.0, 0.0))
                          * Transform::scale(&Vector::broadcast(32.0)))
        ];
        Scene {
            camera: Arc::new(Camera::new(Transform::look_at(&Point::new(0.0, -60.0, 12.0),
                &Point::new(0.0, 0.0, 12.0), &Vector::new(0.0, 0.0, 1.0)), 30.0, (w, h))),
            instances: Arc::new(instances),
            integrator: Arc::new(Box::new(Whitted::new(8)) as Box<Integrator + Send + Sync>),
            light: Arc::new(Box::new(light::Point::new(&Point::new(0.0, 0.0, 22.0), &Colorf::broadcast(150.0)))
                            as Box<Light + Send + Sync>),
            sphere: sphere.clone(),
        }
    }
    /// Test the ray for intersections against the objects in the scene.
    /// Returns Some(Intersection) if an intersection was found and None if not.
    pub fn intersect(&self, ray: &mut Ray) -> Option<Intersection> {
        // We can always return the next hit found since the ray's max_t value is updated
        // after an intersection is found. Thus if we find another hit we know that one
        // occured before any previous ones. TODO: Replace with a BVH
        self.instances.iter().fold(None, |p, ref i|
                                    match i.intersect(ray) {
                                        Some(h) => Some(h),
                                        None => p,
                                    })
    }
}

<|endoftext|>


<commit_before>extern mod std;
use task::spawn;

mod environment;
use environment::Environment;
mod expression;
use expression::Expression;
use expression::{Int,Float,Symbol,List,Proc};
mod parse;
use parse::parse;

#[test]
fn test_eval_returns_number_when_passed_number() {
    let value = eval( Int(1), @Environment::new_global_environment() );
    match value {
        Int(1) => (),
        _ => fail
    }
}

#[test]
fn test_eval_returns_expression_when_passed_quote() {
    let value = eval( List( ~[ Symbol(~"quote"), List( ~[ Symbol(~"a") ] ) ] ),
    @Environment::new_global_environment() );
    match value {
        List( [ Symbol( ~"a" ) ] ) => (),
        _ => fail
    }
}

#[test]
fn test_eval_returns_last_expression_when_passed_begin() {
    let expression = parse( ~"(begin 1 2 3)" );
    let value = eval( expression, @Environment::new_global_environment() );
    match value {
        Int(3) => (),
        _ => fail
    }
}

#[test]
fn test_if_returns_third_part_when_if_is_true() {
    let expression = parse( ~"(if 1 2 3)" );
    let value = eval( expression, @Environment::new_global_environment() );
    match value {
        Int(2) => (),
        _ => fail
    }
}

#[test]
fn test_if_returns_fourth_part_when_if_is_false() {
    let expression = parse( ~"(if 0 2 3)" );
    let value = eval( expression, @Environment::new_global_environment() );
    match value {
        Int(3) => (),
        _ => fail
    }
}

#[test]
fn test_that_if_evaluates_the_then_branch() {
    let expression = parse( ~"(if 1 (begin 1 2) 7)" );
    let value = eval( expression, @Environment::new_global_environment() );
    match value {
        Int(2) => (),
        List( [Symbol(~"begin"), Int(1), Int(2)]) => fail ~"If just returned the then branch",
        _ => fail fmt!("If returned something unusual (%s)", value.to_str())
    }
}

#[test]
fn test_that_if_evaluates_the_else_branch() {
    let expression = parse( ~"(if 0 7 (begin 1 2))" );
    let value = eval( expression, @Environment::new_global_environment() );
    match value {
        Int(2) => (),
        List( [Symbol(~"begin"), Int(1), Int(2)]) => fail ~"If just returned the else branch",
        _ => fail fmt!("If returned something unusual (%s)", value.to_str())
    }
}

#[test]
fn test_that_if_evaluates_the_test() {
    let expression = parse( ~"(if (begin 1 0) 1 2)" );
    let value = eval( expression, @Environment::new_global_environment() );
    match value {
        Int(1) => fail ~"If didn't evaluate the test",
        Int(2) => (),
        _ => fail fmt!("If returned something unusual (%s)", value.to_str())
    }
}

#[test]
fn test_that_bare_symbol_is_interpreted_as_variable() {
    let env = @Environment::new_global_environment();
    env.define(~"monkey", Int(10));
    let expression = parse( ~"monkey" );
    let value = eval( expression, env );
    match value {
        Int(10) => (),
        _ => fail fmt!("Expected 10 got %s", value.to_str())
    }
}

#[test]
#[should_fail]
fn test_that_undefined_symbol_is_an_error() {
    let env = @Environment::new_global_environment();
    let expression = parse( ~"monkey" );
    eval( expression, env );
}

#[test]
fn test_that_define_can_add_a_variable() {
    let env = @Environment::new_global_environment();
    let expression = parse( ~"(define x 10)" );
    let value = eval( expression, env );
    match env.lookup(~"x") {
        Some(Int(10)) => (),
        _ => fail fmt!("Expected 10 got %s", value.to_str())
    }
}

#[test]
#[should_fail]
fn test_that_set_cannot_create_a_variable() {
    let env = @Environment::new_global_environment();
    let expression = parse( ~"(set! x 10)" );
    eval( expression, env );
}

#[test]
fn test_that_set_can_change_a_variable() {
    let env = @Environment::new_global_environment();
    env.define(~"x", Int(100));
    let expression = parse( ~"(set! x 10)" );
    let value = eval( expression, env );
    match env.lookup(~"x") {
        Some(Int(10)) => (),
        _ => fail fmt!("Expected 10 got %s", value.to_str())
    }
}

#[test]
fn test_that_set_returns_the_value_not_the_key() {
    let env = @Environment::new_global_environment();
    env.define(~"x", Int(100));
    let expression = parse( ~"(set! x 10)" );
    let value = eval( expression, env );
    match value {
        Int(10) => (),
        Symbol(~"x") => fail ~"set! returned the key, not the value",
        _ => fail fmt!("Expected 10 got %s", value.to_str())
    }
}

#[test]
fn test_that_begin_can_handle_one_argument() {
    let env = @Environment::new_global_environment();
    let expression = parse( ~"(begin 10)" );
    let value = eval( expression, env );
    match value {
        Int(10) => (),
        _ => fail fmt!("Expected 10 got %s", value.to_str())
    }
}

#[test]
fn test_that_begin_evaluates_all_arguments() {
    let env = @Environment::new_global_environment();
    let expression = parse( ~"(begin (define x 10) x)" );
    let value = eval( expression, env );
    match env.lookup(~"x") {
        Some(Int(10)) => (),
        _ => fail fmt!("Expected 10 got %s", value.to_str())
    }
    match value {
        Int(10) => (),
        _ => fail fmt!("Expected 10 got %s", value.to_str())
    }
}

#[test]
fn test_that_other_symbols_are_evaluated_as_procs() {
    let env = @Environment::new_global_environment();
    let expression = parse( ~"(+ 1 2)" );
    let value = eval( expression, env );
    match value {
        Int(3) => (),
        _ => fail fmt!("(+ 1 2) became %s", value.to_str())
    }
}

#[test]
fn test_that_proc_params_are_evaluated() {
    let env=@Environment::new_global_environment();
    let expression = parse( ~"(+ (+ 1 2) 3)" );
    let value = eval (expression, env);
    match value {
        Int(6) => (),
        _ => fail fmt!("(+ (+ 1 2) 3) became %s", value.to_str())
    }
}

#[test]
fn test_that_lambda_evaluates_to_a_proc() {
    let env=@Environment::new_global_environment();
    let expression = parse( ~"(lambda (x) (* x x))" );
    let value = eval(expression, env);
    match value {
        Proc(_) => (),
        _ => fail ~"lambda doesn't turn into a Proc"
    }
}

#[test]
fn test_that_lambda_without_variables_evals() {
    let env=@Environment::new_global_environment();
    let expression = parse( ~"( (lambda () (+ 1 1))  )" );
    let value = eval(expression, env);
    match value {
        Int(2) => (),
        _ => fail fmt!("lambda evaluated to %s", value.to_str())
    }
}

#[test]
fn test_that_lambda_with_a_variable_evals() {
    let env=@Environment::new_global_environment();
    let expression = parse( ~"( (lambda (x) (+ x 1)) 1  )" );
    let value = eval(expression, env);
    match value {
        Int(2) => (),
        _ => fail fmt!("lambda evaluated to %s", value.to_str())
    }
}

fn eval( expression:Expression, environment:@Environment ) -> Expression {
    fn quote(expressions:~[Expression]) -> Expression {
        match expressions {
            [_, expr] => expr,
            _ => fail ~"Syntax Error: quote must take a single argument"
        }
    }

    fn begin(expressions:~[Expression], environment:@Environment) -> Expression {
        for expressions.tail().init().each() |&expression| {
            eval( expression, environment );
        }
        eval( expressions.last(), environment )
    }

    fn if_(expressions:~[Expression], environment:@Environment) -> Expression {
        match expressions {
            [_, test, true_expr, false_expr] => {
                let condition = eval(test, environment);
                eval(if condition.to_bool() {
                    true_expr
                } else {
                    false_expr
                }, environment)
            }
            _ => fail ~"Syntax Error: if must take three arguments"
        }
    }

    fn reset_variable(expressions:~[Expression], environment:@Environment, function:~str) -> Expression {
        match expressions {
            [_, symbol, value] => {
                match copy symbol {
                    Symbol( key ) => {
                        environment.define(key, eval(value, environment));
                        symbol
                    }
                    _ => fail fmt!("Syntax Error: %s takes a symbol as its first argument", function)
                }
            }
            _ => fail fmt!("Syntax Error: %s must take two arguments", function)
        }
    }

    fn define(expressions:~[Expression], environment:@Environment) -> Expression {
        reset_variable(expressions, environment, ~"define")
    }

    fn set_bang(expressions:~[Expression], environment:@Environment) -> Expression {
        match copy expressions {
            [_, symbol, _] => {
                match copy symbol {
                    Symbol( key ) => {
                        match environment.lookup( copy key )  {
                            None => fail ~"Syntax Error: set! cannot create a variable",
                            _ => ()
                        }
                    }
                    _ => ()
                }
            }
            _ => ()
        }
        let symbol = reset_variable(expressions, environment, ~"set!");
        match copy symbol {
            Symbol( key ) => {
                match environment.lookup( copy key ) {
                    Some( value ) => value,
                    None => fail
                }
            }
            _ => fail
        }
    }

    fn proc(expressions:~[Expression], environment:@Environment) -> Expression {
        let exprs = expressions.map(|&expr| eval(expr, environment));
        match exprs.head() {
            Proc( procedure ) => procedure( exprs.tail(), environment ),
            _ => fail fmt!("\"%s\" is not a procedure", exprs.head().to_str())
        }
    }

    fn lambda(expressions:~[Expression], _:@Environment) -> Expression {
        match copy expressions {
            [_, List(param_names), expression] => Proc( |param_values, env| {
                    let local_env = @Environment::new( env );
                    for vec::zip(copy param_names, param_values).each |param| {
                        match param.first() {
                            Symbol(key) => local_env.define( key, param.second() ),
                            _ => fail ~"lambda params list must be list of symbols"
                        }
                    }
                    eval(copy expression, local_env)
                } ),
            _ => fail fmt!("Syntax Error: lambda requires 2 arguments, got \"%u\"", expressions.len()-1 )
        }
    }

    match copy expression {
        List( expressions ) => {
            match expressions[0] {
                Symbol(~"quote") => quote(expressions),
                Symbol(~"begin") => begin(expressions, environment),
                Symbol(~"if") => if_(expressions, environment),
                Symbol(~"define") => define(expressions, environment),
                Symbol(~"set!") => set_bang(expressions, environment),
                Symbol(~"lambda") => lambda(expressions, environment),
                _ => proc(expressions, environment)
            }
        }
        Symbol( symbol ) => {
            match environment.lookup( copy symbol ) {
                Some( value ) => value,
                None => fail fmt!("Undefined symbol %s",symbol)
            }
        }
        _ => {
            expression
        }
    }
}

fn main() {
    fn evaluate( expr:~str ) {
        let expr2 = copy expr;
        let result = do task::try {
             eval( parse(expr), @Environment::new_global_environment() )
        };
        if result.is_ok() {
            io::println( fmt!("%s -> %s", expr2, result.unwrap().to_str()) );
        } else {
            io::println( fmt!("%s gave an error.", expr2) );
        }
    }
    evaluate( ~"(* 4 99)" );
    evaluate( ~"(begin (define square (lambda (x) (* x x))) (square 4))" );
    evaluate( ~"(7 7)" );
}
<commit_msg>Add repl loop (state is not preserved, yet)<commit_after>extern mod std;
use task::spawn;
use io::{Reader,ReaderUtil};

mod environment;
use environment::Environment;
mod expression;
use expression::Expression;
use expression::{Int,Float,Symbol,List,Proc};
mod parse;
use parse::parse;

#[test]
fn test_eval_returns_number_when_passed_number() {
    let value = eval( Int(1), @Environment::new_global_environment() );
    match value {
        Int(1) => (),
        _ => fail
    }
}

#[test]
fn test_eval_returns_expression_when_passed_quote() {
    let value = eval( List( ~[ Symbol(~"quote"), List( ~[ Symbol(~"a") ] ) ] ),
    @Environment::new_global_environment() );
    match value {
        List( [ Symbol( ~"a" ) ] ) => (),
        _ => fail
    }
}

#[test]
fn test_eval_returns_last_expression_when_passed_begin() {
    let expression = parse( ~"(begin 1 2 3)" );
    let value = eval( expression, @Environment::new_global_environment() );
    match value {
        Int(3) => (),
        _ => fail
    }
}

#[test]
fn test_if_returns_third_part_when_if_is_true() {
    let expression = parse( ~"(if 1 2 3)" );
    let value = eval( expression, @Environment::new_global_environment() );
    match value {
        Int(2) => (),
        _ => fail
    }
}

#[test]
fn test_if_returns_fourth_part_when_if_is_false() {
    let expression = parse( ~"(if 0 2 3)" );
    let value = eval( expression, @Environment::new_global_environment() );
    match value {
        Int(3) => (),
        _ => fail
    }
}

#[test]
fn test_that_if_evaluates_the_then_branch() {
    let expression = parse( ~"(if 1 (begin 1 2) 7)" );
    let value = eval( expression, @Environment::new_global_environment() );
    match value {
        Int(2) => (),
        List( [Symbol(~"begin"), Int(1), Int(2)]) => fail ~"If just returned the then branch",
        _ => fail fmt!("If returned something unusual (%s)", value.to_str())
    }
}

#[test]
fn test_that_if_evaluates_the_else_branch() {
    let expression = parse( ~"(if 0 7 (begin 1 2))" );
    let value = eval( expression, @Environment::new_global_environment() );
    match value {
        Int(2) => (),
        List( [Symbol(~"begin"), Int(1), Int(2)]) => fail ~"If just returned the else branch",
        _ => fail fmt!("If returned something unusual (%s)", value.to_str())
    }
}

#[test]
fn test_that_if_evaluates_the_test() {
    let expression = parse( ~"(if (begin 1 0) 1 2)" );
    let value = eval( expression, @Environment::new_global_environment() );
    match value {
        Int(1) => fail ~"If didn't evaluate the test",
        Int(2) => (),
        _ => fail fmt!("If returned something unusual (%s)", value.to_str())
    }
}

#[test]
fn test_that_bare_symbol_is_interpreted_as_variable() {
    let env = @Environment::new_global_environment();
    env.define(~"monkey", Int(10));
    let expression = parse( ~"monkey" );
    let value = eval( expression, env );
    match value {
        Int(10) => (),
        _ => fail fmt!("Expected 10 got %s", value.to_str())
    }
}

#[test]
#[should_fail]
fn test_that_undefined_symbol_is_an_error() {
    let env = @Environment::new_global_environment();
    let expression = parse( ~"monkey" );
    eval( expression, env );
}

#[test]
fn test_that_define_can_add_a_variable() {
    let env = @Environment::new_global_environment();
    let expression = parse( ~"(define x 10)" );
    let value = eval( expression, env );
    match env.lookup(~"x") {
        Some(Int(10)) => (),
        _ => fail fmt!("Expected 10 got %s", value.to_str())
    }
}

#[test]
#[should_fail]
fn test_that_set_cannot_create_a_variable() {
    let env = @Environment::new_global_environment();
    let expression = parse( ~"(set! x 10)" );
    eval( expression, env );
}

#[test]
fn test_that_set_can_change_a_variable() {
    let env = @Environment::new_global_environment();
    env.define(~"x", Int(100));
    let expression = parse( ~"(set! x 10)" );
    let value = eval( expression, env );
    match env.lookup(~"x") {
        Some(Int(10)) => (),
        _ => fail fmt!("Expected 10 got %s", value.to_str())
    }
}

#[test]
fn test_that_set_returns_the_value_not_the_key() {
    let env = @Environment::new_global_environment();
    env.define(~"x", Int(100));
    let expression = parse( ~"(set! x 10)" );
    let value = eval( expression, env );
    match value {
        Int(10) => (),
        Symbol(~"x") => fail ~"set! returned the key, not the value",
        _ => fail fmt!("Expected 10 got %s", value.to_str())
    }
}

#[test]
fn test_that_begin_can_handle_one_argument() {
    let env = @Environment::new_global_environment();
    let expression = parse( ~"(begin 10)" );
    let value = eval( expression, env );
    match value {
        Int(10) => (),
        _ => fail fmt!("Expected 10 got %s", value.to_str())
    }
}

#[test]
fn test_that_begin_evaluates_all_arguments() {
    let env = @Environment::new_global_environment();
    let expression = parse( ~"(begin (define x 10) x)" );
    let value = eval( expression, env );
    match env.lookup(~"x") {
        Some(Int(10)) => (),
        _ => fail fmt!("Expected 10 got %s", value.to_str())
    }
    match value {
        Int(10) => (),
        _ => fail fmt!("Expected 10 got %s", value.to_str())
    }
}

#[test]
fn test_that_other_symbols_are_evaluated_as_procs() {
    let env = @Environment::new_global_environment();
    let expression = parse( ~"(+ 1 2)" );
    let value = eval( expression, env );
    match value {
        Int(3) => (),
        _ => fail fmt!("(+ 1 2) became %s", value.to_str())
    }
}

#[test]
fn test_that_proc_params_are_evaluated() {
    let env=@Environment::new_global_environment();
    let expression = parse( ~"(+ (+ 1 2) 3)" );
    let value = eval (expression, env);
    match value {
        Int(6) => (),
        _ => fail fmt!("(+ (+ 1 2) 3) became %s", value.to_str())
    }
}

#[test]
fn test_that_lambda_evaluates_to_a_proc() {
    let env=@Environment::new_global_environment();
    let expression = parse( ~"(lambda (x) (* x x))" );
    let value = eval(expression, env);
    match value {
        Proc(_) => (),
        _ => fail ~"lambda doesn't turn into a Proc"
    }
}

#[test]
fn test_that_lambda_without_variables_evals() {
    let env=@Environment::new_global_environment();
    let expression = parse( ~"( (lambda () (+ 1 1))  )" );
    let value = eval(expression, env);
    match value {
        Int(2) => (),
        _ => fail fmt!("lambda evaluated to %s", value.to_str())
    }
}

#[test]
fn test_that_lambda_with_a_variable_evals() {
    let env=@Environment::new_global_environment();
    let expression = parse( ~"( (lambda (x) (+ x 1)) 1  )" );
    let value = eval(expression, env);
    match value {
        Int(2) => (),
        _ => fail fmt!("lambda evaluated to %s", value.to_str())
    }
}

fn eval( expression:Expression, environment:@Environment ) -> Expression {
    fn quote(expressions:~[Expression]) -> Expression {
        match expressions {
            [_, expr] => expr,
            _ => fail ~"Syntax Error: quote must take a single argument"
        }
    }

    fn begin(expressions:~[Expression], environment:@Environment) -> Expression {
        for expressions.tail().init().each() |&expression| {
            eval( expression, environment );
        }
        eval( expressions.last(), environment )
    }

    fn if_(expressions:~[Expression], environment:@Environment) -> Expression {
        match expressions {
            [_, test, true_expr, false_expr] => {
                let condition = eval(test, environment);
                eval(if condition.to_bool() {
                    true_expr
                } else {
                    false_expr
                }, environment)
            }
            _ => fail ~"Syntax Error: if must take three arguments"
        }
    }

    fn reset_variable(expressions:~[Expression], environment:@Environment, function:~str) -> Expression {
        match expressions {
            [_, symbol, value] => {
                match copy symbol {
                    Symbol( key ) => {
                        environment.define(key, eval(value, environment));
                        symbol
                    }
                    _ => fail fmt!("Syntax Error: %s takes a symbol as its first argument", function)
                }
            }
            _ => fail fmt!("Syntax Error: %s must take two arguments", function)
        }
    }

    fn define(expressions:~[Expression], environment:@Environment) -> Expression {
        reset_variable(expressions, environment, ~"define")
    }

    fn set_bang(expressions:~[Expression], environment:@Environment) -> Expression {
        match copy expressions {
            [_, symbol, _] => {
                match copy symbol {
                    Symbol( key ) => {
                        match environment.lookup( copy key )  {
                            None => fail ~"Syntax Error: set! cannot create a variable",
                            _ => ()
                        }
                    }
                    _ => ()
                }
            }
            _ => ()
        }
        let symbol = reset_variable(expressions, environment, ~"set!");
        match copy symbol {
            Symbol( key ) => {
                match environment.lookup( copy key ) {
                    Some( value ) => value,
                    None => fail
                }
            }
            _ => fail
        }
    }

    fn proc(expressions:~[Expression], environment:@Environment) -> Expression {
        let exprs = expressions.map(|&expr| eval(expr, environment));
        match exprs.head() {
            Proc( procedure ) => procedure( exprs.tail(), environment ),
            _ => fail fmt!("\"%s\" is not a procedure", exprs.head().to_str())
        }
    }

    fn lambda(expressions:~[Expression], _:@Environment) -> Expression {
        match copy expressions {
            [_, List(param_names), expression] => Proc( |param_values, env| {
                    let local_env = @Environment::new( env );
                    for vec::zip(copy param_names, param_values).each |param| {
                        match param.first() {
                            Symbol(key) => local_env.define( key, param.second() ),
                            _ => fail ~"lambda params list must be list of symbols"
                        }
                    }
                    eval(copy expression, local_env)
                } ),
            _ => fail fmt!("Syntax Error: lambda requires 2 arguments, got \"%u\"", expressions.len()-1 )
        }
    }

    match copy expression {
        List( expressions ) => {
            match expressions[0] {
                Symbol(~"quote") => quote(expressions),
                Symbol(~"begin") => begin(expressions, environment),
                Symbol(~"if") => if_(expressions, environment),
                Symbol(~"define") => define(expressions, environment),
                Symbol(~"set!") => set_bang(expressions, environment),
                Symbol(~"lambda") => lambda(expressions, environment),
                _ => proc(expressions, environment)
            }
        }
        Symbol( symbol ) => {
            match environment.lookup( copy symbol ) {
                Some( value ) => value,
                None => fail fmt!("Undefined symbol %s",symbol)
            }
        }
        _ => {
            expression
        }
    }
}

fn main() {
    fn evaluate( expr:~str ) {
        let sent_expr = copy expr;
        let result = do task::try {
            let env = @Environment::new_global_environment();
            eval( parse(sent_expr), env )
        };
        if result.is_ok() {
            io::println( fmt!("%s -> %s", expr, result.unwrap().to_str()) );
        } else {
            io::println( fmt!("%s gave an error.", expr) );
        }
    }

    evaluate( ~"(* 4 99)" );
    evaluate( ~"(begin (define square (lambda (x) (* x x))) (square 4))" );
    evaluate( ~"(7 7)" );

    loop {
        io::print("rusty> ");
        let in = io::stdin().read_line();
        evaluate( in );
    }
}
<|endoftext|>


<commit_before>use std::path::Path;

use cache::{Cache, Get};
use resource::{Load, Reload};

/// The scene type.
///
/// This type gathers all the required objects a scene needs to correctly handle and render all
/// visual effects.
pub struct Scene<'a> {
  /// Cache.
  cache: Cache<'a>
}

impl<'a> Scene<'a> {
  pub fn new<P>(root: P) -> Self where P: AsRef<Path>{
    Scene {
      cache: Cache::new(root),
    }
  }

  pub fn get_id<T>(&mut self, name: &str, args: <T as Load>::Args) -> Option<<Cache<'a> as Get<T>>::Id> where Cache<'a>: Get<T>, T: Reload {
    self.cache.get_id(name, args)
  }

  pub fn get_by_id<T>(&mut self, id: &<Cache<'a> as Get<T>>::Id) -> Option<&T> where Cache<'a>: Get<T>, T: Reload {
    self.cache.get_by_id(id)
  }

  pub fn get<T>(&mut self, name: &str, args: <T as Load>::Args) -> Option<&T> where Cache<'a>: Get<T>, T: Reload {
    self.cache.get(name, args)
  }
}

#[macro_export]
macro_rules! get_id {
  ($scene:ident, $name:ident) => {
    $scene.get_id($name, ())
  };

  ($scene:ident, $name:ident, $($arg:ident),*) => {
    $scene.get_id($name, ($($arg),*))
  }
}
<commit_msg>Fixed get_id!.<commit_after>use std::path::Path;

use cache::{Cache, Get};
use resource::{Load, Reload};

/// The scene type.
///
/// This type gathers all the required objects a scene needs to correctly handle and render all
/// visual effects.
pub struct Scene<'a> {
  /// Cache.
  cache: Cache<'a>
}

impl<'a> Scene<'a> {
  pub fn new<P>(root: P) -> Self where P: AsRef<Path>{
    Scene {
      cache: Cache::new(root),
    }
  }

  pub fn get_id<T>(&mut self, name: &str, args: <T as Load>::Args) -> Option<<Cache<'a> as Get<T>>::Id> where Cache<'a>: Get<T>, T: Reload {
    self.cache.get_id(name, args)
  }

  pub fn get_by_id<T>(&mut self, id: &<Cache<'a> as Get<T>>::Id) -> Option<&T> where Cache<'a>: Get<T>, T: Reload {
    self.cache.get_by_id(id)
  }

  pub fn get<T>(&mut self, name: &str, args: <T as Load>::Args) -> Option<&T> where Cache<'a>: Get<T>, T: Reload {
    self.cache.get(name, args)
  }
}

#[macro_export]
macro_rules! get_id {
  ($scene:ident, $name:expr) => {
    $scene.get_id($name, ())
  };

  ($scene:ident, $name:expr, $($arg:expr),*) => {
    $scene.get_id($name, ($($arg),*))
  }
}
<|endoftext|>