<commit_before>use na::{Vector2, Vector3, Vector4, Rotation2};
use super::Line;
use geometry::ToRenderables;
use rendering;

pub struct Rectangle {
    pub length: f64,  /// x-axis
    pub height: f64,  /// y-axis
    pub rot: Rotation2<f64>,
    pub pos: Vector2<f64>,
}

impl Rectangle {
    pub fn new_regular(
            length: f64,
            height: f64,
            pos: Vector2<f64>,
        ) -> Rectangle {
        Rectangle {
            length,
            height,
            rot: Rotation2::new(0.0),
            pos,
        }
    }

    pub fn new_with_rotation(
            length: f64,
            height: f64,
            pos: Vector2<f64>,
            rotation: Rotation2<f64>,
        ) -> Rectangle {
        Rectangle {
            length,
            height,
            rot: rotation,
            pos,
        }
    }

    pub fn new_regular_fixed(
            length: f64,
            height: f64,
            pos: Vector2<f64>,
        ) -> Rectangle {
        Rectangle {
            length,
            height,
            rot: Rotation2::new(0.0),
            pos,
        }
    }

    pub fn new_from_line(line: Line, thickness: f64) -> Self {
        let line_length = line.get_length();

        Rectangle {
            length: line_length,
            height: thickness,
            rot: Rotation2::new(line.get_angle()),
            pos: line.get_midpoint(),
        }
    }
}

impl ToRenderables for Rectangle {
    fn to_renderables(&self, color: Vector4<f64>, depth: f64, fixed: bool) -> Vec<Box<rendering::Renderable>> {
        vec![
            Box::new(
                rendering::Rectangle {
                    length: self.length,
                    height: self.height,
                    rot: self.rot,
                    pos: Vector3::new(self.pos.x, self.pos.y, depth),
                    color: color,
                    fixed: fixed,
                }
            )
        ]
    }
}

<commit_msg>Fill out Rectangle geometry functions<commit_after>use na::{Vector2, Vector3, Vector4, Rotation2};
use super::Line;
use geometry::{ToRenderables, TwoDTransformable};
use rendering;
use std::f64::consts::PI;

#[derive(Copy, Clone, Debug)]
pub struct Rectangle {
    pub length: f64,  /// x-axis
    pub height: f64,  /// y-axis
    pub rot: Rotation2<f64>,
    pub pos: Vector2<f64>,
}

impl Rectangle {
    pub fn new_regular(
            length: f64,
            height: f64,
            pos: Vector2<f64>,
        ) -> Rectangle {
        Rectangle {
            length,
            height,
            rot: Rotation2::new(0.0),
            pos,
        }
    }

    pub fn new_with_rotation(
            length: f64,
            height: f64,
            pos: Vector2<f64>,
            rotation: Rotation2<f64>,
        ) -> Rectangle {
        Rectangle {
            length,
            height,
            rot: rotation,
            pos,
        }
    }

    pub fn new_with_whole_rotation_angle(
            length: f64,
            height: f64,
            pos: Vector2<f64>,
            angle: f64,
        ) -> Rectangle {
        Rectangle {
            length,
            height,
            rot: Rotation2::new(2.0 * PI * angle),
            pos,
        }
    }

    pub fn new_regular_fixed(
            length: f64,
            height: f64,
            pos: Vector2<f64>,
        ) -> Rectangle {
        Rectangle {
            length,
            height,
            rot: Rotation2::new(0.0),
            pos,
        }
    }

    pub fn new_from_line(line: Line, thickness: f64) -> Self {
        let line_length = line.get_length();

        Rectangle {
            length: line_length,
            height: thickness,
            rot: Rotation2::new(line.get_angle()),
            pos: line.get_midpoint(),
        }
    }
}

impl TwoDTransformable for Rectangle {
    fn shift_by(&mut self, shift: Vector2<f64>) {
        self.pos += shift;
    }

    fn rotate(&mut self, rot_angle: f64) {
        let rot_mat = Rotation2::new(rot_angle);
        self.rot = rot_mat * self.rot;
    }
}

impl ToRenderables for Rectangle {
    fn to_renderables(&self, color: Vector4<f64>, depth: f64, fixed: bool) -> Vec<Box<rendering::Renderable>> {
        vec![
            Box::new(
                rendering::Rectangle {
                    length: self.length,
                    height: self.height,
                    rot: self.rot,
                    pos: Vector3::new(self.pos.x, self.pos.y, depth),
                    color: color,
                    fixed: fixed,
                }
            )
        ]
    }
}

<|endoftext|>


<commit_before>use serde::de::{Deserialize, Error as DeError, MapAccess, Visitor};
use std::fmt::{Display, Formatter, Result as FmtResult, Write as FmtWrite};
use std::str::FromStr;
use std::error::Error as StdError;
use internal::prelude::*;
use model::*;

#[cfg(all(feature = "cache", feature = "model"))]
use CACHE;
#[cfg(feature = "model")]
use http;

/// An emoji reaction to a message.
#[derive(Clone, Debug, Deserialize)]
pub struct Reaction {
    /// The [`Channel`] of the associated [`Message`].
    ///
    /// [`Channel`]: enum.Channel.html
    /// [`Message`]: struct.Message.html
    pub channel_id: ChannelId,
    /// The reactive emoji used.
    pub emoji: ReactionType,
    /// The Id of the [`Message`] that was reacted to.
    ///
    /// [`Message`]: struct.Message.html
    pub message_id: MessageId,
    /// The Id of the [`User`] that sent the reaction.
    ///
    /// [`User`]: struct.User.html
    pub user_id: UserId,
}

#[cfg(feature = "model")]
impl Reaction {
    /// Deletes the reaction, but only if the current user is the user who made
    /// the reaction or has permission to.
    ///
    /// **Note**: Requires the [Manage Messages] permission, _if_ the current
    /// user did not perform the reaction.
    ///
    /// # Errors
    ///
    /// If the `cache` is enabled, then returns a
    /// [`ModelError::InvalidPermissions`] if the current user does not have
    /// the required [permissions].
    ///
    /// [`ModelError::InvalidPermissions`]: enum.ModelError.html#variant.InvalidPermissions
    /// [Manage Messages]: permissions/constant.MANAGE_MESSAGES.html
    /// [permissions]: permissions
    pub fn delete(&self) -> Result<()> {
        let user_id = feature_cache! {
            {
                let user = if self.user_id == CACHE.read().user.id {
                    None
                } else {
                    Some(self.user_id.0)
                };

                // If the reaction is one _not_ made by the current user, then ensure
                // that the current user has permission* to delete the reaction.
                //
                // Normally, users can only delete their own reactions.
                //
                // * The `Manage Messages` permission.
                if user.is_some() {
                    let req = Permissions::MANAGE_MESSAGES;

                    if !utils::user_has_perms(self.channel_id, req).unwrap_or(true) {
                        return Err(Error::Model(ModelError::InvalidPermissions(req)));
                    }
                }

                user
            } else {
                Some(self.user_id.0)
            }
        };

        http::delete_reaction(self.channel_id.0, self.message_id.0, user_id, &self.emoji)
    }

    /// Retrieves the list of [`User`]s who have reacted to a [`Message`] with a
    /// certain [`Emoji`].
    ///
    /// The default `limit` is `50` - specify otherwise to receive a different
    /// maximum number of users. The maximum that may be retrieve at a time is
    /// `100`, if a greater number is provided then it is automatically reduced.
    ///
    /// The optional `after` attribute is to retrieve the users after a certain
    /// user. This is useful for pagination.
    ///
    /// **Note**: Requires the [Read Message History] permission.
    ///
    /// # Errors
    ///
    /// Returns a [`ModelError::InvalidPermissions`] if the current user does
    /// not have the required [permissions].
    ///
    /// [`ModelError::InvalidPermissions`]: enum.ModelError.html#variant.InvalidPermissions
    /// [`Emoji`]: struct.Emoji.html
    /// [`Message`]: struct.Message.html
    /// [`User`]: struct.User.html
    /// [Read Message History]: permissions/constant.READ_MESSAGE_HISTORY.html
    /// [permissions]: permissions
    pub fn users<R, U>(&self,
                       reaction_type: R,
                       limit: Option<u8>,
                       after: Option<U>)
                       -> Result<Vec<User>>
        where R: Into<ReactionType>, U: Into<UserId> {
        http::get_reaction_users(
            self.channel_id.0,
            self.message_id.0,
            &reaction_type.into(),
            limit.unwrap_or(50),
            after.map(|u| u.into().0),
        )
    }
}

/// The type of a [`Reaction`] sent.
///
/// [`Reaction`]: struct.Reaction.html
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
pub enum ReactionType {
    /// A reaction with a [`Guild`]s custom [`Emoji`], which is unique to the
    /// guild.
    ///
    /// [`Emoji`]: struct.Emoji.html
    /// [`Guild`]: struct.Guild.html
    Custom {
        /// The Id of the custom [`Emoji`].
        ///
        /// [`Emoji`]: struct.Emoji.html
        id: EmojiId,
        /// The name of the custom emoji. This is primarily used for decoration
        /// and distinguishing the emoji client-side.
        name: Option<String>,
    },
    /// A reaction with a twemoji.
    Unicode(String),
}

