<commit_before>extern crate byteorder;

use std::{io,convert,string};
use std::io::{Read, Write};

use self::byteorder::{BigEndian, WriteBytesExt, ReadBytesExt};

#[derive(Debug)]
pub enum Error {
    IoError(io::Error),
    StringConvertError,
    StringHasInvalidLength,
    StringHasInvalidCharacter,
    VarIntIsTooShort,
    VarIntIsTooLong,
    VarLongIsTooShort,
    VarLongIsTooLong,
    StringIsTooLong,
}

impl_convert_for_error!(io::Error, Error::IoError);

impl convert::From<string::FromUtf8Error> for Error {
    fn from(_: string::FromUtf8Error) -> Error {
        Error::StringConvertError
    }
}

pub struct ReadContainer<T> {
    pub content: T,
    pub read_len: usize
}

impl<T> ReadContainer<T> {
    fn new(content: T, read_len: usize) -> Self {
        Self { content, read_len }
    }
}

type WriteResult = Result<(), Error>;
type ReadResult<T>  = Result<ReadContainer<T>, Error>;

pub trait WritePacketData {
    fn write_varint(&mut self, i32) -> WriteResult;
    fn write_varlong(&mut self, i64) -> WriteResult;
    fn write_byte(&mut self, val: u8) -> WriteResult;
    fn write_unsigned_short(&mut self, val: u16) -> WriteResult;
    fn write_unsigned_int(&mut self, val: u32) -> WriteResult;
    fn write_string(&mut self, string: &str) -> WriteResult;
}

pub trait ReadPacketData {
    fn read_varint(&mut self) -> ReadResult<i32>;
    fn read_varlong(&mut self) -> ReadResult<i64>;
    fn read_byte(&mut self) -> ReadResult<u8>;
    fn read_unsigned_short(&mut self) -> ReadResult<u16>;
    fn read_unsigned_int(&mut self) -> ReadResult<u32>;
    fn read_string(&mut self) -> ReadResult<String>;
}

macro_rules! write_variable_integer {
    ($name:ident, $signed:ty, $unsigned:ty) => (
        fn $name(&mut self, val: $signed) -> WriteResult {
            let mut uval = val as $unsigned;

            loop {
                let mut tmp = (uval & 0b_0111_1111) as u8;

                uval >>= 7;
                if uval != 0 {
                    tmp |= 0b_1000_0000;
                }

                self.write(&[tmp])?;

                if uval == 0 { break; }
            }

            Ok(())
        }
    );
}

impl<T> WritePacketData for T where T: Write {
    /// Writes a VarInt (i32) to the packet body.
    write_variable_integer!(write_varint,  i32, u32);

    /// Writes a VarLong (i64) to the packet body.
    write_variable_integer!(write_varlong, i64, u64);

    /// Writes an byte (u8) to the packet body.
    fn write_byte(&mut self, val: u8) -> WriteResult {
        self.write_u8(val)?;
        Ok(())
    }

    /// Writes an unsigned short (u16) to the packet body.
    fn write_unsigned_short(&mut self, val: u16) -> WriteResult {
        self.write_u16::<BigEndian>(val)?;
        Ok(())
    }

    /// Writes an unsigned int (u32) to the packet body.
    fn write_unsigned_int(&mut self, val: u32) -> WriteResult {
        self.write_u32::<BigEndian>(val)?;
        Ok(())
    }

    /// Writes a String to the packet body.
    fn write_string(&mut self, string: &str) -> WriteResult {
        // str.len() returns length of BYTES
        let len = string.len();

        if len > 32767 {
            return Err(Error::StringIsTooLong);
        }

        self.write_varint(len as i32)?;

        for chr in string.as_bytes().into_iter() {
            self.write_byte(*chr)?;
        }

        Ok(())
    }
}

macro_rules! read_variable_integer {
    ($name:ident, $t:ty, $max_len:expr, $err_too_short:path, $err_too_long:path) => (
        fn $name(&mut self) -> ReadResult<$t> {
            let mut result : $t = 0;

            let mut count : usize = 0;
            loop {
                let read = self.read_byte()?.content;
                let value = (read & 0b_0111_1111) as $t;
                result |= value << (7 * count);

                count += 1;
                if count > $max_len {
                    return Err($err_too_long);
                }

                if (read & 0b_1000_0000) == 0 {
                    break;
                }
            }

            Ok(ReadContainer::new(result, count))
        }
    );
}

impl<T> ReadPacketData for T where T: Read {
    read_variable_integer!(read_varint,  i32,  5_usize, Error::VarIntIsTooShort,  Error::VarIntIsTooLong);
    read_variable_integer!(read_varlong, i64, 10_usize, Error::VarLongIsTooShort, Error::VarLongIsTooLong);

    fn read_byte(&mut self) -> ReadResult<u8> {
        let result = self.read_u8()?;
        Ok(ReadContainer::new(result, 1))
    }

    fn read_unsigned_short(&mut self) -> ReadResult<u16> {
        let result = self.read_u16::<BigEndian>()?;
        Ok(ReadContainer::new(result, 2))
    }

    fn read_unsigned_int(&mut self) -> ReadResult<u32> {
        let result = self.read_u32::<BigEndian>()?;
        Ok(ReadContainer::new(result, 4))
    }

    fn read_string(&mut self) -> ReadResult<String> {
        let len_container = self.read_varint()?;
        let len = len_container.content;

        if len > 32767 {
            return Err(Error::StringIsTooLong);
        } else if len <= 0 {
            return Err(Error::StringHasInvalidLength);
        }

        let mut buff = vec![0_u8; len as usize];
        self.read_exact(buff.as_mut_slice())?;

        let result = String::from_utf8(buff)?;

        let read_len = len as usize + len_container.read_len;

        Ok(ReadContainer::new(result, read_len))
    }
}

#[cfg(test)]
mod tests {
    use std::io::{Seek, SeekFrom, Cursor};
    use super::*;