impl<'de> Deserialize<'de> for ReactionType {
    fn deserialize<D: Deserializer<'de>>(deserializer: D) -> StdResult<Self, D::Error> {
        #[derive(Deserialize)]
        #[serde(field_identifier, rename_all = "snake_case")]
        enum Field {
            Id,
            Name,
        }

        struct ReactionTypeVisitor;

        impl<'de> Visitor<'de> for ReactionTypeVisitor {
            type Value = ReactionType;

            fn expecting(&self, formatter: &mut Formatter) -> FmtResult {
                formatter.write_str("enum ReactionType")
            }

            fn visit_map<V: MapAccess<'de>>(self, mut map: V) -> StdResult<Self::Value, V::Error> {
                let mut id = None;
                let mut name = None;

                while let Some(key) = map.next_key()? {
                    match key {
                        Field::Id => {
                            if id.is_some() {
                                return Err(DeError::duplicate_field("id"));
                            }

                            if let Ok(emoji_id) = map.next_value::<EmojiId>() {
                                id = Some(emoji_id)
                            }
                        },
                        Field::Name => {
                            if name.is_some() {
                                return Err(DeError::duplicate_field("name"));
                            }

                            name = Some(map.next_value()?);
                        },
                    }
                }

                let name = name.ok_or_else(|| DeError::missing_field("name"))?;

                Ok(if let Some(id) = id {
                    ReactionType::Custom {
                        id: id,
                        name: name,
                    }
                } else {
                    ReactionType::Unicode(name.unwrap())
                })
            }
        }

        deserializer.deserialize_map(ReactionTypeVisitor)
    }
}

#[cfg(any(feature = "model", feature = "http"))]
impl ReactionType {
    /// Creates a data-esque display of the type. This is not very useful for
    /// displaying, as the primary client can not render it, but can be useful
    /// for debugging.
    ///
    /// **Note**: This is mainly for use internally. There is otherwise most
    /// likely little use for it.
    pub fn as_data(&self) -> String {
        match *self {
            ReactionType::Custom {
                id,
                ref name,
            } => format!("{}:{}", name.as_ref().map_or("", |s| s.as_str()), id),
            ReactionType::Unicode(ref unicode) => unicode.clone(),
        }
    }
}

#[cfg(feature = "model")]
impl From<char> for ReactionType {
    /// Creates a `ReactionType` from a `char`.
    ///
    /// # Examples
    ///
    /// Reacting to a message with an apple:
    ///
    /// ```rust,no_run
    /// # use serenity::model::ChannelId;
    /// # use std::error::Error;
    /// #
    /// # fn try_main() -> Result<(), Box<Error>> {
    /// #     let message = ChannelId(0).message(0)?;
    /// #
    /// message.react('🍎')?;
    /// #     Ok(())
    /// # }
    /// #
    /// # fn main() {
    /// #     try_main().unwrap();
    /// # }
    /// ```
    fn from(ch: char) -> ReactionType { ReactionType::Unicode(ch.to_string()) }
}

impl From<Emoji> for ReactionType {
    fn from(emoji: Emoji) -> ReactionType {
        ReactionType::Custom {
            id: emoji.id,
            name: Some(emoji.name),
        }
    }
}

impl From<String> for ReactionType {
    fn from(unicode: String) -> ReactionType { ReactionType::Unicode(unicode) }
}

impl<'a> From<&'a str> for ReactionType {
    /// Creates a `ReactionType` from a string slice.
    ///
    /// # Examples
    ///
    /// Creating a `ReactionType` from a `🍎`, modeling a similar API as the
    /// rest of the library:
    ///
    /// ```rust
    /// use serenity::model::ReactionType;
    ///
    /// fn foo<R: Into<ReactionType>>(bar: R) {
    ///     println!("{:?}", bar.into());
    /// }
    ///
    /// foo("🍎");
    /// ```
    fn from(unicode: &str) -> ReactionType { ReactionType::Unicode(unicode.to_string()) }
}

// TODO: Change this to `!` once it becomes stable.

#[derive(Debug)]
pub struct NeverFails;

impl Display for NeverFails {
    fn fmt(&self, f: &mut Formatter) -> FmtResult {
        write!(f, "never fails")
    }
}

impl StdError for NeverFails {
    fn description(&self) -> &str {
        "never fails"
    }
}

impl FromStr for ReactionType {
    type Err = NeverFails;

    fn from_str(s: &str) -> ::std::result::Result<Self, Self::Err> {
        Ok(ReactionType::from(s))
    }
}

impl Display for ReactionType {
    /// Formats the reaction type, displaying the associated emoji in a
    /// way that clients can understand.
    ///
    /// If the type is a [custom][`ReactionType::Custom`] emoji, then refer to
    /// the documentation for [emoji's formatter][`Emoji::fmt`] on how this is
    /// displayed. Otherwise, if the type is a
    /// [unicode][`ReactionType::Unicode`], then the inner unicode is displayed.
    ///
    /// [`Emoji::fmt`]: struct.Emoji.html#method.fmt
    /// [`ReactionType::Custom`]: enum.ReactionType.html#variant.Custom
    /// [`ReactionType::Unicode`]: enum.ReactionType.html#variant.Unicode
    fn fmt(&self, f: &mut Formatter) -> FmtResult {
        match *self {
            ReactionType::Custom {
                id,
                ref name,
            } => {
                f.write_char('<')?;
                f.write_char(':')?;
                f.write_str(name.as_ref().map_or("", |s| s.as_str()))?;
                f.write_char(':')?;
                Display::fmt(&id, f)?;
                f.write_char('>')
            },
            ReactionType::Unicode(ref unicode) => f.write_str(unicode),
        }
    }
}
<commit_msg>Actually, change `NeverFails` to a void enum<commit_after>use serde::de::{Deserialize, Error as DeError, MapAccess, Visitor};
use std::fmt::{Display, Formatter, Result as FmtResult, Write as FmtWrite};
use std::str::FromStr;
use std::error::Error as StdError;
use internal::prelude::*;
use model::*;

#[cfg(all(feature = "cache", feature = "model"))]
use CACHE;
#[cfg(feature = "model")]
use http;

/// An emoji reaction to a message.
#[derive(Clone, Debug, Deserialize)]
pub struct Reaction {
    /// The [`Channel`] of the associated [`Message`].
    ///
    /// [`Channel`]: enum.Channel.html
    /// [`Message`]: struct.Message.html
    pub channel_id: ChannelId,
    /// The reactive emoji used.
    pub emoji: ReactionType,
    /// The Id of the [`Message`] that was reacted to.
    ///
    /// [`Message`]: struct.Message.html
    pub message_id: MessageId,
    /// The Id of the [`User`] that sent the reaction.
    ///
    /// [`User`]: struct.User.html
    pub user_id: UserId,
}

#[cfg(feature = "model")]
impl Reaction {
    /// Deletes the reaction, but only if the current user is the user who made
    /// the reaction or has permission to.
    ///
    /// **Note**: Requires the [Manage Messages] permission, _if_ the current
    /// user did not perform the reaction.
    ///
    /// # Errors
    ///
    /// If the `cache` is enabled, then returns a
    /// [`ModelError::InvalidPermissions`] if the current user does not have
    /// the required [permissions].
    ///
    /// [`ModelError::InvalidPermissions`]: enum.ModelError.html#variant.InvalidPermissions
    /// [Manage Messages]: permissions/constant.MANAGE_MESSAGES.html
    /// [permissions]: permissions
    pub fn delete(&self) -> Result<()> {
        let user_id = feature_cache! {
            {
                let user = if self.user_id == CACHE.read().user.id {
                    None
                } else {
                    Some(self.user_id.0)
                };

                // If the reaction is one _not_ made by the current user, then ensure
                // that the current user has permission* to delete the reaction.
                //
                // Normally, users can only delete their own reactions.
                //
                // * The `Manage Messages` permission.
                if user.is_some() {
                    let req = Permissions::MANAGE_MESSAGES;

                    if !utils::user_has_perms(self.channel_id, req).unwrap_or(true) {
                        return Err(Error::Model(ModelError::InvalidPermissions(req)));
                    }
                }

                user
            } else {
                Some(self.user_id.0)
            }
        };

        http::delete_reaction(self.channel_id.0, self.message_id.0, user_id, &self.emoji)
    }

    /// Retrieves the list of [`User`]s who have reacted to a [`Message`] with a
    /// certain [`Emoji`].
    ///
    /// The default `limit` is `50` - specify otherwise to receive a different
    /// maximum number of users. The maximum that may be retrieve at a time is
    /// `100`, if a greater number is provided then it is automatically reduced.
    ///
    /// The optional `after` attribute is to retrieve the users after a certain
    /// user. This is useful for pagination.
    ///
    /// **Note**: Requires the [Read Message History] permission.
    ///
    /// # Errors
    ///
    /// Returns a [`ModelError::InvalidPermissions`] if the current user does
    /// not have the required [permissions].
    ///
    /// [`ModelError::InvalidPermissions`]: enum.ModelError.html#variant.InvalidPermissions
    /// [`Emoji`]: struct.Emoji.html
    /// [`Message`]: struct.Message.html
    /// [`User`]: struct.User.html
    /// [Read Message History]: permissions/constant.READ_MESSAGE_HISTORY.html
    /// [permissions]: permissions
    pub fn users<R, U>(&self,
                       reaction_type: R,
                       limit: Option<u8>,
                       after: Option<U>)
                       -> Result<Vec<User>>
        where R: Into<ReactionType>, U: Into<UserId> {
        http::get_reaction_users(
            self.channel_id.0,
            self.message_id.0,
            &reaction_type.into(),
            limit.unwrap_or(50),
            after.map(|u| u.into().0),
        )
    }
}

/// The type of a [`Reaction`] sent.
///
/// [`Reaction`]: struct.Reaction.html
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
pub enum ReactionType {
    /// A reaction with a [`Guild`]s custom [`Emoji`], which is unique to the
    /// guild.
    ///
    /// [`Emoji`]: struct.Emoji.html
    /// [`Guild`]: struct.Guild.html
    Custom {
        /// The Id of the custom [`Emoji`].
        ///
        /// [`Emoji`]: struct.Emoji.html
        id: EmojiId,
        /// The name of the custom emoji. This is primarily used for decoration
        /// and distinguishing the emoji client-side.
        name: Option<String>,
    },
    /// A reaction with a twemoji.
    Unicode(String),
}

impl<'de> Deserialize<'de> for ReactionType {
    fn deserialize<D: Deserializer<'de>>(deserializer: D) -> StdResult<Self, D::Error> {
        #[derive(Deserialize)]
        #[serde(field_identifier, rename_all = "snake_case")]
        enum Field {
            Id,
            Name,
        }

        struct ReactionTypeVisitor;

        impl<'de> Visitor<'de> for ReactionTypeVisitor {
            type Value = ReactionType;

            fn expecting(&self, formatter: &mut Formatter) -> FmtResult {
                formatter.write_str("enum ReactionType")
            }

            fn visit_map<V: MapAccess<'de>>(self, mut map: V) -> StdResult<Self::Value, V::Error> {
                let mut id = None;
                let mut name = None;

                while let Some(key) = map.next_key()? {
                    match key {
                        Field::Id => {
                            if id.is_some() {
                                return Err(DeError::duplicate_field("id"));
                            }

                            if let Ok(emoji_id) = map.next_value::<EmojiId>() {
                                id = Some(emoji_id)
                            }
                        },
                        Field::Name => {
                            if name.is_some() {
                                return Err(DeError::duplicate_field("name"));
                            }

                            name = Some(map.next_value()?);
                        },
                    }
                }

                let name = name.ok_or_else(|| DeError::missing_field("name"))?;

                Ok(if let Some(id) = id {
                    ReactionType::Custom {
                        id: id,
                        name: name,
                    }
                } else {
                    ReactionType::Unicode(name.unwrap())
                })
            }
        }

        deserializer.deserialize_map(ReactionTypeVisitor)
    }
}

#[cfg(any(feature = "model", feature = "http"))]
impl ReactionType {
    /// Creates a data-esque display of the type. This is not very useful for
    /// displaying, as the primary client can not render it, but can be useful
    /// for debugging.
    ///
    /// **Note**: This is mainly for use internally. There is otherwise most
    /// likely little use for it.
    pub fn as_data(&self) -> String {
        match *self {
            ReactionType::Custom {
                id,
                ref name,
            } => format!("{}:{}", name.as_ref().map_or("", |s| s.as_str()), id),
            ReactionType::Unicode(ref unicode) => unicode.clone(),
        }
    }
}

#[cfg(feature = "model")]
impl From<char> for ReactionType {
    /// Creates a `ReactionType` from a `char`.
    ///
    /// # Examples
    ///
    /// Reacting to a message with an apple:
    ///
    /// ```rust,no_run
    /// # use serenity::model::ChannelId;
    /// # use std::error::Error;
    /// #
    /// # fn try_main() -> Result<(), Box<Error>> {
    /// #     let message = ChannelId(0).message(0)?;
    /// #
    /// message.react('🍎')?;
    /// #     Ok(())
    /// # }
    /// #
    /// # fn main() {
    /// #     try_main().unwrap();
    /// # }
    /// ```
    fn from(ch: char) -> ReactionType { ReactionType::Unicode(ch.to_string()) }
}

impl From<Emoji> for ReactionType {
    fn from(emoji: Emoji) -> ReactionType {
        ReactionType::Custom {
            id: emoji.id,
            name: Some(emoji.name),
        }
    }
}

impl From<String> for ReactionType {
    fn from(unicode: String) -> ReactionType { ReactionType::Unicode(unicode) }
}

impl<'a> From<&'a str> for ReactionType {
    /// Creates a `ReactionType` from a string slice.
    ///
    /// # Examples
    ///
    /// Creating a `ReactionType` from a `🍎`, modeling a similar API as the
    /// rest of the library:
    ///
    /// ```rust
    /// use serenity::model::ReactionType;
    ///
    /// fn foo<R: Into<ReactionType>>(bar: R) {
    ///     println!("{:?}", bar.into());
    /// }
    ///
    /// foo("🍎");
    /// ```
    fn from(unicode: &str) -> ReactionType { ReactionType::Unicode(unicode.to_string()) }
}

// TODO: Change this to `!` once it becomes stable.

#[derive(Debug)]
pub enum NeverFails {}

impl Display for NeverFails {
    fn fmt(&self, f: &mut Formatter) -> FmtResult {
        write!(f, "never fails")
    }
}

impl StdError for NeverFails {
    fn description(&self) -> &str {
        "never fails"
    }
}

impl FromStr for ReactionType {
    type Err = NeverFails;

    fn from_str(s: &str) -> ::std::result::Result<Self, Self::Err> {
        Ok(ReactionType::from(s))
    }
}

impl Display for ReactionType {
    /// Formats the reaction type, displaying the associated emoji in a
    /// way that clients can understand.
    ///
    /// If the type is a [custom][`ReactionType::Custom`] emoji, then refer to
    /// the documentation for [emoji's formatter][`Emoji::fmt`] on how this is
    /// displayed. Otherwise, if the type is a
    /// [unicode][`ReactionType::Unicode`], then the inner unicode is displayed.
    ///
    /// [`Emoji::fmt`]: struct.Emoji.html#method.fmt
    /// [`ReactionType::Custom`]: enum.ReactionType.html#variant.Custom
    /// [`ReactionType::Unicode`]: enum.ReactionType.html#variant.Unicode
    fn fmt(&self, f: &mut Formatter) -> FmtResult {
        match *self {
            ReactionType::Custom {
                id,
                ref name,
            } => {
                f.write_char('<')?;
                f.write_char(':')?;
                f.write_str(name.as_ref().map_or("", |s| s.as_str()))?;
                f.write_char(':')?;
                Display::fmt(&id, f)?;
                f.write_char('>')
            },
            ReactionType::Unicode(ref unicode) => f.write_str(unicode),
        }
    }
}
<|endoftext|>


<commit_before>use engine::{Game, Command, MessageType, Tile};
use engine::log;
use gui::{primitives};
use gui::{Console, Colors, Key, Widget};
use gui::screens::{self, Screen, ScreenChange};
use util::units::{AsTuple, Direction, Point, Size};

#[allow(missing_copy_implementations)]
pub struct GameScreen {
    map: Widget,
    info: Widget,
    messages: Widget,
    map_view: Point,
}

impl GameScreen {
    pub fn new() -> Box<Screen> {
        let info_widget_location = Point::new(0, 0);
        let map_widget_location = Point::new(15, 0);
        let message_widget_location = Point::new(15, 40);

        Box::new(
            GameScreen {
                map: Widget::new(map_widget_location, Size::new(64, 39)),
                info: Widget::new(info_widget_location, Size::new(14, 49)),
                messages: Widget::new(message_widget_location, Size::new(64, 9)),
                map_view: Point::new(0, 0),
            }
        )
    }
}

impl Screen for GameScreen {
    #[allow(unused)]
    fn input(&mut self, game: &mut Game, console: &mut Console) -> Option<ScreenChange> {
        if let Some(key) = console.check_for_keypress() {
            match key {
                Key::Up => {
                    game.do_command(Command::Walk(Direction::Up));
                },
                Key::Down => {
                    game.do_command(Command::Walk(Direction::Down));
                },
                Key::Left => {
                    game.do_command(Command::Walk(Direction::Left));
                },
                Key::Right => {
                    game.do_command(Command::Walk(Direction::Right));
                },
                Key::Escape => {
                    return Some(ScreenChange::AddScreen(screens::PauseScreen::new()));
                },
                _ => {}
            }
        }

        None
    }

    #[allow(unused)]
    fn update(&mut self, game: &mut Game, console: &mut Console) -> Option<ScreenChange> {
        game.step();
        None
    }

    #[allow(unused)]
    fn render(&mut self, game: &mut Game, console: &mut Console) {
        self.draw_borders(game, console);
        self.draw_info(game, console);
        self.draw_map(game, console);
        self.draw_player(game, console);
        self.draw_messages(game, console);
    }
}

impl GameScreen {
    #[allow(unused)]
    fn draw_borders(&self, game: &mut Game, console: &mut Console) {
        primitives::draw_box_with_title(console, "Map", self.map.rect);
        primitives::draw_box_with_title(console, "Info", self.info.rect);
        primitives::draw_box_with_title(console, "Messages", self.messages.rect);
    }