    const VARINT_DATA : [(i32, &'static [u8]); 10] = [
        (          0_i32, &[0x00_u8]),
        (          1_i32, &[0x01_u8]),
        (          2_i32, &[0x02_u8]),
        (         19_i32, &[0x13_u8]),
        (        127_i32, &[0x7f_u8]),
        (        128_i32, &[0x80_u8, 0x01_u8]),
        (        255_i32, &[0xff_u8, 0x01_u8]),
        ( 2147483647_i32, &[0xff_u8, 0xff_u8, 0xff_u8, 0xff_u8, 0x07_u8]),
        (         -1_i32, &[0xff_u8, 0xff_u8, 0xff_u8, 0xff_u8, 0x0f_u8]),
        (-2147483648_i32, &[0x80_u8, 0x80_u8, 0x80_u8, 0x80_u8, 0x08_u8]),
        ];

    const VARLONG_DATA : [(i64, &'static [u8]); 11] = [
        (                   0_i64, &[0x00_u8]),
        (                   1_i64, &[0x01_u8]),
        (                   2_i64, &[0x02_u8]),
        (                 127_i64, &[0x7f_u8]),
        (                 128_i64, &[0x80_u8, 0x01_u8]),
        (                 255_i64, &[0xff_u8, 0x01_u8]),
        (          2147483647_i64, &[0xff_u8, 0xff_u8, 0xff_u8, 0xff_u8, 0x07_u8]),
        ( 9223372036854775807_i64, &[0xff_u8, 0xff_u8, 0xff_u8, 0xff_u8, 0xff_u8, 0xff_u8, 0xff_u8, 0xff_u8, 0x7f]),
        (                  -1_i64, &[0xff_u8, 0xff_u8, 0xff_u8, 0xff_u8, 0xff_u8, 0xff_u8, 0xff_u8, 0xff_u8, 0xff_u8, 0x01]),
        (         -2147483648_i64, &[0x80_u8, 0x80_u8, 0x80_u8, 0x80_u8, 0xf8_u8, 0xff_u8, 0xff_u8, 0xff_u8, 0xff_u8, 0x01]),
        (-9223372036854775808_i64, &[0x80_u8, 0x80_u8, 0x80_u8, 0x80_u8, 0x80_u8, 0x80_u8, 0x80_u8, 0x80_u8, 0x80_u8, 0x01]),
    ];

    macro_rules! test_write_variable_integer {
        ($name:ident, $f:ident, $cases:tt) => (
            #[test]
            fn $name() {
                let mut cursor = Cursor::new(Vec::new());

                let cases = $cases;
                for &(given, ref expect) in cases.iter() {
                    cursor.seek(SeekFrom::Start(0)).unwrap();
                    cursor.$f(given).unwrap();
                    assert_eq!(cursor.get_ref(), expect);
                }
            }
        );
    }

    macro_rules! test_read_variable_integer {
        ($name:ident, $f:ident, $cases:tt) => (
            #[test]
            fn $name() {
                let cases = $cases;
                for &(expect, given) in cases.iter() {
                    let mut cursor = Cursor::new(&given);
                    let result = cursor.$f().unwrap();
                    assert_eq!(result.content, expect);
                    assert_eq!(result.read_len, given.len());
                }
            }
        );
    }

    test_write_variable_integer!(write_varint,  write_varint,  VARINT_DATA);
    test_write_variable_integer!(write_varlong, write_varlong, VARLONG_DATA);
    test_read_variable_integer!(read_varint,  read_varint,  VARINT_DATA);
    test_read_variable_integer!(read_varlong, read_varlong, VARLONG_DATA);

    #[test]
    fn write_unsigned_short() {
        let mut cursor = Cursor::new(Vec::new());

        cursor.write_unsigned_short(517_u16).unwrap();
        assert_eq!(cursor.get_ref(), &vec![2_u8, 5_u8]);
    }

    #[test]
    fn write_string() {
        let mut cursor = Cursor::new(Vec::new());

        cursor.write_string("hello world😆").unwrap();
        assert_eq!(cursor.get_ref(), &vec![15, 104, 101, 108, 108, 111, 32, 119, 111, 114, 108, 100, 240, 159, 152, 134]);
    }

    #[test]
    fn read_string() {
        let vec = vec![15, 104, 101, 108, 108, 111, 32, 119, 111, 114, 108, 100, 240, 159, 152, 134];
        let mut cursor = Cursor::new(vec);

        let s = cursor.read_string().unwrap();
        assert_eq!(s.content, "hello world😆".to_owned());
    }
}
<commit_msg>add read_string_with_max_len<commit_after>extern crate byteorder;

use std::{io,convert,string};
use std::io::{Read, Write};

use self::byteorder::{BigEndian, WriteBytesExt, ReadBytesExt};

pub const STRING_MAX : usize = 32767;

#[derive(Debug)]
pub enum Error {
    IoError(io::Error),
    MaxStringLenIsTooLong,
    StringConvertError,
    StringHasInvalidLength,
    StringHasInvalidCharacter,
    VarIntIsTooShort,
    VarIntIsTooLong,
    VarLongIsTooShort,
    VarLongIsTooLong,
    StringIsTooLong,
}

impl_convert_for_error!(io::Error, Error::IoError);

impl convert::From<string::FromUtf8Error> for Error {
    fn from(_: string::FromUtf8Error) -> Error {
        Error::StringConvertError
    }
}

pub struct ReadContainer<T> {
    pub content: T,
    pub read_len: usize
}

impl<T> ReadContainer<T> {
    fn new(content: T, read_len: usize) -> Self {
        Self { content, read_len }
    }
}

type WriteResult = Result<(), Error>;
type ReadResult<T>  = Result<ReadContainer<T>, Error>;

pub trait WritePacketData {
    fn write_varint(&mut self, i32) -> WriteResult;
    fn write_varlong(&mut self, i64) -> WriteResult;
    fn write_byte(&mut self, val: u8) -> WriteResult;
    fn write_unsigned_short(&mut self, val: u16) -> WriteResult;
    fn write_unsigned_int(&mut self, val: u32) -> WriteResult;
    fn write_string(&mut self, string: &str) -> WriteResult;
}

pub trait ReadPacketData {
    fn read_varint(&mut self) -> ReadResult<i32>;
    fn read_varlong(&mut self) -> ReadResult<i64>;
    fn read_byte(&mut self) -> ReadResult<u8>;
    fn read_unsigned_short(&mut self) -> ReadResult<u16>;
    fn read_unsigned_int(&mut self) -> ReadResult<u32>;
    fn read_string_with_max_len(&mut self, max_len: usize) -> ReadResult<String>;
    fn read_string(&mut self) -> ReadResult<String>;
}

macro_rules! write_variable_integer {
    ($name:ident, $signed:ty, $unsigned:ty) => (
        fn $name(&mut self, val: $signed) -> WriteResult {
            let mut uval = val as $unsigned;

            loop {
                let mut tmp = (uval & 0b_0111_1111) as u8;

                uval >>= 7;
                if uval != 0 {
                    tmp |= 0b_1000_0000;
                }

                self.write(&[tmp])?;

                if uval == 0 { break; }
            }

            Ok(())
        }
    );
}

impl<T> WritePacketData for T where T: Write {
    /// Writes a VarInt (i32) to the packet body.
    write_variable_integer!(write_varint,  i32, u32);

    /// Writes a VarLong (i64) to the packet body.
    write_variable_integer!(write_varlong, i64, u64);

    /// Writes an byte (u8) to the packet body.
    fn write_byte(&mut self, val: u8) -> WriteResult {
        self.write_u8(val)?;
        Ok(())
    }

    /// Writes an unsigned short (u16) to the packet body.
    fn write_unsigned_short(&mut self, val: u16) -> WriteResult {
        self.write_u16::<BigEndian>(val)?;
        Ok(())
    }

    /// Writes an unsigned int (u32) to the packet body.
    fn write_unsigned_int(&mut self, val: u32) -> WriteResult {
        self.write_u32::<BigEndian>(val)?;
        Ok(())
    }

    /// Writes a String to the packet body.
    fn write_string(&mut self, string: &str) -> WriteResult {
        // str.len() returns length of BYTES
        let len = string.len();

        if len > 32767 {
            return Err(Error::StringIsTooLong);
        }

        self.write_varint(len as i32)?;

        for chr in string.as_bytes().into_iter() {
            self.write_byte(*chr)?;
        }

        Ok(())
    }
}

macro_rules! read_variable_integer {
    ($name:ident, $t:ty, $max_len:expr, $err_too_short:path, $err_too_long:path) => (
        fn $name(&mut self) -> ReadResult<$t> {
            let mut result : $t = 0;

            let mut count : usize = 0;
            loop {
                let read = self.read_byte()?.content;
                let value = (read & 0b_0111_1111) as $t;
                result |= value << (7 * count);

                count += 1;
                if count > $max_len {
                    return Err($err_too_long);
                }

                if (read & 0b_1000_0000) == 0 {
                    break;
                }
            }

            Ok(ReadContainer::new(result, count))
        }
    );
}

impl<T> ReadPacketData for T where T: Read {
    read_variable_integer!(read_varint,  i32,  5_usize, Error::VarIntIsTooShort,  Error::VarIntIsTooLong);
    read_variable_integer!(read_varlong, i64, 10_usize, Error::VarLongIsTooShort, Error::VarLongIsTooLong);

    fn read_byte(&mut self) -> ReadResult<u8> {
        let result = self.read_u8()?;
        Ok(ReadContainer::new(result, 1))
    }

    fn read_unsigned_short(&mut self) -> ReadResult<u16> {
        let result = self.read_u16::<BigEndian>()?;
        Ok(ReadContainer::new(result, 2))
    }

    fn read_unsigned_int(&mut self) -> ReadResult<u32> {
        let result = self.read_u32::<BigEndian>()?;
        Ok(ReadContainer::new(result, 4))
    }

    fn read_string(&mut self) -> ReadResult<String> {
        self.read_string_with_max_len(STRING_MAX)
    }

    fn read_string_with_max_len(&mut self, max_len: usize) -> ReadResult<String> {
        let len_container = self.read_varint()?;
        let len = len_container.content as usize;

        if max_len > STRING_MAX {
            return Err(Error::MaxStringLenIsTooLong)
        }

        if (len > max_len) || (len > STRING_MAX) {
            return Err(Error::StringIsTooLong);
        } else if len <= 0 {
            return Err(Error::StringHasInvalidLength);
        }

        let mut buff = vec![0_u8; len as usize];
        self.read_exact(buff.as_mut_slice())?;

        let result = String::from_utf8(buff)?;

        let read_len = len as usize + len_container.read_len;

        Ok(ReadContainer::new(result, read_len))
    }
}

#[cfg(test)]
mod tests {
    use std::io::{Seek, SeekFrom, Cursor};
    use super::*;

    const VARINT_DATA : [(i32, &'static [u8]); 10] = [
        (          0_i32, &[0x00_u8]),
        (          1_i32, &[0x01_u8]),
        (          2_i32, &[0x02_u8]),
        (         19_i32, &[0x13_u8]),
        (        127_i32, &[0x7f_u8]),
        (        128_i32, &[0x80_u8, 0x01_u8]),
        (        255_i32, &[0xff_u8, 0x01_u8]),
        ( 2147483647_i32, &[0xff_u8, 0xff_u8, 0xff_u8, 0xff_u8, 0x07_u8]),
        (         -1_i32, &[0xff_u8, 0xff_u8, 0xff_u8, 0xff_u8, 0x0f_u8]),
        (-2147483648_i32, &[0x80_u8, 0x80_u8, 0x80_u8, 0x80_u8, 0x08_u8]),
        ];

    const VARLONG_DATA : [(i64, &'static [u8]); 11] = [
        (                   0_i64, &[0x00_u8]),
        (                   1_i64, &[0x01_u8]),
        (                   2_i64, &[0x02_u8]),
        (                 127_i64, &[0x7f_u8]),
        (                 128_i64, &[0x80_u8, 0x01_u8]),
        (                 255_i64, &[0xff_u8, 0x01_u8]),
        (          2147483647_i64, &[0xff_u8, 0xff_u8, 0xff_u8, 0xff_u8, 0x07_u8]),
        ( 9223372036854775807_i64, &[0xff_u8, 0xff_u8, 0xff_u8, 0xff_u8, 0xff_u8, 0xff_u8, 0xff_u8, 0xff_u8, 0x7f]),
        (                  -1_i64, &[0xff_u8, 0xff_u8, 0xff_u8, 0xff_u8, 0xff_u8, 0xff_u8, 0xff_u8, 0xff_u8, 0xff_u8, 0x01]),
        (         -2147483648_i64, &[0x80_u8, 0x80_u8, 0x80_u8, 0x80_u8, 0xf8_u8, 0xff_u8, 0xff_u8, 0xff_u8, 0xff_u8, 0x01]),
        (-9223372036854775808_i64, &[0x80_u8, 0x80_u8, 0x80_u8, 0x80_u8, 0x80_u8, 0x80_u8, 0x80_u8, 0x80_u8, 0x80_u8, 0x01]),
    ];

    const STRING_DATA : (&'static str, &'static [u8]) = (
        "hello world😆",
        &[15, 104, 101, 108, 108, 111, 32, 119, 111, 114, 108, 100, 240, 159, 152, 134]
    );

    macro_rules! test_write_variable_integer {
        ($name:ident, $f:ident, $cases:tt) => (
            #[test]
            fn $name() {
                let mut cursor = Cursor::new(Vec::new());

                let cases = $cases;
                for &(given, ref expect) in cases.iter() {
                    cursor.seek(SeekFrom::Start(0)).unwrap();
                    cursor.$f(given).unwrap();
                    assert_eq!(cursor.get_ref(), expect);
                }
            }
        );
    }

    macro_rules! test_read_variable_integer {
        ($name:ident, $f:ident, $cases:tt) => (
            #[test]
            fn $name() {
                let cases = $cases;
                for &(expect, given) in cases.iter() {
                    let mut cursor = Cursor::new(&given);
                    let result = cursor.$f().unwrap();
                    assert_eq!(result.content, expect);
                    assert_eq!(result.read_len, given.len());
                }
            }
        );
    }

    test_write_variable_integer!(write_varint,  write_varint,  VARINT_DATA);
    test_write_variable_integer!(write_varlong, write_varlong, VARLONG_DATA);
    test_read_variable_integer!(read_varint,  read_varint,  VARINT_DATA);
    test_read_variable_integer!(read_varlong, read_varlong, VARLONG_DATA);

    #[test]
    fn write_unsigned_short() {
        let mut cursor = Cursor::new(Vec::new());

        cursor.write_unsigned_short(517_u16).unwrap();
        assert_eq!(cursor.get_ref(), &vec![2_u8, 5_u8]);
    }

    #[test]
    fn write_string() {
        let mut cursor = Cursor::new(Vec::new());

        cursor.write_string("hello world😆").unwrap();
        assert_eq!(cursor.get_ref(), &vec![15, 104, 101, 108, 108, 111, 32, 119, 111, 114, 108, 100, 240, 159, 152, 134]);
    }

    #[test]
    fn read_string() {
        let (expected, given) = STRING_DATA;
        let mut cursor = Cursor::new(given);

        let s = cursor.read_string().unwrap();
        assert_eq!(s.content.as_str(), expected);
    }

    #[test]
    fn read_string_with_max_len() {
        let (expected, given) = STRING_DATA;
        let mut cursor = Cursor::new(given);

        let s = cursor.read_string_with_max_len(expected.len()).unwrap();
        assert_eq!(s.content.as_str(), expected);
    }
}
<|endoftext|>


<commit_before>use cgmath;
use glutin::Event;
use gfx;
use {level, model, render};
use config::Settings;

pub struct Camera {
    pub loc: cgmath::Vector3<f32>,
    pub rot: cgmath::Quaternion<f32>,
    pub proj: cgmath::PerspectiveFov<f32>,
}

impl Camera {
    pub fn get_view_proj(&self) -> cgmath::Matrix4<f32> {
        use cgmath::{Decomposed, Matrix4, Transform};
        let view = Decomposed {
            scale: 1.0,
            rot: self.rot,
            disp: self.loc,
        };
        let view_mx: Matrix4<f32> = view.inverse_transform().unwrap().into();
        let proj_mx: Matrix4<f32> = self.proj.into();
        proj_mx * view_mx
    }
}

pub trait App<R: gfx::Resources> {
    fn on_event<F: gfx::Factory<R>>(&mut self, Event, delta: f32, &mut F) -> bool;
    fn on_frame<C: gfx::CommandBuffer<R>>(&mut self, &mut gfx::Encoder<R, C>);
    fn do_iter<I, F, C>(&mut self, events: I, delta: f32, factory: &mut F, encoder: &mut gfx::Encoder<R, C>)
               -> bool where
        I: Iterator<Item=Event>,
        F: gfx::Factory<R>,
        C: gfx::CommandBuffer<R>,
    {
        for event in events {
            if !self.on_event(event, delta, factory) {
                return false;
            }
        }
        self.on_frame(encoder);
        true
    }
}

pub struct Game<R: gfx::Resources> {
    render: render::Render<R>,
    cam: Camera,
}

impl<R: gfx::Resources> Game<R> {
    pub fn new<F: gfx::Factory<R>>(settings: &Settings,
           out_color: gfx::handle::RenderTargetView<R, render::ColorFormat>,
           out_depth: gfx::handle::DepthStencilView<R, render::DepthFormat>,
           factory: &mut F) -> Game<R>
    {
        info!("Loading world parameters");
        let config = settings.get_level();
        let lev = level::load(&config);

        Game {
            render: render::init(factory, out_color, out_depth, &lev),
            cam: Camera {
                loc: cgmath::vec3(0.0, 0.0, 200.0),
                rot: cgmath::Quaternion::new(1.0, 0.0, 0.0, 0.0),
                proj: cgmath::PerspectiveFov {
                    fovy: cgmath::deg(45.0).into(),
                    aspect: settings.get_screen_aspect(),
                    near: 1.0,
                    far: 100000.0,
                },
            },
        }
    }
}

impl<R: gfx::Resources> App<R> for Game<R> {
    fn on_event<F: gfx::Factory<R>>(&mut self, event: Event, delta: f32, factory: &mut F) -> bool {
        use cgmath::Rotation3;
        use glutin::VirtualKeyCode as Key;
        let angle = cgmath::rad(delta * 2.0);
        let step = delta * 400.0;
        match event {
            Event::KeyboardInput(_, _, Some(Key::Escape)) |
            Event::Closed => return false,
            Event::KeyboardInput(_, _, Some(Key::L)) => self.render.reload(factory),
            Event::KeyboardInput(_, _, Some(Key::W)) =>
                self.cam.loc = self.cam.loc + cgmath::vec3(0.0, step, 0.0),
            Event::KeyboardInput(_, _, Some(Key::S)) =>
                self.cam.loc = self.cam.loc - cgmath::vec3(0.0, step, 0.0),
            Event::KeyboardInput(_, _, Some(Key::R)) =>
                self.cam.rot = self.cam.rot * cgmath::Quaternion::from_axis_angle(cgmath::Vector3::unit_x(), angle),
            Event::KeyboardInput(_, _, Some(Key::F)) =>
                self.cam.rot = self.cam.rot * cgmath::Quaternion::from_axis_angle(cgmath::Vector3::unit_x(), -angle),
            Event::KeyboardInput(_, _, Some(Key::A)) =>
                self.cam.rot = cgmath::Quaternion::from_axis_angle(cgmath::Vector3::unit_z(), angle) * self.cam.rot,
            Event::KeyboardInput(_, _, Some(Key::D)) =>
                self.cam.rot = cgmath::Quaternion::from_axis_angle(cgmath::Vector3::unit_z(), -angle) * self.cam.rot,
            _ => {},
        }
        true
    }
    fn on_frame<C: gfx::CommandBuffer<R>>(&mut self, enc: &mut gfx::Encoder<R, C>) {
        self.render.draw(enc, &self.cam);
    }
}

pub struct ModelView<R: gfx::Resources> {
    model: model::Model<R>,
    transform: cgmath::Decomposed<cgmath::Vector3<f32>, cgmath::Quaternion<f32>>,
    pso: gfx::PipelineState<R, render::object::Meta>,
    data: render::object::Data<R>,
    cam: Camera,
}

impl<R: gfx::Resources> ModelView<R> {
    pub fn new<F: gfx::Factory<R>>(path: &str, settings: &Settings,
               out_color: gfx::handle::RenderTargetView<R, render::ColorFormat>,
               out_depth: gfx::handle::DepthStencilView<R, render::DepthFormat>,
               factory: &mut F) -> ModelView<R>
    {
        use std::io::BufReader;
        use gfx::traits::FactoryExt;

        let pal_data = level::load_palette(&settings.get_object_palette_path());

        info!("Loading model {}", path);
        let mut file = BufReader::new(settings.open(path));
        let model = model::load_m3d(&mut file, factory);
        let data = render::object::Data {
            vbuf: model.body.buffer.clone(),
            locals: factory.create_constant_buffer(1),
            ctable: render::Render::create_color_table(factory),
            palette: render::Render::create_palette(&pal_data, factory),
            out_color: out_color,
            out_depth: out_depth,
        };

        ModelView {
            model: model,
            transform: cgmath::Decomposed {
                scale: 1.0,
                disp: cgmath::Vector3::unit_z(),
                rot: cgmath::One::one(),
            },
            pso: render::Render::create_object_pso(factory),
            data: data,
            cam: Camera {
                loc: cgmath::vec3(0.0, -40.0, 20.0),
                rot: cgmath::Rotation3::from_axis_angle(cgmath::Vector3::unit_x(), cgmath::Angle::turn_div_6()),
                proj: cgmath::PerspectiveFov {
                    fovy: cgmath::deg(45.0).into(),
                    aspect: settings.get_screen_aspect(),
                    near: 1.0,
                    far: 100.0,
                },
            },
        }
    }

    fn rotate(&mut self, angle: cgmath::Rad<f32>) {
        use cgmath::Transform;
        let other = cgmath::Decomposed {
            scale: 1.0,
            rot: cgmath::Rotation3::from_axis_angle(cgmath::Vector3::unit_z(), angle),
            disp: cgmath::Zero::zero(),
        };
        self.transform = other.concat(&self.transform);
    }
}

impl<R: gfx::Resources> App<R> for ModelView<R> {
    fn on_event<F: gfx::Factory<R>>(&mut self, event: Event, delta: f32, factory: &mut F) -> bool {
        use glutin::VirtualKeyCode as Key;
        let angle = cgmath::rad(delta * 2.0);
        match event {
            Event::KeyboardInput(_, _, Some(Key::Escape)) |
            Event::Closed => return false,
            Event::KeyboardInput(_, _, Some(Key::A)) => self.rotate(-angle),
            Event::KeyboardInput(_, _, Some(Key::D)) => self.rotate(angle),
            Event::KeyboardInput(_, _, Some(Key::L)) =>
                self.pso = render::Render::create_object_pso(factory),
            _ => {}, //TODO
        }
        true
    }
    fn on_frame<C: gfx::CommandBuffer<R>>(&mut self, enc: &mut gfx::Encoder<R, C>) {
        let model_trans: cgmath::Matrix4<f32> = self.transform.into();
        let locals = render::ObjectLocals {
            m_mvp: (self.cam.get_view_proj() * model_trans).into(),
        };
        enc.update_constant_buffer(&self.data.locals, &locals);
        enc.clear(&self.data.out_color, [0.1, 0.2, 0.3, 1.0]);
        enc.clear_depth(&self.data.out_depth, 1.0);
        enc.draw(&self.model.body.slice, &self.pso, &self.data);
    }
}
<commit_msg>Fixed rotation/movement controls<commit_after>use cgmath;
use glutin::Event;
use gfx;
use {level, model, render};
use config::Settings;

pub struct Camera {
    pub loc: cgmath::Vector3<f32>,
    pub rot: cgmath::Quaternion<f32>,
    pub proj: cgmath::PerspectiveFov<f32>,
}

impl Camera {
    pub fn get_view_proj(&self) -> cgmath::Matrix4<f32> {
        use cgmath::{Decomposed, Matrix4, Transform};
        let view = Decomposed {
            scale: 1.0,
            rot: self.rot,
            disp: self.loc,
        };
        let view_mx: Matrix4<f32> = view.inverse_transform().unwrap().into();
        let proj_mx: Matrix4<f32> = self.proj.into();
        proj_mx * view_mx
    }
}

pub trait App<R: gfx::Resources> {
    fn on_event<F: gfx::Factory<R>>(&mut self, Event, delta: f32, &mut F) -> bool;
    fn on_frame<C: gfx::CommandBuffer<R>>(&mut self, &mut gfx::Encoder<R, C>);
    fn do_iter<I, F, C>(&mut self, events: I, delta: f32, factory: &mut F, encoder: &mut gfx::Encoder<R, C>)
               -> bool where
        I: Iterator<Item=Event>,
        F: gfx::Factory<R>,
        C: gfx::CommandBuffer<R>,
    {
        for event in events {
            if !self.on_event(event, delta, factory) {
                return false;
            }
        }
        self.on_frame(encoder);
        true
    }
}

pub struct Game<R: gfx::Resources> {
    render: render::Render<R>,
    cam: Camera,
}

impl<R: gfx::Resources> Game<R> {
    pub fn new<F: gfx::Factory<R>>(settings: &Settings,
           out_color: gfx::handle::RenderTargetView<R, render::ColorFormat>,
           out_depth: gfx::handle::DepthStencilView<R, render::DepthFormat>,
           factory: &mut F) -> Game<R>
    {
        info!("Loading world parameters");
        let config = settings.get_level();
        let lev = level::load(&config);

        Game {
            render: render::init(factory, out_color, out_depth, &lev),
            cam: Camera {
                loc: cgmath::vec3(0.0, 0.0, 200.0),
                rot: cgmath::Quaternion::new(1.0, 0.0, 0.0, 0.0),
                proj: cgmath::PerspectiveFov {
                    fovy: cgmath::deg(45.0).into(),
                    aspect: settings.get_screen_aspect(),
                    near: 1.0,
                    far: 100000.0,
                },
            },
        }
    }

    fn move_cam(&mut self, step: f32) {
        use cgmath::{InnerSpace, Rotation};
        let mut back = self.cam.rot.rotate_vector(cgmath::Vector3::unit_z());
        back.z = 0.0;
        self.cam.loc -= back.normalize() * step;
    }
}

impl<R: gfx::Resources> App<R> for Game<R> {
    fn on_event<F: gfx::Factory<R>>(&mut self, event: Event, delta: f32, factory: &mut F) -> bool {
        use cgmath::Rotation3;
        use glutin::VirtualKeyCode as Key;
        let angle = cgmath::rad(delta * 2.0);
        let step = delta * 400.0;
        match event {
            Event::KeyboardInput(_, _, Some(Key::Escape)) |
            Event::Closed => return false,
            Event::KeyboardInput(_, _, Some(Key::L)) => self.render.reload(factory),
            Event::KeyboardInput(_, _, Some(Key::W)) => self.move_cam(step),
            Event::KeyboardInput(_, _, Some(Key::S)) => self.move_cam(-step),
            Event::KeyboardInput(_, _, Some(Key::R)) =>
                self.cam.rot = self.cam.rot * cgmath::Quaternion::from_axis_angle(cgmath::Vector3::unit_x(), angle),
            Event::KeyboardInput(_, _, Some(Key::F)) =>
                self.cam.rot = self.cam.rot * cgmath::Quaternion::from_axis_angle(cgmath::Vector3::unit_x(), -angle),
            Event::KeyboardInput(_, _, Some(Key::A)) =>
                self.cam.rot = cgmath::Quaternion::from_axis_angle(cgmath::Vector3::unit_z(), angle) * self.cam.rot,
            Event::KeyboardInput(_, _, Some(Key::D)) =>
                self.cam.rot = cgmath::Quaternion::from_axis_angle(cgmath::Vector3::unit_z(), -angle) * self.cam.rot,
            _ => {},
        }
        true
    }
    fn on_frame<C: gfx::CommandBuffer<R>>(&mut self, enc: &mut gfx::Encoder<R, C>) {
        self.render.draw(enc, &self.cam);
    }
}

pub struct ModelView<R: gfx::Resources> {
    model: model::Model<R>,
    transform: cgmath::Decomposed<cgmath::Vector3<f32>, cgmath::Quaternion<f32>>,
    pso: gfx::PipelineState<R, render::object::Meta>,
    data: render::object::Data<R>,
    cam: Camera,
}

impl<R: gfx::Resources> ModelView<R> {
    pub fn new<F: gfx::Factory<R>>(path: &str, settings: &Settings,
               out_color: gfx::handle::RenderTargetView<R, render::ColorFormat>,
               out_depth: gfx::handle::DepthStencilView<R, render::DepthFormat>,
               factory: &mut F) -> ModelView<R>
    {
        use std::io::BufReader;
        use gfx::traits::FactoryExt;

        let pal_data = level::load_palette(&settings.get_object_palette_path());

        info!("Loading model {}", path);
        let mut file = BufReader::new(settings.open(path));
        let model = model::load_m3d(&mut file, factory);
        let data = render::object::Data {
            vbuf: model.body.buffer.clone(),
            locals: factory.create_constant_buffer(1),
            ctable: render::Render::create_color_table(factory),
            palette: render::Render::create_palette(&pal_data, factory),
            out_color: out_color,
            out_depth: out_depth,
        };

        ModelView {
            model: model,
            transform: cgmath::Decomposed {
                scale: 1.0,
                disp: cgmath::Vector3::unit_z(),
                rot: cgmath::One::one(),
            },
            pso: render::Render::create_object_pso(factory),
            data: data,
            cam: Camera {
                loc: cgmath::vec3(0.0, -40.0, 20.0),
                rot: cgmath::Rotation3::from_axis_angle(cgmath::Vector3::unit_x(), cgmath::Angle::turn_div_6()),
                proj: cgmath::PerspectiveFov {
                    fovy: cgmath::deg(45.0).into(),
                    aspect: settings.get_screen_aspect(),
                    near: 1.0,
                    far: 100.0,
                },
            },
        }
    }

    fn rotate(&mut self, angle: cgmath::Rad<f32>) {
        use cgmath::Transform;
        let other = cgmath::Decomposed {
            scale: 1.0,
            rot: cgmath::Rotation3::from_axis_angle(cgmath::Vector3::unit_z(), angle),
            disp: cgmath::Zero::zero(),
        };
        self.transform = other.concat(&self.transform);
    }
}

impl<R: gfx::Resources> App<R> for ModelView<R> {
    fn on_event<F: gfx::Factory<R>>(&mut self, event: Event, delta: f32, factory: &mut F) -> bool {
        use glutin::VirtualKeyCode as Key;
        let angle = cgmath::rad(delta * 2.0);
        match event {
            Event::KeyboardInput(_, _, Some(Key::Escape)) |
            Event::Closed => return false,
            Event::KeyboardInput(_, _, Some(Key::A)) => self.rotate(-angle),
            Event::KeyboardInput(_, _, Some(Key::D)) => self.rotate(angle),
            Event::KeyboardInput(_, _, Some(Key::L)) =>
                self.pso = render::Render::create_object_pso(factory),
            _ => {}, //TODO
        }
        true
    }
    fn on_frame<C: gfx::CommandBuffer<R>>(&mut self, enc: &mut gfx::Encoder<R, C>) {
        let model_trans: cgmath::Matrix4<f32> = self.transform.into();
        let locals = render::ObjectLocals {
            m_mvp: (self.cam.get_view_proj() * model_trans).into(),
        };
        enc.update_constant_buffer(&self.data.locals, &locals);
        enc.clear(&self.data.out_color, [0.1, 0.2, 0.3, 1.0]);
        enc.clear_depth(&self.data.out_depth, 1.0);
        enc.draw(&self.model.body.slice, &self.pso, &self.data);
    }
}
<|endoftext|>


<commit_before>use core::intrinsics;

// TODO use `global_asm!`
#[naked]
#[no_mangle]
pub unsafe extern "aapcs" fn __aeabi_uidivmod() {
    asm!("push    { lr }
          sub     sp, sp, #4
          mov     r2, sp
          bl      __udivmodsi4
          ldr     r1, [sp]
          add     sp, sp, #4
          pop     { pc }");
    intrinsics::unreachable();
}

// TODO use `global_asm!`
#[naked]
#[no_mangle]
pub unsafe extern "aapcs" fn __aeabi_uldivmod() {
    asm!("push	{r11, lr}
          sub	sp, sp, #16
          add	r12, sp, #8
          str	r12, [sp]
          bl	__udivmoddi4
          ldr	r2, [sp, #8]
          ldr	r3, [sp, #12]
          add	sp, sp, #16
          pop	{r11, pc}");
    intrinsics::unreachable();
}

extern "C" {
    fn memcpy(dest: *mut u8, src: *const u8, n: usize) -> *mut u8;
    fn memmove(dest: *mut u8, src: *const u8, n: usize) -> *mut u8;
    fn memset(dest: *mut u8, c: i32, n: usize) -> *mut u8;
}

// FIXME: The `*4` and `*8` variants should be defined as aliases.

#[no_mangle]
pub unsafe extern "aapcs" fn __aeabi_memcpy(dest: *mut u8, src: *const u8, n: usize) {
    memcpy(dest, src, n);
}
#[no_mangle]
pub unsafe extern "aapcs" fn __aeabi_memcpy4(dest: *mut u8, src: *const u8, n: usize) {
    memcpy(dest, src, n);
}
#[no_mangle]
pub unsafe extern "aapcs" fn __aeabi_memcpy8(dest: *mut u8, src: *const u8, n: usize) {
    memcpy(dest, src, n);
}

#[no_mangle]
pub unsafe extern "aapcs" fn __aeabi_memmove(dest: *mut u8, src: *const u8, n: usize) {
    memmove(dest, src, n);
}
#[no_mangle]
pub unsafe extern "aapcs" fn __aeabi_memmove4(dest: *mut u8, src: *const u8, n: usize) {
    memmove(dest, src, n);
}
#[no_mangle]
pub unsafe extern "aapcs" fn __aeabi_memmove8(dest: *mut u8, src: *const u8, n: usize) {
    memmove(dest, src, n);
}

// Note the different argument order
#[no_mangle]
pub unsafe extern "aapcs" fn __aeabi_memset(dest: *mut u8, n: usize, c: i32) {
    memset(dest, c, n);
}
#[no_mangle]
pub unsafe extern "aapcs" fn __aeabi_memset4(dest: *mut u8, n: usize, c: i32) {
    memset(dest, c, n);
}
#[no_mangle]
pub unsafe extern "aapcs" fn __aeabi_memset8(dest: *mut u8, n: usize, c: i32) {
    memset(dest, c, n);
}

#[no_mangle]
pub unsafe extern "aapcs" fn __aeabi_memclr(dest: *mut u8, n: usize) {
    memset(dest, 0, n);
}
#[no_mangle]
pub unsafe extern "aapcs" fn __aeabi_memclr4(dest: *mut u8, n: usize) {
    memset(dest, 0, n);
}
#[no_mangle]
pub unsafe extern "aapcs" fn __aeabi_memclr8(dest: *mut u8, n: usize) {
    memset(dest, 0, n);
}
<commit_msg>note about calling convention<commit_after>use core::intrinsics;

// NOTE This function and the one below are implemented using assembly because they using a custom
// calling convention which can't be implemented using a normal Rust function
// TODO use `global_asm!`
#[naked]
#[no_mangle]
pub unsafe extern "aapcs" fn __aeabi_uidivmod() {
    asm!("push    { lr }
          sub     sp, sp, #4
          mov     r2, sp
          bl      __udivmodsi4
          ldr     r1, [sp]
          add     sp, sp, #4
          pop     { pc }");
    intrinsics::unreachable();
}

// TODO use `global_asm!`
#[naked]
#[no_mangle]
pub unsafe extern "aapcs" fn __aeabi_uldivmod() {
    asm!("push	{r11, lr}
          sub	sp, sp, #16
          add	r12, sp, #8
          str	r12, [sp]
          bl	__udivmoddi4
          ldr	r2, [sp, #8]
          ldr	r3, [sp, #12]
          add	sp, sp, #16
          pop	{r11, pc}");
    intrinsics::unreachable();
}

extern "C" {
    fn memcpy(dest: *mut u8, src: *const u8, n: usize) -> *mut u8;
    fn memmove(dest: *mut u8, src: *const u8, n: usize) -> *mut u8;
    fn memset(dest: *mut u8, c: i32, n: usize) -> *mut u8;
}

// FIXME: The `*4` and `*8` variants should be defined as aliases.

#[no_mangle]
pub unsafe extern "aapcs" fn __aeabi_memcpy(dest: *mut u8, src: *const u8, n: usize) {
    memcpy(dest, src, n);
}
#[no_mangle]
pub unsafe extern "aapcs" fn __aeabi_memcpy4(dest: *mut u8, src: *const u8, n: usize) {
    memcpy(dest, src, n);
}
#[no_mangle]
pub unsafe extern "aapcs" fn __aeabi_memcpy8(dest: *mut u8, src: *const u8, n: usize) {
    memcpy(dest, src, n);
}

#[no_mangle]
pub unsafe extern "aapcs" fn __aeabi_memmove(dest: *mut u8, src: *const u8, n: usize) {
    memmove(dest, src, n);
}
#[no_mangle]
pub unsafe extern "aapcs" fn __aeabi_memmove4(dest: *mut u8, src: *const u8, n: usize) {
    memmove(dest, src, n);
}
#[no_mangle]
pub unsafe extern "aapcs" fn __aeabi_memmove8(dest: *mut u8, src: *const u8, n: usize) {
    memmove(dest, src, n);
}

// Note the different argument order
#[no_mangle]
pub unsafe extern "aapcs" fn __aeabi_memset(dest: *mut u8, n: usize, c: i32) {
    memset(dest, c, n);
}
#[no_mangle]
pub unsafe extern "aapcs" fn __aeabi_memset4(dest: *mut u8, n: usize, c: i32) {
    memset(dest, c, n);
}
#[no_mangle]
pub unsafe extern "aapcs" fn __aeabi_memset8(dest: *mut u8, n: usize, c: i32) {
    memset(dest, c, n);
}

#[no_mangle]
pub unsafe extern "aapcs" fn __aeabi_memclr(dest: *mut u8, n: usize) {
    memset(dest, 0, n);
}
#[no_mangle]
pub unsafe extern "aapcs" fn __aeabi_memclr4(dest: *mut u8, n: usize) {
    memset(dest, 0, n);
}
#[no_mangle]
pub unsafe extern "aapcs" fn __aeabi_memclr8(dest: *mut u8, n: usize) {
    memset(dest, 0, n);
}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use std::fmt;

#[deriving(PartialEq, Show)]
pub struct NumericValue {
    pub representation: String,
    pub value: f64,
    pub int_value: Option<i64>,
}

#[deriving(PartialEq, Show, Copy)]
pub struct SourceLocation {
    pub line: uint,  // First line is 1
    pub column: uint,  // First character of a line is at column 1
}

pub type Node = (Token, SourceLocation);  // TODO this is not a good name

#[deriving(PartialEq, Show)]
pub enum Token {
    // Preserved tokens.
    Ident(String),
    AtKeyword(String),
    Hash(String),
    IDHash(String),  // Hash that is a valid ID selector.
    QuotedString(String),
    Url(String),
    Delim(char),
    Number(NumericValue),
    Percentage(NumericValue),
    Dimension(NumericValue, String),
    UnicodeRange(u32, u32),  // (start, end) of range
    WhiteSpace,
    Colon,  // :
    Semicolon,  // ;
    Comma,  // ,
    IncludeMatch, // ~=
    DashMatch, // |=
    PrefixMatch, // ^=
    SuffixMatch, // $=
    SubstringMatch, // *=
    Column, // ||
    CDO,  // <!--
    CDC,  // -->

    // Function
    Function(String),  // name

    // Simple block
    ParenthesisBlock,  // (…)
    SquareBracketBlock,  // […]
    CurlyBracketBlock,  // {…}

    // These are always invalid
    BadUrl,
    BadString,
    CloseParenthesis, // )
    CloseSquareBracket, // ]
    CloseCurlyBracket, // }
}

#[deriving(PartialEq)]
pub struct Declaration {
    pub location: SourceLocation,
    pub name: String,
    pub value: Vec<Token>,
    pub important: bool,
}

#[deriving(PartialEq)]
pub struct QualifiedRule {
    pub location: SourceLocation,
    pub prelude: Vec<Token>,
    pub block: Vec<Node>,
}

#[deriving(PartialEq)]
pub struct AtRule {
    pub location: SourceLocation,
    pub name: String,
    pub prelude: Vec<Token>,
    pub block: Option<Vec<Node>>,
}

#[deriving(PartialEq)]
pub enum DeclarationListItem {
    Declaration(Declaration),
    AtRule(AtRule),
}

#[deriving(PartialEq)]
pub enum Rule {
    QualifiedRule(QualifiedRule),
    AtRule(AtRule),
}

#[deriving(PartialEq, Copy)]
pub struct SyntaxError {
    pub location: SourceLocation,
    pub reason: ErrorReason,
}

#[deriving(PartialEq, Show, Copy)]
pub enum ErrorReason {
    EmptyInput,  // Parsing a single "thing", found only whitespace.
    ExtraInput,  // Found more non-whitespace after parsing a single "thing".
    MissingQualifiedRuleBlock,  // EOF in a qualified rule prelude, before '{'
    InvalidDeclarationSyntax,
    InvalidBangImportantSyntax,
    // This is meant to be extended
}

impl fmt::Show for SyntaxError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}:{} {}", self.location.line, self.location.column, self.reason)
    }
}
<commit_msg>Remove ast.rs file left over from 41fa928b7df1acc05b16af5f4ec3edb229274957.<commit_after><|endoftext|>


<commit_before>
use std::comm::{Chan, Port, SharedChan};

use std::hashmap::{HashMap};

use std::task::{task};

use object::{JavaObject, JavaObjectId};

// Enumerates all possible types of accessing objects.
// Threads wishing to acquire ownership of an object specify one of
// these access modi and are served accordingly.
#[deriving(Eq)]
pub enum RequestObjectAccessType {

	// Normal access - any access of an object's field requires
	// threads to own objects, which is made possible through
	// this access mode. Arbitrary modifications are possible,
	// but no guarantee is made that between two instructions on
	// one thread context not another thread kick in and obtains
	// access.
	OBJECT_ACCESS_Normal,

	// Request to also lock the object's monitor, thus enforcing
	// mutual exclusion with other threads who also go through
	// the monitor for accessing the object.
	//
	// Note that this does *not* actually lock() the monitor,
	// it only ensures that the object's monitor is not currently
	// lock by somebody else by the time the requesting thread
	// receives object ownership.
	OBJECT_ACCESS_Monitor,

	// Request to also lock the object's monitor, and to be given
	// preference over threads attempting to access with the
	// OBJECT_ACCESS_Monitor flag. This is used in response to
	// a wait() call on a monitor to make sure that such threads
	// are given preference over threads accessing a monitor from
	// outside.
	//
	// This also does *not* lock() the monitor.
	OBJECT_ACCESS_MonitorPriority,
}

// OB_REMOTE_OBJECT_OP() detail messages, enumerating all supported
// operations on remote (i.e. owned by other thread) objects.
pub enum RemoteObjectOpMessage {

	// request from thread a to addref object b. If the object
	// is not known to the broker yet, this registers the object
	// as being owned by thread a.
	REMOTE_ADD_REF,

	// request from thread a to release object b. If thread a
	// owns this object, the message informs the broker that the
	// object has been deleted.
	REMOTE_RELEASE,

	// thread a asks which thread owns object b. Response is the
	// same message with a (c, b) tuple, c is the id of the the
	// owning thread.
	REMOTE_WHO_OWNS,

	// thread a asks to take over ownership of object b with the
	// given access type. When granted, a OB_RQ_DISOWN message
	// returns the object.
	REMOTE_OWN(RequestObjectAccessType),

	// thread a abandons ownership of object b. When send from
	// broker to a thread c, this means that this thread should
	// take over ownership of the object. When send from a thread
	// to broker in response to a RQ_OWN message, the last tuple
	// element indicates the original asker.
	REMOTE_DISOWN(~JavaObject, uint),
}

// Top-level ObjectBroker message type
pub enum ObjectBrokerMessage {
	// ## Object management ##
	OB_REMOTE_OBJECT_OP(uint, JavaObjectId, RemoteObjectOpMessage),

	// ## Thread management ##
	// a new thread a registers with the object broker
	OB_REGISTER(uint, Chan<ObjectBrokerMessage>),

	// ## VM management ##
	OB_SHUTDOWN
}

// The ObjectBroker handles ownership for concurrently accessed
// objects. At every time, every object has one well-defined owner.
// If a thread needs access to an object that it does not currently
// own, it submits a OB_RQ_OWN message to the object broker, which
// in turn asks the thread who owns the object to relinquish it using
// a OB_RQ_DISOWN message. The owning thread gives up ownership and
// sends a OB_RQ_DISOWN message to the broker, which forwards it to
// the original thread and updates its book-keeping to reflect the
// change in ownership.
//
// The ObjectBroker keeps a HM of object ids mapped to their owning
// thread ids.
//
// When a thread dies, it forwards all of its alive objects to the
// object broker using a OB_RQ_DISOWN message. The broker, in turn,
// keeps those objects internally until another thread demands to
// own them.
pub struct ObjectBroker {
	priv objects_with_owners: HashMap<JavaObjectId, uint>,

	priv in_port : Port<ObjectBrokerMessage>,
	priv out_chan : HashMap<uint, Chan<ObjectBrokerMessage>>,

	// this is duplicated into all threads
	priv in_shared_chan : SharedChan<ObjectBrokerMessage>,

	// once an OB_RQ_OWN message has been sent to a thread,
	// all further requests to the same object are saved
	// up and dispatched to whomever gains new ownership
	// of the objects.
	priv waiting_shelf : HashMap<JavaObjectId, ~[ObjectBrokerMessage]>

	// TODO: how to guarantee object transfer if threads are blocking?
}

static OB_INITIAL_OBJ_HASHMAP_CAPACITY : uint = 4096;
static OB_INITIAL_THREAD_CAPACITY : uint = 16;
static OB_INITIAL_WAITING_SHELF_CAPACITY : uint = 256;

impl ObjectBroker {

	// ----------------------------------------------
	pub fn new() -> ObjectBroker
	{
	 	let (out,input) = SharedChan::new();
		ObjectBroker {
			objects_with_owners : HashMap::with_capacity(OB_INITIAL_OBJ_HASHMAP_CAPACITY),

			in_port : out,
			in_shared_chan : input,
			out_chan : HashMap::with_capacity(OB_INITIAL_THREAD_CAPACITY),
			waiting_shelf : HashMap::with_capacity(OB_INITIAL_WAITING_SHELF_CAPACITY)
		}
	}

	// ----------------------------------------------
	// Launches the object broker. Returns a SharedChan object that can be used
	// to direct messages to the broker. Send an OB_SHUTDOWN to terminate
	// operation.
	pub fn launch(mut self) -> SharedChan<ObjectBrokerMessage> {
		let ret_chan = self.in_shared_chan.clone();

		// ownership of th ObjectBroker instance moves into the task,
		// all the caller gets back is a channel to communicate.
		do spawn {
			let mut s = self;
			while s.handle_message() {}
		}
		return ret_chan;
	}

	// IMPL

	// ----------------------------------------------
	fn handle_message(&mut self) -> bool {
		match self.in_port.recv() {

			OB_REMOTE_OBJECT_OP(a, b, remote_op) => {
				self.handle_object_op(a, b, remote_op)
			},

			OB_REGISTER(a, chan) => {
				let ref mut threads = self.out_chan;
				assert!(!threads.contains_key(&a));
				threads.insert(a, chan);
				debug!("object broker registered with thread {}", a);
			},

			OB_SHUTDOWN => {
				debug!("object broker shutting down");
				return false;
			},
		}
		return true;
	}

	// ----------------------------------------------
	fn handle_object_op(&mut self, a : uint, b : JavaObjectId, op : RemoteObjectOpMessage)
	{
		let ref mut objects = self.objects_with_owners;
		let ref mut threads = self.out_chan;
		let ref mut shelf = self.waiting_shelf;

		// check if the object in question is currently being transferred
		// between threads and any further requests are therefore shelved
		// until a new owner is in place
		match op {
			REMOTE_DISOWN(ref obj,ref receiver) => (),
			_ => {
				match shelf.find_mut(&b) {
					Some(ref v) => {
						v.push( OB_REMOTE_OBJECT_OP(a,b,op) );
						return;
					},
					_ => ()
				}
			}
		}

		match op {
			REMOTE_ADD_REF => {
				// for somebody to have a reference to a field and thus
				// being able to addref/release it, they must have had
				// accss to an object that was owned by this thread.
				// As this object must have been transferred using the
				// object broker and messages are guaranteed to be
				// ordered, we must already know about that object.

				// Therefore, whether the object is present in the HM
				// is safe for determining whether it is new.
				match objects.find(&b) {
					Some(owner) => {
						let t = threads.get(owner);
						t.send(OB_REMOTE_OBJECT_OP(a,b,REMOTE_ADD_REF));
						return;
					},
					_ => (),
				}
				objects.insert(b,a);
			},

			REMOTE_RELEASE => {
				// correctness follows by the same reasoning as for AddRef()
				let owner = *objects.get(&b);
				if owner == a {
					objects.remove(&b);
				}
				else {
					let t = threads.get(&owner);
					t.send(OB_REMOTE_OBJECT_OP(a,b,REMOTE_RELEASE));
				}
			},

			REMOTE_WHO_OWNS => {
				let t = threads.get(&a);
				t.send(OB_REMOTE_OBJECT_OP(*objects.get(&b),b,REMOTE_WHO_OWNS));
			},

			REMOTE_OWN(rmode) => {
				// b must be in objects as per the same reasoning as
				// OB_RQ_ADD_REF() is sound.

				let owner = *objects.get(&b);
				// cannot request object oned by oneself
				// bookkeeping of own owned objects is consistent,
				// so failure to hold this would be a logic error.
				assert!(owner != a);

				// TODO: what if somebody else concurrently requested
				// owning the object, but has not received it yet?

				let t = threads.get(&owner);
				t.send(OB_REMOTE_OBJECT_OP(a, b, REMOTE_OWN(rmode)));

				// from now on, shelve any further requests pertaining
				// to this object until the new owner has taken over.
				shelf.insert(b, ~[]);
			},

			REMOTE_DISOWN(obj,receiver) => {
				// must own object to be able to disown it
				assert!(*objects.get(&b) == a);

				*objects.get_mut(&b) = receiver;
				let t = threads.get(&receiver);
				t.send(OB_REMOTE_OBJECT_OP(a, b, REMOTE_DISOWN(obj, receiver )));

				// cleanup shelf, sending the messages all in the right order
				let mut sh = shelf.pop(&b).unwrap();
				while sh.len() > 0 {
					t.send(sh.shift());
				}
			},
		}
	}
}

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

	use object::{JavaObject};
	use std::task::{task};

	use classloader::tests::{test_get_real_classloader};

	type test_proc = proc(SharedChan<ObjectBrokerMessage>, Port<ObjectBrokerMessage>) -> ();

	fn test_setup(a : test_proc, b : test_proc) {
		let mut ob = ObjectBroker::new();
		let chan = ob.launch();

		// thread 1
		let input1 = chan.clone();
		let mut t1 = task();
		let f1 = t1.future_result();
		do t1.spawn {
			let (port, chan) = Chan::new();
			input1.send(OB_REGISTER(1, chan));

			a(input1, port);
		}

		// thread 2
		let input2 = chan.clone();
		let mut t2 = task();
		let f2 = t2.future_result();
		do t2.spawn {
			let (port, chan) = Chan::new();
			input2.send(OB_REGISTER(2, chan));

			b(input2, port);
		}

		f1.recv();
		f2.recv();
	}

	#[test]
	fn test_object_broker() {
		let mut cl = test_get_real_classloader();
		let v = cl.add_from_classfile("EmptyClass").unwrap_all();

		let (sync_port, sync_chan) = Chan::new();
		test_setup(
			proc(input : SharedChan<ObjectBrokerMessage>, output: Port<ObjectBrokerMessage>) {
				// register object 15
				input.send(OB_REMOTE_OBJECT_OP(1,15,REMOTE_ADD_REF));
				sync_chan.send(1);

				let request = output.recv();
				match request {
					OB_REMOTE_OBJECT_OP(2,15,REMOTE_OWN (mode) ) => {
						assert_eq!(mode, OBJECT_ACCESS_Normal);
						input.send(OB_REMOTE_OBJECT_OP(1,15,REMOTE_DISOWN(~JavaObject::new(*v,0),2)))
					},
					_ => assert!(false),
				}
			},
			proc(input : SharedChan<ObjectBrokerMessage>, output: Port<ObjectBrokerMessage>) {
				// we have to ensure that object 15 is registered. Normally,
				// this is implicitly guaranteed because how would we otherwise
				// know about its id?
				sync_port.recv();

				// want to own object 15
				input.send(OB_REMOTE_OBJECT_OP(2,15,REMOTE_OWN(OBJECT_ACCESS_Normal) ));

				let response = output.recv();
				match response {
					OB_REMOTE_OBJECT_OP(1,15,REMOTE_DISOWN(val,2)) => {
						let cl = val.get_class();
						assert_eq!(*cl.get().get_name(), ~"EmptyClass");
						input.send(OB_SHUTDOWN);
					},
					_ => assert!(false),
				}
			}
		);
	}
}

// TODO: tests of more complex scenarios
<commit_msg>ObjectBroker: fix proper handlin of shelved messages<commit_after>
use std::comm::{Chan, Port, SharedChan};

use std::hashmap::{HashMap};

use std::task::{task};

use object::{JavaObject, JavaObjectId};

// Enumerates all possible types of accessing objects.
// Threads wishing to acquire ownership of an object specify one of
// these access modi and are served accordingly.
#[deriving(Eq)]
pub enum RequestObjectAccessType {

	// Normal access - any access of an object's field requires
	// threads to own objects, which is made possible through
	// this access mode. Arbitrary modifications are possible,
	// but no guarantee is made that between two instructions on
	// one thread context not another thread kick in and obtains
	// access.
	OBJECT_ACCESS_Normal,

	// Request to also lock the object's monitor, thus enforcing
	// mutual exclusion with other threads who also go through
	// the monitor for accessing the object.
	//
	// Note that this does *not* actually lock() the monitor,
	// it only ensures that the object's monitor is not currently
	// lock by somebody else by the time the requesting thread
	// receives object ownership.
	OBJECT_ACCESS_Monitor,

	// Request to also lock the object's monitor, and to be given
	// preference over threads attempting to access with the
	// OBJECT_ACCESS_Monitor flag. This is used in response to
	// a wait() call on a monitor to make sure that such threads
	// are given preference over threads accessing a monitor from
	// outside.
	//
	// This also does *not* lock() the monitor.
	OBJECT_ACCESS_MonitorPriority,
}

// OB_REMOTE_OBJECT_OP() detail messages, enumerating all supported
// operations on remote (i.e. owned by other thread) objects.
pub enum RemoteObjectOpMessage {

	// request from thread a to addref object b. If the object
	// is not known to the broker yet, this registers the object
	// as being owned by thread a.
	REMOTE_ADD_REF,

	// request from thread a to release object b. If thread a
	// owns this object, the message informs the broker that the
	// object has been deleted.
	REMOTE_RELEASE,

	// thread a asks which thread owns object b. Response is the
	// same message with a (c, b) tuple, c is the id of the the
	// owning thread.
	REMOTE_WHO_OWNS,

	// thread a asks to take over ownership of object b with the
	// given access type. When granted, a OB_RQ_DISOWN message
	// returns the object.
	REMOTE_OWN(RequestObjectAccessType),

	// thread a abandons ownership of object b. When send from
	// broker to a thread c, this means that this thread should
	// take over ownership of the object. When send from a thread
	// to broker in response to a RQ_OWN message, the last tuple
	// element indicates the original asker.
	REMOTE_DISOWN(~JavaObject, uint),
}

// Top-level ObjectBroker message type
pub enum ObjectBrokerMessage {
	// ## Object management ##
	OB_REMOTE_OBJECT_OP(uint, JavaObjectId, RemoteObjectOpMessage),

	// ## Thread management ##
	// a new thread a registers with the object broker
	OB_REGISTER(uint, Chan<ObjectBrokerMessage>),

	// ## VM management ##
	OB_SHUTDOWN
}

// The ObjectBroker handles ownership for concurrently accessed
// objects. At every time, every object has one well-defined owner.
// If a thread needs access to an object that it does not currently
// own, it submits a OB_RQ_OWN message to the object broker, which
// in turn asks the thread who owns the object to relinquish it using
// a OB_RQ_DISOWN message. The owning thread gives up ownership and
// sends a OB_RQ_DISOWN message to the broker, which forwards it to
// the original thread and updates its book-keeping to reflect the
// change in ownership.
//
// The ObjectBroker keeps a HM of object ids mapped to their owning
// thread ids.
//
// When a thread dies, it forwards all of its alive objects to the
// object broker using a OB_RQ_DISOWN message. The broker, in turn,
// keeps those objects internally until another thread demands to
// own them.
pub struct ObjectBroker {
	priv objects_with_owners: HashMap<JavaObjectId, uint>,

	priv in_port : Port<ObjectBrokerMessage>,
	priv out_chan : HashMap<uint, Chan<ObjectBrokerMessage>>,

	// this is duplicated into all threads
	priv in_shared_chan : SharedChan<ObjectBrokerMessage>,

	// once an OB_RQ_OWN message has been sent to a thread,
	// all further requests to the same object are saved
	// up and dispatched to whomever gains new ownership
	// of the objects.
	priv waiting_shelf : HashMap<JavaObjectId, ~[ObjectBrokerMessage]>

	// TODO: how to guarantee object transfer if threads are blocking?
}

static OB_INITIAL_OBJ_HASHMAP_CAPACITY : uint = 4096;
static OB_INITIAL_THREAD_CAPACITY : uint = 16;
static OB_INITIAL_WAITING_SHELF_CAPACITY : uint = 256;

impl ObjectBroker {

	// ----------------------------------------------
	pub fn new() -> ObjectBroker
	{
	 	let (out,input) = SharedChan::new();
		ObjectBroker {
			objects_with_owners : HashMap::with_capacity(OB_INITIAL_OBJ_HASHMAP_CAPACITY),

			in_port : out,
			in_shared_chan : input,
			out_chan : HashMap::with_capacity(OB_INITIAL_THREAD_CAPACITY),
			waiting_shelf : HashMap::with_capacity(OB_INITIAL_WAITING_SHELF_CAPACITY)
		}
	}

	// ----------------------------------------------
	// Launches the object broker. Returns a SharedChan object that can be used
	// to direct messages to the broker. Send an OB_SHUTDOWN to terminate
	// operation.
	pub fn launch(mut self) -> SharedChan<ObjectBrokerMessage> {
		let ret_chan = self.in_shared_chan.clone();

		// ownership of th ObjectBroker instance moves into the task,
		// all the caller gets back is a channel to communicate.
		do spawn {
			let mut s = self;
			while s.handle_message() {}
		}
		return ret_chan;
	}

	// IMPL

	// ----------------------------------------------
	fn handle_message(&mut self) -> bool {
		match self.in_port.recv() {

			OB_REMOTE_OBJECT_OP(a, b, remote_op) => {
				self.handle_object_op(a, b, remote_op)
			},

			OB_REGISTER(a, chan) => {
				let ref mut threads = self.out_chan;
				assert!(!threads.contains_key(&a));
				threads.insert(a, chan);
				debug!("object broker registered with thread {}", a);
			},

			OB_SHUTDOWN => {
				debug!("object broker shutting down");
				return false;
			},
		}
		return true;
	}

	// ----------------------------------------------
	fn handle_object_op(&mut self, a : uint, b : JavaObjectId, op : RemoteObjectOpMessage)
	{
		// check if the object in question is currently being transferred
		// between threads and any further requests are therefore shelved
		// until a new owner is in place
		match op {
			REMOTE_WHO_OWNS => (),
			REMOTE_DISOWN(obj,receiver) => {
				{	let ref mut objects = self.objects_with_owners;
					let ref mut threads = self.out_chan;

					// must own object to be able to disown it
					assert!(*objects.get(&b) == a);

					*objects.get_mut(&b) = receiver;
					let t = threads.get(&receiver);
					t.send(OB_REMOTE_OBJECT_OP(a, b, REMOTE_DISOWN(obj, receiver )));
				}

				// cleanup shelf, sending the messages all in the right order,
				// but not more than one OWN message
				let mut sh = self.waiting_shelf.pop(&b).unwrap();
				while sh.len() > 0 {
					match sh.shift() {
						OB_REMOTE_OBJECT_OP(a, b, op) => self.handle_object_op(a, b, op),
						_ => fail!("logic error, cannot shelve this message"),
					}
				}
				return;
			},
			_ => {
				match self.waiting_shelf.find_mut(&b) {
					Some(ref v) => {
						v.push( OB_REMOTE_OBJECT_OP(a,b,op) );
						return;
					},
					_ => ()
				}
			}
		}

		let ref mut objects = self.objects_with_owners;
		let ref mut threads = self.out_chan;

		match op {
			REMOTE_ADD_REF => {
				// for somebody to have a reference to a field and thus
				// being able to addref/release it, they must have had
				// accss to an object that was owned by this thread.
				// As this object must have been transferred using the
				// object broker and messages are guaranteed to be
				// ordered, we must already know about that object.

				// Therefore, whether the object is present in the HM
				// is safe for determining whether it is new.
				match objects.find(&b) {
					Some(owner) => {
						let t = threads.get(owner);
						t.send(OB_REMOTE_OBJECT_OP(a,b,REMOTE_ADD_REF));
						return;
					},
					_ => (),
				}
				objects.insert(b,a);
			},

			REMOTE_RELEASE => {
				// correctness follows by the same reasoning as for AddRef()
				let owner = *objects.get(&b);
				if owner == a {
					objects.remove(&b);
				}
				else {
					let t = threads.get(&owner);
					t.send(OB_REMOTE_OBJECT_OP(a,b,REMOTE_RELEASE));
				}
			},

			REMOTE_WHO_OWNS => {
				let t = threads.get(&a);
				t.send(OB_REMOTE_OBJECT_OP(*objects.get(&b),b,REMOTE_WHO_OWNS));
			},

			REMOTE_OWN(rmode) => {
				// b must be in objects as per the same reasoning as
				// OB_RQ_ADD_REF() is sound.

				let owner = *objects.get(&b);
				// cannot request object oned by oneself
				// bookkeeping of own owned objects is consistent,
				// so failure to hold this would be a logic error.
				assert!(owner != a);

				// TODO: what if somebody else concurrently requested
				// owning the object, but has not received it yet?

				let t = threads.get(&owner);
				t.send(OB_REMOTE_OBJECT_OP(a, b, REMOTE_OWN(rmode)));

				// from now on, shelve any further requests pertaining
				// to this object until the new owner has taken over.
				self.waiting_shelf.insert(b, ~[]);
			},

			REMOTE_DISOWN(obj,receiver) => fail!("logic error, handled earlier"),
		}
	}
}

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

	use object::{JavaObject};
	use std::task::{task};

	use classloader::tests::{test_get_real_classloader};

	type test_proc = proc(SharedChan<ObjectBrokerMessage>, Port<ObjectBrokerMessage>) -> ();

	fn test_setup(a : test_proc, b : test_proc) {
		let mut ob = ObjectBroker::new();
		let chan = ob.launch();

		// thread 1
		let input1 = chan.clone();
		let mut t1 = task();
		let f1 = t1.future_result();
		do t1.spawn {
			let (port, chan) = Chan::new();
			input1.send(OB_REGISTER(1, chan));

			a(input1, port);
		}

		// thread 2
		let input2 = chan.clone();
		let mut t2 = task();
		let f2 = t2.future_result();
		do t2.spawn {
			let (port, chan) = Chan::new();
			input2.send(OB_REGISTER(2, chan));

			b(input2, port);
		}

		f1.recv();
		f2.recv();
	}

	#[test]
	fn test_object_broker() {
		let mut cl = test_get_real_classloader();
		let v = cl.add_from_classfile("EmptyClass").unwrap_all();

		let (sync_port, sync_chan) = Chan::new();
		test_setup(
			proc(input : SharedChan<ObjectBrokerMessage>, output: Port<ObjectBrokerMessage>) {
				// register object 15
				input.send(OB_REMOTE_OBJECT_OP(1,15,REMOTE_ADD_REF));
				sync_chan.send(1);

				let request = output.recv();
				match request {
					OB_REMOTE_OBJECT_OP(2,15,REMOTE_OWN (mode) ) => {
						assert_eq!(mode, OBJECT_ACCESS_Normal);
						input.send(OB_REMOTE_OBJECT_OP(1,15,REMOTE_DISOWN(~JavaObject::new(*v,0),2)))
					},
					_ => assert!(false),
				}
			},
			proc(input : SharedChan<ObjectBrokerMessage>, output: Port<ObjectBrokerMessage>) {
				// we have to ensure that object 15 is registered. Normally,
				// this is implicitly guaranteed because how would we otherwise
				// know about its id?
				sync_port.recv();

				// want to own object 15
				input.send(OB_REMOTE_OBJECT_OP(2,15,REMOTE_OWN(OBJECT_ACCESS_Normal) ));

				let response = output.recv();
				match response {
					OB_REMOTE_OBJECT_OP(1,15,REMOTE_DISOWN(val,2)) => {
						let cl = val.get_class();
						assert_eq!(*cl.get().get_name(), ~"EmptyClass");
						input.send(OB_SHUTDOWN);
					},
					_ => assert!(false),
				}
			}
		);
	}
}

// TODO: tests of more complex scenarios
<|endoftext|>


<commit_before>use std::io::Read;
use std::thread;

use reqwest::Client;
use serde_json;
use serde_json::Value;
use serde_json::value::Map;

use error::Result;
use error::Error::{RequestFailed, JsonNotFound};
use objects::update::Update;
use objects::user::User;
use objects::message::Message;
use value_extension::ValueExtension;

/// A struct which contains things associated with the bot.
#[derive(Debug)]
pub struct Bot {
    id: i64,
    first_name: String,
    last_name: Option<String>,
    username: Option<String>,
    client: Client,
    pub bot_url: String,
}

impl Bot {
    /// Return a new bot struct.
    pub fn new(bot_url: String) -> Result<Self> {
        let client = Client::new()?;
        let rjson = Bot::get_me(&client, &bot_url)?;
        let id = rjson.as_required_i64("id")?;
        let first_name = rjson.as_required_string("first_name")?;
        let last_name = rjson.as_optional_string("last_name");
        let username = rjson.as_optional_string("username");

        Ok(Bot {
            id: id,
            first_name: first_name,
            last_name: last_name,
            username: username,
            client: client,
            bot_url: bot_url,
        })
    }

    /// Gets the information about the bot.
    fn get_me(client: &Client, bot_url: &str) -> Result<Value> {
        let path = ["getMe"];
        let url = ::construct_api_url(bot_url, &path);
        let mut resp = client.get(&url).send()?;

        if resp.status().is_success() {
            let rjson: Value = resp.json()?;
            rjson.find("result").cloned().ok_or(JsonNotFound)
        } else {
            Err(RequestFailed(*resp.status()))
        }
    }

    pub fn get_updates(&self,
                       offset: i32,
                       limit: Option<i32>,
                       timeout: Option<i32>,
                       network_delay: Option<i32>)
                       -> Result<Option<Vec<Update>>> {
        let limit = limit.unwrap_or(100);
        let timeout = timeout.unwrap_or(0);
        // Use network_delay when it gets implemented
        let network_delay = network_delay.unwrap_or(5);
        let path = ["getUpdates"];
        let path_url = ::construct_api_url(&self.bot_url, &path);
        let url = format!("{}?offset={}&limit={}&timeout={}",
                          path_url,
                          offset,
                          limit,
                          timeout);
        let mut data = self.client.get(&url).send()?;
        let rjson: Value = data.json()?;
        let updates_json = rjson.find("result");

        if let Some(result) = updates_json {
            let updates: Vec<Update> = serde_json::from_value(result.clone())?;
            Ok(Some(updates))
        } else {
            Ok(None)
        }
    }

    pub fn send_message(&self,
                        chat_id: &i64,
                        text: &str,
                        parse_mode: Option<&str>,
                        disable_web_page_preview: Option<&bool>,
                        disable_notification: Option<&bool>,
                        reply_to_message_id: Option<&i32>)
                        -> Result<Message> {
        let chat_id: &str = &chat_id.to_string();
        let parse_mode = parse_mode.unwrap_or("None");
        let disable_web_page_preview: &str = &disable_web_page_preview.unwrap_or(&false)
            .to_string();
        let disable_notification: &str = &disable_notification.unwrap_or(&false).to_string();
        let reply_to_message_id: &str = &reply_to_message_id.map(|i| i.to_string())
            .unwrap_or("None".to_string());
        let path = ["sendMessage"];
        let url = ::construct_api_url(&self.bot_url, &path);
        let params = [("chat_id", chat_id),
                      ("text", text),
                      ("parse_mode", parse_mode),
                      ("disable_web_page_preview", disable_web_page_preview),
                      ("disable_notification", disable_notification),
                      ("reply_to_message_id", reply_to_message_id)];
        let mut data = self.client.post(&url).form(&params).send()?;
        let rjson: Value = data.json()?;
        let message_json = rjson.find("result").ok_or(JsonNotFound)?;
        let message: Message = serde_json::from_value(message_json.clone())?;
        Ok(message)
    }

    pub fn reply_to_message(&self, update: &Update, text: &str) -> Result<Message> {
        let chat_id = update.clone().message.unwrap().chat.id;
        self.send_message(&chat_id, text, None, None, None, None)
    }
}
<commit_msg>Making attributes public and username required<commit_after>use std::io::Read;
use std::thread;

use reqwest::Client;
use serde_json;
use serde_json::Value;
use serde_json::value::Map;

use error::Result;
use error::Error::{RequestFailed, JsonNotFound};
use objects::update::Update;
use objects::user::User;
use objects::message::Message;
use value_extension::ValueExtension;

/// A struct which contains things associated with the bot.
#[derive(Debug)]
pub struct Bot {
    pub id: i64,
    pub first_name: String,
    pub last_name: Option<String>,
    pub username: String,
    client: Client,
    pub bot_url: String,
}

impl Bot {
    /// Return a new bot struct.
    pub fn new(bot_url: String) -> Result<Self> {
        let client = Client::new()?;
        let rjson = Bot::get_me(&client, &bot_url)?;
        let id = rjson.as_required_i64("id")?;
        let first_name = rjson.as_required_string("first_name")?;
        let last_name = rjson.as_optional_string("last_name");
        let username = rjson.as_required_string("username")?;

        Ok(Bot {
            id: id,
            first_name: first_name,
            last_name: last_name,
            username: username,
            client: client,
            bot_url: bot_url,
        })
    }

    /// Gets the information about the bot.
    fn get_me(client: &Client, bot_url: &str) -> Result<Value> {
        let path = ["getMe"];
        let url = ::construct_api_url(bot_url, &path);
        let mut resp = client.get(&url).send()?;

        if resp.status().is_success() {
            let rjson: Value = resp.json()?;
            rjson.find("result").cloned().ok_or(JsonNotFound)
        } else {
            Err(RequestFailed(*resp.status()))
        }
    }

    pub fn get_updates(&self,
                       offset: i32,
                       limit: Option<i32>,
                       timeout: Option<i32>,
                       network_delay: Option<i32>)
                       -> Result<Option<Vec<Update>>> {
        let limit = limit.unwrap_or(100);
        let timeout = timeout.unwrap_or(0);
        // Use network_delay when it gets implemented
        let network_delay = network_delay.unwrap_or(5);
        let path = ["getUpdates"];
        let path_url = ::construct_api_url(&self.bot_url, &path);
        let url = format!("{}?offset={}&limit={}&timeout={}",
                          path_url,
                          offset,
                          limit,
                          timeout);
        let mut data = self.client.get(&url).send()?;
        let rjson: Value = data.json()?;
        let updates_json = rjson.find("result");

        if let Some(result) = updates_json {
            let updates: Vec<Update> = serde_json::from_value(result.clone())?;
            Ok(Some(updates))
        } else {
            Ok(None)
        }
    }

    pub fn send_message(&self,
                        chat_id: &i64,
                        text: &str,
                        parse_mode: Option<&str>,
                        disable_web_page_preview: Option<&bool>,
                        disable_notification: Option<&bool>,
                        reply_to_message_id: Option<&i32>)
                        -> Result<Message> {
        let chat_id: &str = &chat_id.to_string();
        let parse_mode = parse_mode.unwrap_or("None");
        let disable_web_page_preview: &str = &disable_web_page_preview.unwrap_or(&false)
            .to_string();
        let disable_notification: &str = &disable_notification.unwrap_or(&false).to_string();
        let reply_to_message_id: &str = &reply_to_message_id.map(|i| i.to_string())
            .unwrap_or("None".to_string());
        let path = ["sendMessage"];
        let url = ::construct_api_url(&self.bot_url, &path);
        let params = [("chat_id", chat_id),
                      ("text", text),
                      ("parse_mode", parse_mode),
                      ("disable_web_page_preview", disable_web_page_preview),
                      ("disable_notification", disable_notification),
                      ("reply_to_message_id", reply_to_message_id)];
        let mut data = self.client.post(&url).form(&params).send()?;
        let rjson: Value = data.json()?;
        let message_json = rjson.find("result").ok_or(JsonNotFound)?;
        let message: Message = serde_json::from_value(message_json.clone())?;
        Ok(message)
    }

    pub fn reply_to_message(&self, update: &Update, text: &str) -> Result<Message> {
        let chat_id = update.clone().message.unwrap().chat.id;
        self.send_message(&chat_id, text, None, None, None, None)
    }
}
<|endoftext|>


<commit_before>use std::thread::{self,Thread,Builder};
use std::sync::mpsc::{self,channel,Sender,Receiver};
use std::collections::HashMap;

#[derive(Debug,Clone,PartialEq,Eq,Hash)]
pub enum Tag {
  Msg
}

#[derive(Clone)]
pub enum Message {
  Subscribe(Tag, Sender<Message>),
  SubscribeOk,
  Msg(String)
}

pub fn start_bus() -> Sender<Message> {
  let (tx,rx) = channel::<Message>();

  thread::spawn(move|| {
    let mut bus = Bus {
      rx: rx,
      senders: HashMap::new()
    };

    bus.loop_message();
  });
  tx
}

struct Bus {
  rx: Receiver<Message>,
  senders: HashMap<Tag, Vec<Sender<Message>>>
}

impl Bus {
  fn loop_message(&mut self) {
    loop {
      if ! self.handle_message() {
        break;
      }
    }
  }

  fn handle_message(&mut self) -> bool {
    match &self.rx.recv() {
      &Ok(Message::Subscribe(ref tag, ref tx)) => {
        self.subscribe(tag, tx);
        println!("SUBSCRIBED");
        return true;
      },
      &Ok(Message::Msg(ref s)) => {
        println!("GOT MSG");
        if let &Some(v) = &self.senders.get(&Tag::Msg) {
          println!("GOT MSG 2");
          for tx in v {
            println!("GOT MSG 3");
            tx.send(Message::Msg(s.clone()));
          }
        }
        return true;
      },
      &Err(_) => {
        println!("the bus's channel is closed, exiting");
        return false;
      }
      &Ok(_) => {
        println!("invalid message");
        // FIXME: maybe we should not stop if there's an invalid message
        return false;
      }
    }
  }

  fn subscribe(&mut self, t: &Tag, tx: &Sender<Message>) {
    println!("X");
    if ! &self.senders.contains_key(t) {
      let mut v = Vec::new();
      let t2 = t.clone();
      &self.senders.insert(t2, v);
      println!("Y");
    }
    if let Some(ref mut v) = self.senders.get_mut(t) {
      v.push(tx.clone());
      tx.send(Message::SubscribeOk);
      println!("Z");
    }
  }
}

#[test]
fn bus_test() {
  let tx = start_bus();

  let (tx2,rx2) = channel();
  println!("AA");
  tx.send(Message::Subscribe(Tag::Msg, tx2));
  println!("BB");

  if let Ok(Message::SubscribeOk) = rx2.recv() {
    println!("successfully subscribed");
    let test = String::new() + "test";
    tx.send(Message::Msg(test.clone()));

    if let Ok(Message::Msg(s)) = rx2.recv() {
      assert_eq!(s, test);
    } else {
      assert!(false);
    }
  } else {
    assert!(false);
  }
}
<commit_msg>Command data structure for Bus<commit_after>use std::thread::{self,Thread,Builder};
use std::sync::mpsc::{self,channel,Sender,Receiver};
use std::collections::HashMap;

#[derive(Debug,Clone,PartialEq,Eq,Hash)]
pub struct Acl {
    app_id: String,
    hostname: String,
    path_begin: String
}

#[derive(Debug,Clone,PartialEq,Eq,Hash)]
pub struct Instance {
    app_id: String,
    ip_address: String,
    port: u16
}

#[derive(Debug,Clone,PartialEq,Eq,Hash)]
pub enum Command {
    AddAcl(Acl),
    RemoveAcl(Acl),
    AddInstance(Instance),
    RemoveInstance(Instance)
}

#[derive(Debug,Clone,PartialEq,Eq,Hash)]
pub enum Tag {
    AddAcl,
    RemoveAcl,
    AddInstance,
    RemoveInstance
}

#[derive(Clone)]
pub enum Message {
  Subscribe(Tag, Sender<Message>),
  SubscribeOk,
  Msg(Tag, Command)
}

pub fn start_bus() -> Sender<Message> {
  let (tx,rx) = channel::<Message>();

  thread::spawn(move|| {
    let mut bus = Bus {
      rx: rx,
      senders: HashMap::new()
    };

    bus.loop_message();
  });
  tx
}

struct Bus {
  rx: Receiver<Message>,
  senders: HashMap<Tag, Vec<Sender<Message>>>
}

impl Bus {
  fn loop_message(&mut self) {
    loop {
      if ! self.handle_message() {
        break;
      }
    }
  }

  fn handle_message(&mut self) -> bool {
    match &self.rx.recv() {
      &Ok(Message::Subscribe(ref tag, ref tx)) => {
        self.subscribe(tag, tx);
        println!("SUBSCRIBED");
        return true;
      },
      &Ok(Message::Msg(ref t, ref c)) => {
        println!("GOT MSG");
        if let &Some(v) = &self.senders.get(&t) {
          println!("GOT MSG 2");
          for tx in v {
            println!("GOT MSG 3");
            tx.send(Message::Msg(t.clone(), c.clone()));
          }
        }
        return true;
      },
      &Err(_) => {
        println!("the bus's channel is closed, exiting");
        return false;
      }
      &Ok(_) => {
        println!("invalid message");
        // FIXME: maybe we should not stop if there's an invalid message
        return false;
      }
    }
  }

  fn subscribe(&mut self, t: &Tag, tx: &Sender<Message>) {
    println!("X");
    if ! &self.senders.contains_key(t) {
      let mut v = Vec::new();
      let t2 = t.clone();
      &self.senders.insert(t2, v);
      println!("Y");
    }
    if let Some(ref mut v) = self.senders.get_mut(t) {
      v.push(tx.clone());
      tx.send(Message::SubscribeOk);
      println!("Z");
    }
  }
}

#[test]
fn bus_test() {
  let tx = start_bus();

  let (tx2,rx2) = channel();
  println!("AA");
  tx.send(Message::Subscribe(Tag::AddAcl, tx2));
  println!("BB");

  if let Ok(Message::SubscribeOk) = rx2.recv() {
    println!("successfully subscribed");
    let tag = Tag::AddAcl;
    let command = Command::AddAcl(
      Acl {
        app_id: String::new() + "app_e74eb0d4-e01a-4a09-af46-7ecab7157d32",
        hostname: String::new() + "cltdl.fr",
        path_begin: String::new() + ""
      }
    );
    tx.send(Message::Msg(tag.clone(), command.clone()));

    if let Ok(Message::Msg(t, c)) = rx2.recv() {
      assert_eq!(t, tag);
      assert_eq!(c, command);
    } else {
      assert!(false);
    }
  } else {
    assert!(false);
  }
}
<|endoftext|>