    #[allow(unused)]
    fn draw_info(&self, game: &mut Game, console: &mut Console) {
        return;
    }

    #[allow(unused)]
    fn draw_map(&self, game: &mut Game, console: &mut Console) {
        let map = &game.world.map;

        let (ux, uy) = self.map_view.as_tuple();
        let (width, height) : (usize, usize) = self.map.rect.inner_size().as_tuple();

        for (y, line) in map.tiles[uy .. uy + height + 1].iter().enumerate() {
            for (x, cell) in line[ux .. ux + width + 1].iter().enumerate() {
                let bg_color = match *cell {
                    Tile::Empty => Colors::BLACK,
                    Tile::Wall => Colors::DARKER_GREY,
                    Tile::Floor => Colors::DARKEST_SEPIA,
                };

                self.map.put(console, Point::new(x as i32, y as i32), ' ', Colors::WHITE, bg_color);
            }
        }
    }

    #[allow(unused)]
    fn draw_player(&mut self, game: &mut Game, console: &mut Console) {
        let pos = *game.world.player.pos();

        let adjusted_pos = pos + self.map.rect.inner_location() - self.map_view;

        if adjusted_pos.x >= self.map.rect.inner_location().x + self.map.rect.width() - 10 {
            if self.view_can_move_right(game) {
                self.map_view = self.map_view.right(1);
            }
        }

        if adjusted_pos.y >= self.map.rect.inner_location().y + self.map.rect.height() - 5 {
            if self.view_can_move_down(game) {
                self.map_view = self.map_view.down(1);
            }
        }

        if adjusted_pos.y <= self.map.rect.inner_location().y + 5 {
            if self.view_can_move_up(game) {
                self.map_view = self.map_view.up(1);
            }
        }

        if adjusted_pos.x <= self.map.rect.inner_location().x + 10 {
            if self.view_can_move_left(game) {
                self.map_view = self.map_view.left(1);
            }
        }

        if adjusted_pos.x >= self.map.rect.inner_location().x && adjusted_pos.y >= self.map.rect.inner_location().y {
            self.map.put_plain(console, pos, '@');
        }
    }

    #[allow(unused)]
    fn draw_messages(&mut self, game: &mut Game, console: &mut Console) {
        let nmessages = self.messages.rect.height() as usize;

        log::LOG.with(|w| {
            for (i, msg) in w.borrow().items().take(nmessages).enumerate() {
                let message_color = match *msg.ty() {
                    MessageType::Info => Colors::WHITE,
                    MessageType::Error => Colors::RED,
                };

                self.messages.print(console, Point::new(0, i as i32), msg.text(), message_color, Colors::BLACK);
            }
        });
    }

    #[allow(unused)]
    fn view_can_move_up(&self, game: &Game) -> bool {
        self.map_view.y  > 0
    }

    #[allow(unused)]
    fn view_can_move_down(&self, game: &Game) -> bool {
        self.map_view.y + self.map.rect.height() < game.world.map.height()
    }

    #[allow(unused)]
    fn view_can_move_left(&self, game: &Game) -> bool {
        self.map_view.x > 0
    }

    #[allow(unused)]
    fn view_can_move_right(&self, game: &Game) -> bool {
        self.map_view.x + self.map.rect.width() < game.world.map.width()
    }
}
<commit_msg>Fixed rendering of map view<commit_after>use engine::{Game, Command, MessageType, Tile};
use engine::log;
use gui::{primitives};
use gui::{Console, Colors, Key, Widget};
use gui::screens::{self, Screen, ScreenChange};
use util::units::{AsTuple, Direction, Point, Size};

#[allow(missing_copy_implementations)]
pub struct GameScreen {
    map: Widget,
    info: Widget,
    messages: Widget,
    map_view: Point,
}

impl GameScreen {
    pub fn new() -> Box<Screen> {
        let info_widget_location = Point::new(0, 0);
        let map_widget_location = Point::new(15, 0);
        let message_widget_location = Point::new(15, 40);

        Box::new(
            GameScreen {
                map: Widget::new(map_widget_location, Size::new(64, 39)),
                info: Widget::new(info_widget_location, Size::new(14, 49)),
                messages: Widget::new(message_widget_location, Size::new(64, 9)),
                map_view: Point::new(0, 0),
            }
        )
    }
}

impl Screen for GameScreen {
    #[allow(unused)]
    fn input(&mut self, game: &mut Game, console: &mut Console) -> Option<ScreenChange> {
        if let Some(key) = console.check_for_keypress() {
            match key {
                Key::Up => {
                    game.do_command(Command::Walk(Direction::Up));
                },
                Key::Down => {
                    game.do_command(Command::Walk(Direction::Down));
                },
                Key::Left => {
                    game.do_command(Command::Walk(Direction::Left));
                },
                Key::Right => {
                    game.do_command(Command::Walk(Direction::Right));
                },
                Key::Escape => {
                    return Some(ScreenChange::AddScreen(screens::PauseScreen::new()));
                },
                _ => {}
            }
        }

        None
    }

    #[allow(unused)]
    fn update(&mut self, game: &mut Game, console: &mut Console) -> Option<ScreenChange> {
        game.step();
        None
    }

    #[allow(unused)]
    fn render(&mut self, game: &mut Game, console: &mut Console) {
        self.draw_borders(game, console);
        self.draw_info(game, console);
        self.draw_map(game, console);
        self.draw_player(game, console);
        self.draw_messages(game, console);
    }
}

impl GameScreen {
    #[allow(unused)]
    fn draw_borders(&self, game: &mut Game, console: &mut Console) {
        primitives::draw_box_with_title(console, "Map", self.map.rect);
        primitives::draw_box_with_title(console, "Info", self.info.rect);
        primitives::draw_box_with_title(console, "Messages", self.messages.rect);
    }

    #[allow(unused)]
    fn draw_info(&self, game: &mut Game, console: &mut Console) {
        return;
    }

    #[allow(unused)]
    fn draw_map(&self, game: &mut Game, console: &mut Console) {
        let map = &game.world.map;

        let (ux, uy) = self.map_view.as_tuple();
        let (width, height) : (usize, usize) = self.map.rect.inner_size().as_tuple();

        for (y, line) in map.tiles[uy .. uy + height + 1].iter().enumerate() {
            for (x, cell) in line[ux .. ux + width + 1].iter().enumerate() {
                let bg_color = match *cell {
                    Tile::Empty => Colors::BLACK,
                    Tile::Wall => Colors::DARKER_GREY,
                    Tile::Floor => Colors::DARKEST_SEPIA,
                };

                self.map.put(console, Point::new(x as i32, y as i32), ' ', Colors::WHITE, bg_color);
            }
        }
    }

    #[allow(unused)]
    fn draw_player(&mut self, game: &mut Game, console: &mut Console) {
        let pos = *game.world.player.pos();

        let adjusted_pos = pos + self.map.rect.inner_location() - self.map_view;

        if adjusted_pos.x >= self.map.rect.inner_location().x + self.map.rect.width() - 10 {
            if self.view_can_move_right(game) {
                self.map_view = self.map_view.right(1);
            }
        }

        if adjusted_pos.y >= self.map.rect.inner_location().y + self.map.rect.height() - 5 {
            if self.view_can_move_down(game) {
                self.map_view = self.map_view.down(1);
            }
        }

        if adjusted_pos.y <= self.map.rect.inner_location().y + 5 {
            if self.view_can_move_up(game) {
                self.map_view = self.map_view.up(1);
            }
        }

        if adjusted_pos.x <= self.map.rect.inner_location().x + 10 {
            if self.view_can_move_left(game) {
                self.map_view = self.map_view.left(1);
            }
        }

        if adjusted_pos.x >= self.map.rect.inner_location().x && adjusted_pos.y >= self.map.rect.inner_location().y {
            self.map.put_plain(console, pos - self.map_view, '@');
        }
    }

    #[allow(unused)]
    fn draw_messages(&mut self, game: &mut Game, console: &mut Console) {
        let nmessages = self.messages.rect.height() as usize;

        log::LOG.with(|w| {
            for (i, msg) in w.borrow().items().take(nmessages).enumerate() {
                let message_color = match *msg.ty() {
                    MessageType::Info => Colors::WHITE,
                    MessageType::Error => Colors::RED,
                };

                self.messages.print(console, Point::new(0, i as i32), msg.text(), message_color, Colors::BLACK);
            }
        });
    }

    #[allow(unused)]
    fn view_can_move_up(&self, game: &Game) -> bool {
        self.map_view.y  > 0
    }

    #[allow(unused)]
    fn view_can_move_down(&self, game: &Game) -> bool {
        self.map_view.y + self.map.rect.height() < game.world.map.height()
    }

    #[allow(unused)]
    fn view_can_move_left(&self, game: &Game) -> bool {
        self.map_view.x > 0
    }

    #[allow(unused)]
    fn view_can_move_right(&self, game: &Game) -> bool {
        self.map_view.x + self.map.rect.width() < game.world.map.width()
    }
}
<|endoftext|>


<commit_before>use std::collections;
use std::fmt;
use std::error::Error as ErrorTrait;

use rustc_serialize::json;
use rustc_serialize::json::ToJson;

use hyper::header;

use url;

use iron::prelude::*;
use iron::modifiers::Header;
use iron::status;

use urlencoded;

// FIXME: oauth module should not be concerned with serialization
#[derive(RustcDecodable, RustcEncodable, Debug, Clone)]
pub struct OauthRequest {
    pub session: Session,
    pub state: Option<String>,
}

#[derive(RustcDecodable, RustcEncodable, Debug, Clone)]
pub struct Session {
    pub client_id: String,
    pub uri: url::Url,
    pub permissions: collections::HashMap<String, CategoryPermissions>
}

impl Session {
    pub fn permissions_for_category(&self, category: &str) -> Option<&CategoryPermissions> {
        match self.permissions.get(category) {
            Some(x) => Some(x),
            None => self.permissions.get("")
        }
    }

    pub fn identifier(&self) -> String {
        // FIXME: Ugly
        match self.uri.origin() {
            url::Origin::Tuple(scheme, host, port) => url::Url::parse(
                format!("{}://{}:{}", scheme, host, port)
            ).serialize(),
            _ => panic!("Invalid URL: {:?}", self.uri)
        }
    }
}

impl ToJson for Session {
    fn to_json(&self) -> json::Json {
        json::Json::Object({
            let mut rv = collections::BTreeMap::new();
            rv.insert("client_id".to_owned(), self.client_id.to_json());
            rv.insert("uri".to_owned(), self.uri.serialize().to_json());
            rv.insert("permissions".to_owned(), self.permissions.to_json());
            rv
        })
    }
}

#[derive(RustcDecodable, RustcEncodable, Debug, Clone, Copy)]
pub struct CategoryPermissions {
    pub can_read: bool,
    pub can_write: bool
}

impl ToJson for CategoryPermissions {
    // ToJson for passing to template
    fn to_json(&self) -> json::Json {
        json::Json::Object({
            let mut rv = collections::BTreeMap::new();
            rv.insert("can_read".to_owned(), self.can_read.to_json());
            rv.insert("can_write".to_owned(), self.can_write.to_json());
            rv
        })
    }
}

impl ToJson for OauthRequest {
    // ToJson for passing to template
    fn to_json(&self) -> json::Json {
        self.session.to_json()
    }
}

fn expect_param(query: &urlencoded::QueryMap, key: &str) -> Result<String, Error> {
    match query.get(key) {
        Some(x) if x.len() == 1 => Ok(x[0].clone()),
        _ => Err({
            let mut rv = Error::new(ErrorKind::InvalidRequest);
            rv.msg = Some(format!("Missing query parameter: {:?}", key));
            rv
        })
    }
}

impl OauthRequest {
    pub fn from_http(request: &mut Request) -> Result<Self, Error> {
        let query = match request.get_ref::<urlencoded::UrlEncodedQuery>().ok() {
            Some(x) => x,
            None => return Err({
                let mut e = Error::new(ErrorKind::InvalidRequest);
                e.msg = Some("No query parameters.".to_owned());
                e
            })
        };

        let mut rv = OauthRequest {
            session: Session {
                client_id: "".to_owned(),
                uri: match url::Url::parse(&try!(expect_param(query, "redirect_uri"))[..]) {
                    Ok(x) => x,
                    Err(e) => return Err({
                        let mut ne = Error::new(ErrorKind::InvalidRequest);
                        ne.msg = Some(format!("{}", e));
                        ne
                    })
                },
                permissions: collections::HashMap::new()
            },
            state: expect_param(query, "state").ok()
        };

        rv.session.client_id = match expect_param(query, "client_id") {
            Ok(x) => x,
            Err(mut e) => {
                e.request = Some(rv);
                return Err(e);
            }
        };

        let scope = match expect_param(query, "scope") {
            Ok(x) => x,
            Err(mut e) => {
                e.request = Some(rv);
                return Err(e);
            }
        };

        let scope_err = |x| { Err({
            let mut e = Error::new(ErrorKind::InvalidScope);
            e.msg = Some("Invalid scope.".to_owned());
            e.request = Some(x);
            e
        }) };

        for category_permission in scope.split(' ') {
            let parts = category_permission.split(':').collect::<Vec<_>>();
            if parts.len() != 2 { return scope_err(rv); }

            let (category, permission) = (parts[0], parts[1]);
            if category.len() == 0 || permission.len() == 0 { return scope_err(rv); }

            let key = (if category == "*" { "" } else { category }).to_owned();
            if rv.session.permissions.get(&key).is_some() { return scope_err(rv); }

            rv.session.permissions.insert(key, CategoryPermissions {
                can_read: permission.contains("r"),
                can_write: permission.contains("w")
            });
        }

        Ok(rv)
    }

    pub fn grant(self, token: String) -> Grant {
        Grant { request: self, token: token }
    }

    pub fn reject(self) -> Error {
        let mut e = Error::new(ErrorKind::AccessDenied);
        e.request = Some(self);
        e
    }
}

pub struct Grant {
    pub request: OauthRequest,
    pub token: String
}

impl HttpResponder for Grant {
    fn get_redirect_uri(&self) -> Option<url::Url> {
        Some(self.request.session.uri.clone())
    }

    fn get_redirect_uri_params(&self) -> collections::BTreeMap<String, String> {
        let mut rv = collections::BTreeMap::new();
        rv.insert("access_token".to_owned(), self.token.clone());
        self.request.state.as_ref().map(|x| rv.insert("state".to_owned(), x.clone()));
        rv
    }
}

#[derive(Debug)]
pub struct Error {
    pub kind: ErrorKind,
    pub request: Option<OauthRequest>,
    pub error_uri: Option<url::Url>,
    pub msg: Option<String>
}

impl Error {
    pub fn new(kind: ErrorKind) -> Self {
        Error {
            kind: kind,
            request: None,
            error_uri: None,
            msg: None
        }
    }
}

#[derive(Debug)]
#[allow(dead_code)]
pub enum ErrorKind {
    InvalidRequest,
    UnauthorizedClient,
    AccessDenied,
    UnsupportedResponseType,
    InvalidScope,
    ServerError,
    TemporarilyUnavailable
}

impl ErrorKind {
    fn as_snake_case(&self) -> &str {
        match *self {
            ErrorKind::InvalidRequest => "invalid_request",
            ErrorKind::UnauthorizedClient => "unauthorized_client",
            ErrorKind::AccessDenied => "access_denied",
            ErrorKind::UnsupportedResponseType => "unsupported_response_type",
            ErrorKind::InvalidScope => "invalid_scope",
            ErrorKind::ServerError => "server_error",
            ErrorKind::TemporarilyUnavailable => "temporarily_unavailable"
        }
    }
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { self.description().fmt(f) }
}

impl ErrorTrait for Error {
    fn description(&self) -> &str {
        match self.msg {
            Some(ref x) => x,
            None => self.kind.as_snake_case()
        }
    }
    fn cause(&self) -> Option<&ErrorTrait> { None }
}

pub trait HttpResponder {
    fn get_redirect_uri(&self) -> Option<url::Url>;
    fn get_redirect_uri_params(&self) -> collections::BTreeMap<String, String>;

    fn get_response(&self) -> Option<Response> {
        self.get_redirect_uri()
            .map(|mut uri| {
                uri.fragment = Some(url::form_urlencoded::serialize(self.get_redirect_uri_params()));
                Response::with(status::Found)
                 // Do not use Redirect modifier here, we need to handle custom URI schemes as well
                 .set(Header(header::Location(uri.serialize())))
            })
    }
}

impl HttpResponder for Error {
    fn get_redirect_uri(&self) -> Option<url::Url> {
        self.request.as_ref().map(|req| req.session.uri.clone())
    }

    fn get_redirect_uri_params(&self) -> collections::BTreeMap<String, String> {
        let mut rv = collections::BTreeMap::new();
        rv.insert("error".to_owned(), self.kind.as_snake_case().to_owned());
        self.msg.as_ref().map(|x| rv.insert("error_description".to_owned(), x.clone()));
        self.request.as_ref().map(|req| req.state.as_ref().map(|state| rv.insert("state".to_owned(), state.clone())));
        rv
    }
}
<commit_msg>fixup<commit_after>use std::collections;
use std::fmt;
use std::error::Error as ErrorTrait;

use rustc_serialize::json;
use rustc_serialize::json::ToJson;

use hyper::header;

use url;

use iron::prelude::*;
use iron::modifiers::Header;
use iron::status;

use urlencoded;

// FIXME: oauth module should not be concerned with serialization
#[derive(RustcDecodable, RustcEncodable, Debug, Clone)]
pub struct OauthRequest {
    pub session: Session,
    pub state: Option<String>,
}

#[derive(RustcDecodable, RustcEncodable, Debug, Clone)]
pub struct Session {
    pub client_id: String,
    pub uri: url::Url,
    pub permissions: collections::HashMap<String, CategoryPermissions>
}

impl Session {
    pub fn permissions_for_category(&self, category: &str) -> Option<&CategoryPermissions> {
        match self.permissions.get(category) {
            Some(x) => Some(x),
            None => self.permissions.get("")
        }
    }

    pub fn identifier(&self) -> String {
        // FIXME: Ugly
        match self.uri.origin() {
            url::Origin::Tuple(scheme, host, port) => url::Url::parse(
                format!("{}://{}:{}", scheme, host, port)
            ).unwrap().serialize(),
            _ => panic!("Invalid URL: {:?}", self.uri)
        }
    }
}

impl ToJson for Session {
    fn to_json(&self) -> json::Json {
        json::Json::Object({
            let mut rv = collections::BTreeMap::new();
            rv.insert("client_id".to_owned(), self.client_id.to_json());
            rv.insert("uri".to_owned(), self.uri.serialize().to_json());
            rv.insert("permissions".to_owned(), self.permissions.to_json());
            rv
        })
    }
}

#[derive(RustcDecodable, RustcEncodable, Debug, Clone, Copy)]
pub struct CategoryPermissions {
    pub can_read: bool,
    pub can_write: bool
}

impl ToJson for CategoryPermissions {
    // ToJson for passing to template
    fn to_json(&self) -> json::Json {
        json::Json::Object({
            let mut rv = collections::BTreeMap::new();
            rv.insert("can_read".to_owned(), self.can_read.to_json());
            rv.insert("can_write".to_owned(), self.can_write.to_json());
            rv
        })
    }
}

impl ToJson for OauthRequest {
    // ToJson for passing to template
    fn to_json(&self) -> json::Json {
        self.session.to_json()
    }
}

fn expect_param(query: &urlencoded::QueryMap, key: &str) -> Result<String, Error> {
    match query.get(key) {
        Some(x) if x.len() == 1 => Ok(x[0].clone()),
        _ => Err({
            let mut rv = Error::new(ErrorKind::InvalidRequest);
            rv.msg = Some(format!("Missing query parameter: {:?}", key));
            rv
        })
    }
}

impl OauthRequest {
    pub fn from_http(request: &mut Request) -> Result<Self, Error> {
        let query = match request.get_ref::<urlencoded::UrlEncodedQuery>().ok() {
            Some(x) => x,
            None => return Err({
                let mut e = Error::new(ErrorKind::InvalidRequest);
                e.msg = Some("No query parameters.".to_owned());
                e
            })
        };

        let mut rv = OauthRequest {
            session: Session {
                client_id: "".to_owned(),
                uri: match url::Url::parse(&try!(expect_param(query, "redirect_uri"))[..]) {
                    Ok(x) => x,
                    Err(e) => return Err({
                        let mut ne = Error::new(ErrorKind::InvalidRequest);
                        ne.msg = Some(format!("{}", e));
                        ne
                    })
                },
                permissions: collections::HashMap::new()
            },
            state: expect_param(query, "state").ok()
        };

        rv.session.client_id = match expect_param(query, "client_id") {
            Ok(x) => x,
            Err(mut e) => {
                e.request = Some(rv);
                return Err(e);
            }
        };

        let scope = match expect_param(query, "scope") {
            Ok(x) => x,
            Err(mut e) => {
                e.request = Some(rv);
                return Err(e);
            }
        };

        let scope_err = |x| { Err({
            let mut e = Error::new(ErrorKind::InvalidScope);
            e.msg = Some("Invalid scope.".to_owned());
            e.request = Some(x);
            e
        }) };

        for category_permission in scope.split(' ') {
            let parts = category_permission.split(':').collect::<Vec<_>>();
            if parts.len() != 2 { return scope_err(rv); }

            let (category, permission) = (parts[0], parts[1]);
            if category.len() == 0 || permission.len() == 0 { return scope_err(rv); }

            let key = (if category == "*" { "" } else { category }).to_owned();
            if rv.session.permissions.get(&key).is_some() { return scope_err(rv); }

            rv.session.permissions.insert(key, CategoryPermissions {
                can_read: permission.contains("r"),
                can_write: permission.contains("w")
            });
        }

        Ok(rv)
    }

    pub fn grant(self, token: String) -> Grant {
        Grant { request: self, token: token }
    }

    pub fn reject(self) -> Error {
        let mut e = Error::new(ErrorKind::AccessDenied);
        e.request = Some(self);
        e
    }
}

pub struct Grant {
    pub request: OauthRequest,
    pub token: String
}

impl HttpResponder for Grant {
    fn get_redirect_uri(&self) -> Option<url::Url> {
        Some(self.request.session.uri.clone())
    }

    fn get_redirect_uri_params(&self) -> collections::BTreeMap<String, String> {
        let mut rv = collections::BTreeMap::new();
        rv.insert("access_token".to_owned(), self.token.clone());
        self.request.state.as_ref().map(|x| rv.insert("state".to_owned(), x.clone()));
        rv
    }
}

#[derive(Debug)]
pub struct Error {
    pub kind: ErrorKind,
    pub request: Option<OauthRequest>,
    pub error_uri: Option<url::Url>,
    pub msg: Option<String>
}

impl Error {
    pub fn new(kind: ErrorKind) -> Self {
        Error {
            kind: kind,
            request: None,
            error_uri: None,
            msg: None
        }
    }
}

#[derive(Debug)]
#[allow(dead_code)]
pub enum ErrorKind {
    InvalidRequest,
    UnauthorizedClient,
    AccessDenied,
    UnsupportedResponseType,
    InvalidScope,
    ServerError,
    TemporarilyUnavailable
}

impl ErrorKind {
    fn as_snake_case(&self) -> &str {
        match *self {
            ErrorKind::InvalidRequest => "invalid_request",
            ErrorKind::UnauthorizedClient => "unauthorized_client",
            ErrorKind::AccessDenied => "access_denied",
            ErrorKind::UnsupportedResponseType => "unsupported_response_type",
            ErrorKind::InvalidScope => "invalid_scope",
            ErrorKind::ServerError => "server_error",
            ErrorKind::TemporarilyUnavailable => "temporarily_unavailable"
        }
    }
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { self.description().fmt(f) }
}

impl ErrorTrait for Error {
    fn description(&self) -> &str {
        match self.msg {
            Some(ref x) => x,
            None => self.kind.as_snake_case()
        }
    }
    fn cause(&self) -> Option<&ErrorTrait> { None }
}

pub trait HttpResponder {
    fn get_redirect_uri(&self) -> Option<url::Url>;
    fn get_redirect_uri_params(&self) -> collections::BTreeMap<String, String>;

    fn get_response(&self) -> Option<Response> {
        self.get_redirect_uri()
            .map(|mut uri| {
                uri.fragment = Some(url::form_urlencoded::serialize(self.get_redirect_uri_params()));
                Response::with(status::Found)
                 // Do not use Redirect modifier here, we need to handle custom URI schemes as well
                 .set(Header(header::Location(uri.serialize())))
            })
    }
}

impl HttpResponder for Error {
    fn get_redirect_uri(&self) -> Option<url::Url> {
        self.request.as_ref().map(|req| req.session.uri.clone())
    }

    fn get_redirect_uri_params(&self) -> collections::BTreeMap<String, String> {
        let mut rv = collections::BTreeMap::new();
        rv.insert("error".to_owned(), self.kind.as_snake_case().to_owned());
        self.msg.as_ref().map(|x| rv.insert("error_description".to_owned(), x.clone()));
        self.request.as_ref().map(|req| req.state.as_ref().map(|state| rv.insert("state".to_owned(), state.clone())));
        rv
    }
}
<|endoftext|>


<commit_before>use util::flat_tree::FlatTree;
use util::flat_tree::TreeNode;
use std::ops::Deref;
use super::LayoutBox;
use markup::Node;
use state::StateBuffer;

mod repeat_node;
mod simple_node;

pub struct LayoutBuffer(FlatTree<LayoutBox>);
pub type LayoutNode = TreeNode<LayoutBox>;

impl Deref for LayoutBuffer {
    type Target = [LayoutNode];

    fn deref<'a>(&'a self) -> &'a [LayoutNode] {
        self.0.deref()
    }
}

impl LayoutBuffer {

    pub fn new(style_tree: &Node) -> LayoutBuffer {

        let size = style_tree.tree_size();

        LayoutBuffer(FlatTree::new(style_tree, size, converter))
    }

    pub fn update_from_state(&mut self, state_buffer: &StateBuffer) {

        for (lb, state) in self.0.iter_mut().zip(state_buffer.iter()) {
            lb.update_from_state(state);
        }
    }

    pub fn compute_layout(&mut self, max_width: f32, max_height: f32) {

        // First pass: compute default width
        for root in self.0.tree_iter_mut() {
            compute_layout_defaut_width(root, max_width);
        }

        // Second pass: compute auto margins and width auto
        for root in self.0.tree_iter_mut() {
            compute_layout_auto_width(root, max_width);
        }

        // Third pass: layout children and compute their height
        for root in self.0.tree_iter_mut() {
            compute_layout_height_and_position(root, max_height);
        }
    }
}

fn converter(_: &Node) -> Option<LayoutBox> {
    Some(LayoutBox::default())
}

/// This function compute the width for this node
/// and return the space it would have eaten if it had more space
/// than the one given.
///
/// This can appear when this node has a child with a fixed width.
fn compute_layout_defaut_width(this: &mut LayoutNode, space_available_for_self: f32) -> f32
{
    // Compute the extra part to remove
    let o = this.dim.padding.left
        + this.dim.padding.right
        + this.dim.margin.left
        + this.dim.margin.right
        + this.dim.border.left
        + this.dim.border.right;

    // Compute the space available for each line
    let space_available = if this.flags.has_width_fixed() {
        this.dim.content.width
    } else {
        space_available_for_self - o
    };

    // Iterating variables
    let mut max = 0f32;
    let mut sum = 0f32;
    let mut line_space_available = space_available;

    // Scope to reduce iter lifetime.
    {
        let mut iter = this.children_mut();
        let mut option_next = iter.next();
        let mut next_child = false;

        loop {

            // This line is confusing...
            // child has the type &mut &mut LayoutBox (one additional indirection)
            // but in release both child, option_next and iter are optimized out.
            // So I guess I shouldn't worry about that, or not ?
            if let Some(ref mut child) = option_next {

                // Recursive call: eat the space given
                let space_eaten = compute_layout_defaut_width(child, line_space_available);

                // If the child has not eaten more than given
                // then we just reduce the space available for the next child
                if line_space_available >= space_eaten {

                    line_space_available -= space_eaten;
                    sum += space_eaten;

                    // Should we increase the max line size ?
                    if sum > max {
                        max = sum;
                    }

                    // If the child is auto then we simply restart with a new line
                    if child.flags.is_new_line_forced() {
                        sum = 0f32;
                        line_space_available = space_available;
                    }

                    // We'll go see for the next child now.
                    next_child = true;

                // Otherwise, we have to put the child on a new line
                // except if the child was alone on its line
                } else {

                    // Am I alone ?
                    if line_space_available == space_available {

                        // This might be surprising, but here we want to
                        // transmit back to our parent the child constraint.
                        if sum > max {
                            max = sum;
                        }

                        next_child = true;

                    // If I wasn't alone, as I will be on a new line,
                    // the recursion will be done again. This do have an overhead.
                    }

                    // Then start a new line:
                    sum = 0f32;
                    line_space_available = space_available;
                }

            } else {
                break;
            }

            if next_child {

                // Go take care of the next child:
                option_next = iter.next();

                next_child = false;
            }
        }
    }

    // Assign width for this.
    if !this.flags.has_width_fixed() {
        this.dim.content.width = if this.flags.has_width_expand() {
            space_available
        } else {
            max.min(space_available)
        }
    };

    // Compute the free space for margin in expand mode:
    let s = space_available - this.dim.content.width;

    // We can also compute the margins (left/right) if they're auto:
    match (this.flags.has_margin_right_expand(), this.flags.has_margin_left_expand()) {
        (true, true) => {
            this.dim.margin.left  = s / 2f32;
            this.dim.margin.right = s / 2f32;
        }
        (true, false) => {
            this.dim.margin.left = s;
        }
        (false, true) => {
            this.dim.margin.right = s;
        }
        _ => ()
    }

    if this.flags.has_width_fixed() {
        this.dim.content.width + o
    } else {
        max + o
    }
}

/// This function performs a tree traversal to compute the auto values
/// on nodes in the tree.
/// It should be called after compute_layout_default_width
fn compute_layout_auto_width(this: &mut LayoutNode, space_available: f32)
{
    for child in this.children_mut() {

        compute_layout_auto_width(child, this.dim.content.width);
    }

    // Resolve auto width for this.
    if this.flags.has_width_auto() {
        let o = this.dim.padding.left
            + this.dim.padding.right
            + this.dim.margin.left
            + this.dim.margin.right
            + this.dim.border.left
            + this.dim.border.right;

        this.dim.content.width = space_available - o;
    }

    // Compute the free space for margin in auto mode:
    let s = space_available - this.dim.content.width;

    // We can also compute the margins (left/right) if they're auto:
    match (this.flags.has_margin_right_auto(), this.flags.has_margin_left_auto()) {
        (true, true) => {
            this.dim.margin.left  = s / 2f32;
            this.dim.margin.right = s / 2f32;
        }
        (true, false) => {
            this.dim.margin.left = s;
        }
        (false, true) => {
            this.dim.margin.right = s;
        }
        _ => ()
    }
}

//
// TODO: FIXME Text nodes must have their size precomputed somehow
//
// PRECONDITONS: compute_width has been called
//
fn compute_layout_height_and_position(this: &mut LayoutNode, max_height: f32)
{

    // At this point we don't know this.dim.height / this.dim.width
    // positions
    let mut x = this.dim.content.x
        + this.dim.padding.left
        + this.dim.margin.left
        + this.dim.border.left;
    let mut y = this.dim.content.y
        + this.dim.padding.top
        + this.dim.margin.top
        + this.dim.border.top;

    // Equivalent rule for child max height:
    let child_max_height = if this.flags.has_height_fixed() {

        this.dim.content.height
    } else {

        max_height
        - this.dim.padding.bottom - this.dim.padding.top
        - this.dim.border.bottom  - this.dim.border.top
        - this.dim.margin.bottom  - this.dim.margin.top
    };

    // Current line width allow to track the layout progress
    // in the x direction while height allow to track the y direction
    let mut current_line_width  = 0f32;
    let mut current_line_height = 0f32;
    let mut current_height_left = child_max_height;
    let mut accumulated_line_height = 0f32;

    // Reduced scope for stack (borrowck problem otherwise)
    {
        // Used for margin (top/bottom)
        let mut stack: Vec<&mut LayoutNode> = Vec::with_capacity(4);

        macro_rules! line_return {

            ($stack:ident,
             $current_line_height:ident,
             $current_line_width:ident,
             $current_height_left:ident,
             $accumulated_line_height:ident,
             $d:ident) => ({

                while let Some(ref mut c) = $stack.pop() {

                    let s = $current_line_height - c.dim.content.height
                        - c.dim.padding.top - c.dim.padding.bottom
                        - c.dim.border.top  - c.dim.border.bottom
                        - c.dim.margin.top  - c.dim.margin.bottom;

                    // We compute the margin top / bottom
                    match (c.flags.has_margin_top_auto(), c.flags.has_margin_bottom_auto()) {
                        (true, true) => {
                            c.dim.margin.top    = s / 2f32;
                            c.dim.margin.bottom = s / 2f32;
                        }
                        (true, false) => {
                            c.dim.margin.top   = s;
                        }
                        (false, true) => {
                            c.dim.margin.bottom  = s;
                        }
                        _ => ()
                    }
                }

                x = $d.content.x + $d.padding.left + $d.border.left + $d.margin.left;
                y += $current_line_height;
                $accumulated_line_height += $current_line_height;
                $current_height_left     -= $current_line_height;
                $current_line_width   = 0f32;
                $current_line_height  = 0f32;
            });
        }

        for child in this.children_mut() {

            let need_new_line = child.flags.is_new_line_forced();

            // Line return ?
            if child.dim.content.width + current_line_width > this.dim.content.width {
                let ref d = this.dim;
                line_return!(
                    stack,
                    current_line_height,
                    current_line_width,
                    current_height_left,
                    accumulated_line_height,
                    d);
            }

            child.dim.content.x = x;
            child.dim.content.y = y;

            // Update the x position:
            let child_total_width = child.dim.content.width
                + child.dim.margin.left
                + child.dim.margin.right
                + child.dim.border.left
                + child.dim.border.right;

            x += child_total_width;
            current_line_width += child_total_width;

            compute_layout_height_and_position(child, current_height_left);

            // Note: at this point child.margin (top, right) are either fixed
            // or zero (if they were auto). They will be computed in a later pass.
            current_line_height = current_line_height.max(child.dim.content.height
                + child.dim.margin.top
                + child.dim.margin.bottom
                + child.dim.border.top
                + child.dim.border.bottom
            );

            if child.flags.has_margin_top_or_bot_auto() {
                stack.push(child);
            }

            if need_new_line {
                let ref d = this.dim;
                line_return!(
                    stack,
                    current_line_height,
                    current_line_width,
                    current_height_left,
                    accumulated_line_height,
                    d);
            }
        }
    }

    // Finally: the height !
    this.dim.content.height =
        this.dim.content.height.max(child_max_height.min(accumulated_line_height));
}
<commit_msg>End of line in layout was incorrectly handled.<commit_after>use util::flat_tree::FlatTree;
use util::flat_tree::TreeNode;
use std::ops::Deref;
use super::LayoutBox;
use markup::Node;
use state::StateBuffer;

mod repeat_node;
mod simple_node;

pub struct LayoutBuffer(FlatTree<LayoutBox>);
pub type LayoutNode = TreeNode<LayoutBox>;

impl Deref for LayoutBuffer {
    type Target = [LayoutNode];

    fn deref<'a>(&'a self) -> &'a [LayoutNode] {
        self.0.deref()
    }
}

impl LayoutBuffer {

    pub fn new(style_tree: &Node) -> LayoutBuffer {

        let size = style_tree.tree_size();

        LayoutBuffer(FlatTree::new(style_tree, size, converter))
    }

    pub fn update_from_state(&mut self, state_buffer: &StateBuffer) {

        for (lb, state) in self.0.iter_mut().zip(state_buffer.iter()) {
            lb.update_from_state(state);
        }
    }

    pub fn compute_layout(&mut self, max_width: f32, max_height: f32) {

        // First pass: compute default width
        for root in self.0.tree_iter_mut() {
            compute_layout_defaut_width(root, max_width);
        }

        // Second pass: compute auto margins and width auto
        for root in self.0.tree_iter_mut() {
            compute_layout_auto_width(root, max_width);
        }

        // Third pass: layout children and compute their height
        for root in self.0.tree_iter_mut() {
            compute_layout_height_and_position(root, max_height);
        }
    }
}

fn converter(_: &Node) -> Option<LayoutBox> {
    Some(LayoutBox::default())
}

/// This function compute the width for this node
/// and return the space it would have eaten if it had more space
/// than the one given.
///
/// This can appear when this node has a child with a fixed width.
fn compute_layout_defaut_width(this: &mut LayoutNode, space_available_for_self: f32) -> f32
{
    // Compute the extra part to remove
    let o = this.dim.padding.left
        + this.dim.padding.right
        + this.dim.margin.left
        + this.dim.margin.right
        + this.dim.border.left
        + this.dim.border.right;

    // Compute the space available for each line
    let space_available = if this.flags.has_width_fixed() {
        this.dim.content.width
    } else {
        space_available_for_self - o
    };

    // Iterating variables
    let mut max = 0f32;
    let mut sum = 0f32;
    let mut line_space_available = space_available;

    // Scope to reduce iter lifetime.
    {
        let mut iter = this.children_mut();
        let mut option_next = iter.next();
        let mut next_child = false;

        loop {

            // This line is confusing...
            // child has the type &mut &mut LayoutBox (one additional indirection)
            // but in release both child, option_next and iter are optimized out.
            // So I guess I shouldn't worry about that, or not ?
            if let Some(ref mut child) = option_next {

                // Recursive call: eat the space given
                let space_eaten = compute_layout_defaut_width(child, line_space_available);

                // If the child has not eaten more than given
                // then we just reduce the space available for the next child
                if line_space_available >= space_eaten {

                    line_space_available -= space_eaten;
                    sum += space_eaten;

                    // Should we increase the max line size ?
                    if sum > max {
                        max = sum;
                    }

                    // If the child is auto then we simply restart with a new line
                    if child.flags.is_new_line_forced() {
                        sum = 0f32;
                        line_space_available = space_available;
                    }

                    // We'll go see for the next child now.
                    next_child = true;

                // Otherwise, we have to put the child on a new line
                // except if the child was alone on its line
                } else {

                    // Am I alone ?
                    if line_space_available == space_available {

                        // This might be surprising, but here we want to
                        // transmit back to our parent the child constraint.
                        if sum > max {
                            max = sum;
                        }

                        next_child = true;

                    // If I wasn't alone, as I will be on a new line,
                    // the recursion will be done again. This do have an overhead.
                    }

                    // Then start a new line:
                    sum = 0f32;
                    line_space_available = space_available;
                }

            } else {
                break;
            }

            if next_child {

                // Go take care of the next child:
                option_next = iter.next();

                next_child = false;
            }
        }
    }

    // Assign width for this.
    if !this.flags.has_width_fixed() {
        this.dim.content.width = if this.flags.has_width_expand() {
            space_available
        } else {
            max.min(space_available)
        }
    };

    // Compute the free space for margin in expand mode:
    let s = space_available - this.dim.content.width;

    // We can also compute the margins (left/right) if they're auto:
    match (this.flags.has_margin_right_expand(), this.flags.has_margin_left_expand()) {
        (true, true) => {
            this.dim.margin.left  = s / 2f32;
            this.dim.margin.right = s / 2f32;
        }
        (true, false) => {
            this.dim.margin.left = s;
        }
        (false, true) => {
            this.dim.margin.right = s;
        }
        _ => ()
    }

    if this.flags.has_width_fixed() {
        this.dim.content.width + o
    } else {
        max + o
    }
}

/// This function performs a tree traversal to compute the auto values
/// on nodes in the tree.
/// It should be called after compute_layout_default_width
fn compute_layout_auto_width(this: &mut LayoutNode, space_available: f32)
{
    for child in this.children_mut() {

        compute_layout_auto_width(child, this.dim.content.width);
    }

    // Resolve auto width for this.
    if this.flags.has_width_auto() {
        let o = this.dim.padding.left
            + this.dim.padding.right
            + this.dim.margin.left
            + this.dim.margin.right
            + this.dim.border.left
            + this.dim.border.right;

        this.dim.content.width = space_available - o;
    }

    // Compute the free space for margin in auto mode:
    let s = space_available - this.dim.content.width;

    // We can also compute the margins (left/right) if they're auto:
    match (this.flags.has_margin_right_auto(), this.flags.has_margin_left_auto()) {
        (true, true) => {
            this.dim.margin.left  = s / 2f32;
            this.dim.margin.right = s / 2f32;
        }
        (true, false) => {
            this.dim.margin.left = s;
        }
        (false, true) => {
            this.dim.margin.right = s;
        }
        _ => ()
    }
}

//
// TODO: FIXME Text nodes must have their size precomputed somehow
//
// PRECONDITONS: compute_width has been called
//
fn compute_layout_height_and_position(this: &mut LayoutNode, max_height: f32)
{

    // At this point we don't know this.dim.height / this.dim.width
    // positions
    let mut x = this.dim.content.x
        + this.dim.padding.left
        + this.dim.margin.left
        + this.dim.border.left;
    let mut y = this.dim.content.y
        + this.dim.padding.top
        + this.dim.margin.top
        + this.dim.border.top;

    // Equivalent rule for child max height:
    let child_max_height = if this.flags.has_height_fixed() {

        this.dim.content.height
    } else {

        max_height
        - this.dim.padding.bottom - this.dim.padding.top
        - this.dim.border.bottom  - this.dim.border.top
        - this.dim.margin.bottom  - this.dim.margin.top
    };

    // Current line width allow to track the layout progress
    // in the x direction while height allow to track the y direction
    let mut current_line_width  = 0f32;
    let mut current_line_height = 0f32;
    let mut current_height_left = child_max_height;
    let mut accumulated_line_height = 0f32;

    // Reduced scope for stack (borrowck problem otherwise)
    {
        // Used for margin (top/bottom)
        let mut stack: Vec<&mut LayoutNode> = Vec::with_capacity(4);

        macro_rules! resolve_top_bot_auto_margins {
            ($stack:ident,
             $current_line_height:ident) => ({

                 while let Some(ref mut c) = $stack.pop() {

                     let s = $current_line_height - c.dim.content.height
                         - c.dim.padding.top - c.dim.padding.bottom
                         - c.dim.border.top  - c.dim.border.bottom
                         - c.dim.margin.top  - c.dim.margin.bottom;

                     // We compute the margin top / bottom
                     match (c.flags.has_margin_top_auto(), c.flags.has_margin_bottom_auto()) {
                         (true, true) => {
                             c.dim.margin.top    = s / 2f32;
                             c.dim.margin.bottom = s / 2f32;
                         }
                         (true, false) => {
                             c.dim.margin.top   = s;
                         }
                         (false, true) => {
                             c.dim.margin.bottom  = s;
                         }
                         _ => ()
                     }
                 }
            })
        }

        macro_rules! line_return {

            ($stack:ident,
             $current_line_height:ident,
             $current_line_width:ident,
             $current_height_left:ident,
             $accumulated_line_height:ident,
             $d:ident) => ({

                resolve_top_bot_auto_margins!($stack, $current_line_height);

                x = $d.content.x + $d.padding.left + $d.border.left + $d.margin.left;
                y += $current_line_height;
                $accumulated_line_height += $current_line_height;
                $current_height_left     -= $current_line_height;
                $current_line_width   = 0f32;
                $current_line_height  = 0f32;
            });
        }

        for child in this.children_mut() {

            let need_new_line = child.flags.is_new_line_forced();

            // Line return ?
            if child.dim.content.width + current_line_width > this.dim.content.width {
                let ref d = this.dim;
                line_return!(
                    stack,
                    current_line_height,
                    current_line_width,
                    current_height_left,
                    accumulated_line_height,
                    d);
            }

            child.dim.content.x = x;
            child.dim.content.y = y;

            // Update the x position:
            let child_total_width = child.dim.content.width
                + child.dim.margin.left
                + child.dim.margin.right
                + child.dim.border.left
                + child.dim.border.right;

            x += child_total_width;
            current_line_width += child_total_width;

            compute_layout_height_and_position(child, current_height_left);

            // Note: at this point child.margin (top, right) are either fixed
            // or zero (if they were auto). They will be computed in a later pass.
            current_line_height = current_line_height.max(child.dim.content.height
                + child.dim.margin.top
                + child.dim.margin.bottom
                + child.dim.border.top
                + child.dim.border.bottom
            );

            if child.flags.has_margin_top_or_bot_auto() {
                stack.push(child);
            }

            if need_new_line {
                let ref d = this.dim;
                line_return!(
                    stack,
                    current_line_height,
                    current_line_width,
                    current_height_left,
                    accumulated_line_height,
                    d);
            }
        }

        // Last line: we end the line and
        // update margin top/bot auto if needed.
        resolve_top_bot_auto_margins!(stack, current_line_height);
        accumulated_line_height += current_line_height;
    }

    // Finally: the height !
    this.dim.content.height =
        this.dim.content.height.max(child_max_height.min(accumulated_line_height));
}
<|endoftext|>