<commit_before>//
//   Copyright 2016 Andrew Hunter
//
//   Licensed under the Apache License, Version 2.0 (the "License");
//   you may not use this file except in compliance with the License.
//   You may obtain a copy of the License at
//
//       http://www.apache.org/licenses/LICENSE-2.0
//
//   Unless required by applicable law or agreed to in writing, software
//   distributed under the License is distributed on an "AS IS" BASIS,
//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//   See the License for the specific language governing permissions and
//   limitations under the License.
//

use rustc_serialize::*;

use super::encoder::*;
use super::treenode::*;
use super::values::*;

///
/// Used to help decode tree nodes into other types
///
struct TreeNodeDecoder {
    current_node: TreeRef
}

#[derive(Debug)]
pub enum TreeNodeDecodingError {
    UnsupportedType,
    NodeHasInvalidType,
    ValueOutOfRange,
    MissingField,
    GenericError(String)
}

impl TreeNodeDecoder {
    fn read_current(&self) -> &TreeValue {
        self.current_node.get_value()
    }
}

#[allow(unused_variables)]          // Unused function parameters are quite common due to the way this trait is designed
impl Decoder for TreeNodeDecoder {
    type Error = TreeNodeDecodingError;

    fn read_nil(&mut self) -> Result<(), Self::Error> {
        match *self.read_current() {
            TreeValue::Nothing  => Ok(()),
            _                   => Err(TreeNodeDecodingError::NodeHasInvalidType)
        }
    }

    fn read_i32(&mut self) -> Result<i32, Self::Error> {
        match *self.read_current() {
            TreeValue::Int(ref x)   => Ok(*x),
            _                       => Err(TreeNodeDecodingError::NodeHasInvalidType)
        }
    }

    fn read_i16(&mut self) -> Result<i16, Self::Error> {
        match *self.read_current() {
            TreeValue::Int(ref x)   => if (*x >= i16::min_value() as i32) && (*x <= i16::max_value() as i32) { Ok(*x as i16) } else { Err(TreeNodeDecodingError::ValueOutOfRange) },
            _                       => Err(TreeNodeDecodingError::NodeHasInvalidType)
        }
    }

    fn read_i8(&mut self) -> Result<i8, Self::Error> {
        match *self.read_current() {
            TreeValue::Int(ref x)   => if (*x >= i8::min_value() as i32) && (*x <= i8::max_value() as i32) { Ok(*x as i8) } else { Err(TreeNodeDecodingError::ValueOutOfRange) },
            _                       => Err(TreeNodeDecodingError::NodeHasInvalidType)
        }
    }

    fn read_str(&mut self) -> Result<String, Self::Error> {
        match *self.read_current() {
            TreeValue::String(ref x)    => Ok(x.to_owned()),
            _                           => Err(TreeNodeDecodingError::NodeHasInvalidType)
        }
    }

    fn read_bool(&mut self) -> Result<bool, Self::Error> {
        match *self.read_current() {
            TreeValue::Bool(ref x)  => Ok(*x),
            _                       => Err(TreeNodeDecodingError::NodeHasInvalidType)
        }
    }

    fn read_f64(&mut self) -> Result<f64, Self::Error> {
        match *self.read_current() {
            TreeValue::Real(ref x)  => Ok(*x),
            _                       => Err(TreeNodeDecodingError::NodeHasInvalidType)
        }
    }

    fn read_f32(&mut self) -> Result<f32, Self::Error> {
        match *self.read_current() {
            TreeValue::Real(ref x)  => Ok(*x as f32),
            _                       => Err(TreeNodeDecodingError::NodeHasInvalidType)
        }
    }

    fn read_struct<T, F>(&mut self, s_name: &str, len: usize, f: F) -> Result<T, Self::Error> where F: FnOnce(&mut Self) -> Result<T, Self::Error> {
        f(self)
    }

    fn read_struct_field<T, F>(&mut self, f_name: &str, f_idx: usize, f: F) -> Result<T, Self::Error> where F: FnOnce(&mut Self) -> Result<T, Self::Error> {
        // Look up the field
        // TODO: could hash the field names to avoid doing a linear search every time (not clear if there are substantial benefits for this given the small number of fields in most structures)
        let field = self.current_node.get_child_ref_at(f_name);

        match field {
            None        => Err(TreeNodeDecodingError::MissingField),
            Some(ref x) => {
                // Move into the field node
                let previous_node = self.current_node.to_owned();
                self.current_node = x.to_owned();

                // Decode it
                let result = f(self);

                // Move back out
                self.current_node = previous_node.to_owned();

                result
            }
        }
    }

    fn read_usize(&mut self) -> Result<usize, Self::Error> {
        Err(TreeNodeDecodingError::UnsupportedType)
    }

    fn read_u64(&mut self) -> Result<u64, Self::Error> {
        Err(TreeNodeDecodingError::UnsupportedType)
    }

    fn read_u32(&mut self) -> Result<u32, Self::Error> {
        Err(TreeNodeDecodingError::UnsupportedType)
    }

    fn read_u16(&mut self) -> Result<u16, Self::Error> {
        Err(TreeNodeDecodingError::UnsupportedType)
    }

    fn read_u8(&mut self) -> Result<u8, Self::Error> {
        Err(TreeNodeDecodingError::UnsupportedType)
    }

    fn read_isize(&mut self) -> Result<isize, Self::Error> {
        Err(TreeNodeDecodingError::UnsupportedType)
    }

    fn read_i64(&mut self) -> Result<i64, Self::Error> {
        Err(TreeNodeDecodingError::UnsupportedType)
    }

    fn read_char(&mut self) -> Result<char, Self::Error> {
        Err(TreeNodeDecodingError::UnsupportedType)
    }

    fn read_enum<T, F>(&mut self, name: &str, f: F) -> Result<T, Self::Error> where F: FnOnce(&mut Self) -> Result<T, Self::Error> {
        Err(TreeNodeDecodingError::UnsupportedType)
    }

    fn read_enum_variant<T, F>(&mut self, names: &[&str], f: F) -> Result<T, Self::Error> where F: FnMut(&mut Self, usize) -> Result<T, Self::Error> {
        Err(TreeNodeDecodingError::UnsupportedType)
    }

    fn read_enum_variant_arg<T, F>(&mut self, a_idx: usize, f: F) -> Result<T, Self::Error> where F: FnOnce(&mut Self) -> Result<T, Self::Error> {
        Err(TreeNodeDecodingError::UnsupportedType)
    }

    fn read_enum_struct_variant<T, F>(&mut self, names: &[&str], f: F) -> Result<T, Self::Error> where F: FnMut(&mut Self, usize) -> Result<T, Self::Error> {
        Err(TreeNodeDecodingError::UnsupportedType)
    }

    fn read_enum_struct_variant_field<T, F>(&mut self, f_name: &str, f_idx: usize, f: F) -> Result<T, Self::Error> where F: FnOnce(&mut Self) -> Result<T, Self::Error> {
        Err(TreeNodeDecodingError::UnsupportedType)
    }

    fn read_tuple<T, F>(&mut self, len: usize, f: F) -> Result<T, Self::Error> where F: FnOnce(&mut Self) -> Result<T, Self::Error> {
        Err(TreeNodeDecodingError::UnsupportedType)
    }

    fn read_tuple_arg<T, F>(&mut self, a_idx: usize, f: F) -> Result<T, Self::Error> where F: FnOnce(&mut Self) -> Result<T, Self::Error> {
        Err(TreeNodeDecodingError::UnsupportedType)
    }

    fn read_tuple_struct<T, F>(&mut self, s_name: &str, len: usize, f: F) -> Result<T, Self::Error> where F: FnOnce(&mut Self) -> Result<T, Self::Error> {
        Err(TreeNodeDecodingError::UnsupportedType)
    }

    fn read_tuple_struct_arg<T, F>(&mut self, a_idx: usize, f: F) -> Result<T, Self::Error> where F: FnOnce(&mut Self) -> Result<T, Self::Error> {
        Err(TreeNodeDecodingError::UnsupportedType)
    }

    fn read_option<T, F>(&mut self, f: F) -> Result<T, Self::Error> where F: FnMut(&mut Self, bool) -> Result<T, Self::Error> {
        Err(TreeNodeDecodingError::UnsupportedType)
    }

    fn read_seq<T, F>(&mut self, f: F) -> Result<T, Self::Error> where F: FnOnce(&mut Self, usize) -> Result<T, Self::Error> {
        Err(TreeNodeDecodingError::UnsupportedType)
    }

    fn read_seq_elt<T, F>(&mut self, idx: usize, f: F) -> Result<T, Self::Error> where F: FnOnce(&mut Self) -> Result<T, Self::Error> {
        Err(TreeNodeDecodingError::UnsupportedType)
    }

    fn read_map<T, F>(&mut self, f: F) -> Result<T, Self::Error> where F: FnOnce(&mut Self, usize) -> Result<T, Self::Error> {
        Err(TreeNodeDecodingError::UnsupportedType)
    }

    fn read_map_elt_key<T, F>(&mut self, idx: usize, f: F) -> Result<T, Self::Error> where F: FnOnce(&mut Self) -> Result<T, Self::Error> {
        Err(TreeNodeDecodingError::UnsupportedType)
    }

    fn read_map_elt_val<T, F>(&mut self, idx: usize, f: F) -> Result<T, Self::Error> where F: FnOnce(&mut Self) -> Result<T, Self::Error> {
        Err(TreeNodeDecodingError::UnsupportedType)
    }

    fn error(&mut self, err: &str) -> Self::Error {
        TreeNodeDecodingError::GenericError(err.to_string())
    }
}

///
/// Trait implemented by things that can be decoded from a tree node
///
pub trait DecodeFromTreeNode : Sized {
    ///
    /// Creates a new object from a tree node
    ///
    fn new_from_tree(tree: &TreeRef) -> Result<Self, TreeNodeDecodingError>;
}

impl<T: Decodable + EncodeToTreeNode> DecodeFromTreeNode for T {
    ///
    /// Creates a new object from a tree node
    ///
    fn new_from_tree(tree: &TreeRef) -> Result<T, TreeNodeDecodingError> {
        let mut decoder = TreeNodeDecoder { current_node: tree.to_owned() };

        T::decode(&mut decoder)
    }
}

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

    #[derive(RustcEncodable, RustcDecodable)]
    struct Test {
        field1: i32,
        field2: String,
        field3: bool
    }

    impl EncodeToTreeNode for Test { }

    #[test]
    fn encode_decode_structure() {
        let initial_structure = Test { field1: 42, field2: "test string".to_string(), field3: true };

        let encoded = initial_structure.to_tree_node();
        let decoded = Test::new_from_tree(&encoded);

        assert!(decoded.is_ok());

        let result = decoded.unwrap();

        assert!(result.field1 == 42);
        assert!(result.field2 == "test string");
        assert!(result.field3);
    }
}
<commit_msg>Helpful to have the name of the missing field in the event there is one when dealing with a decoder error<commit_after>//
//   Copyright 2016 Andrew Hunter
//
//   Licensed under the Apache License, Version 2.0 (the "License");
//   you may not use this file except in compliance with the License.
//   You may obtain a copy of the License at
//
//       http://www.apache.org/licenses/LICENSE-2.0
//
//   Unless required by applicable law or agreed to in writing, software
//   distributed under the License is distributed on an "AS IS" BASIS,
//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//   See the License for the specific language governing permissions and
//   limitations under the License.
//

use rustc_serialize::*;

use super::encoder::*;
use super::treenode::*;
use super::values::*;

///
/// Used to help decode tree nodes into other types
///
struct TreeNodeDecoder {
    current_node: TreeRef
}

#[derive(Debug)]
pub enum TreeNodeDecodingError {
    UnsupportedType,
    NodeHasInvalidType,
    ValueOutOfRange,
    MissingField(String),
    GenericError(String)
}

impl TreeNodeDecoder {
    fn read_current(&self) -> &TreeValue {
        self.current_node.get_value()
    }
}

#[allow(unused_variables)]          // Unused function parameters are quite common due to the way this trait is designed
impl Decoder for TreeNodeDecoder {
    type Error = TreeNodeDecodingError;

    fn read_nil(&mut self) -> Result<(), Self::Error> {
        match *self.read_current() {
            TreeValue::Nothing  => Ok(()),
            _                   => Err(TreeNodeDecodingError::NodeHasInvalidType)
        }
    }

    fn read_i32(&mut self) -> Result<i32, Self::Error> {
        match *self.read_current() {
            TreeValue::Int(ref x)   => Ok(*x),
            _                       => Err(TreeNodeDecodingError::NodeHasInvalidType)
        }
    }

    fn read_i16(&mut self) -> Result<i16, Self::Error> {
        match *self.read_current() {
            TreeValue::Int(ref x)   => if (*x >= i16::min_value() as i32) && (*x <= i16::max_value() as i32) { Ok(*x as i16) } else { Err(TreeNodeDecodingError::ValueOutOfRange) },
            _                       => Err(TreeNodeDecodingError::NodeHasInvalidType)
        }
    }

    fn read_i8(&mut self) -> Result<i8, Self::Error> {
        match *self.read_current() {
            TreeValue::Int(ref x)   => if (*x >= i8::min_value() as i32) && (*x <= i8::max_value() as i32) { Ok(*x as i8) } else { Err(TreeNodeDecodingError::ValueOutOfRange) },
            _                       => Err(TreeNodeDecodingError::NodeHasInvalidType)
        }
    }

    fn read_str(&mut self) -> Result<String, Self::Error> {
        match *self.read_current() {
            TreeValue::String(ref x)    => Ok(x.to_owned()),
            _                           => Err(TreeNodeDecodingError::NodeHasInvalidType)
        }
    }

    fn read_bool(&mut self) -> Result<bool, Self::Error> {
        match *self.read_current() {
            TreeValue::Bool(ref x)  => Ok(*x),
            _                       => Err(TreeNodeDecodingError::NodeHasInvalidType)
        }
    }

    fn read_f64(&mut self) -> Result<f64, Self::Error> {
        match *self.read_current() {
            TreeValue::Real(ref x)  => Ok(*x),
            _                       => Err(TreeNodeDecodingError::NodeHasInvalidType)
        }
    }

    fn read_f32(&mut self) -> Result<f32, Self::Error> {
        match *self.read_current() {
            TreeValue::Real(ref x)  => Ok(*x as f32),
            _                       => Err(TreeNodeDecodingError::NodeHasInvalidType)
        }
    }

    fn read_struct<T, F>(&mut self, s_name: &str, len: usize, f: F) -> Result<T, Self::Error> where F: FnOnce(&mut Self) -> Result<T, Self::Error> {
        f(self)
    }

    fn read_struct_field<T, F>(&mut self, f_name: &str, f_idx: usize, f: F) -> Result<T, Self::Error> where F: FnOnce(&mut Self) -> Result<T, Self::Error> {
        // Look up the field
        // TODO: could hash the field names to avoid doing a linear search every time (not clear if there are substantial benefits for this given the small number of fields in most structures)
        let field = self.current_node.get_child_ref_at(f_name);

        match field {
            None        => Err(TreeNodeDecodingError::MissingField(f_name.to_string())),
            Some(ref x) => {
                // Move into the field node
                let previous_node = self.current_node.to_owned();
                self.current_node = x.to_owned();

                // Decode it
                let result = f(self);

                // Move back out
                self.current_node = previous_node.to_owned();

                result
            }
        }
    }

    fn read_usize(&mut self) -> Result<usize, Self::Error> {
        Err(TreeNodeDecodingError::UnsupportedType)
    }

    fn read_u64(&mut self) -> Result<u64, Self::Error> {
        Err(TreeNodeDecodingError::UnsupportedType)
    }

    fn read_u32(&mut self) -> Result<u32, Self::Error> {
        Err(TreeNodeDecodingError::UnsupportedType)
    }

    fn read_u16(&mut self) -> Result<u16, Self::Error> {
        Err(TreeNodeDecodingError::UnsupportedType)
    }

    fn read_u8(&mut self) -> Result<u8, Self::Error> {
        Err(TreeNodeDecodingError::UnsupportedType)
    }

    fn read_isize(&mut self) -> Result<isize, Self::Error> {
        Err(TreeNodeDecodingError::UnsupportedType)
    }

    fn read_i64(&mut self) -> Result<i64, Self::Error> {
        Err(TreeNodeDecodingError::UnsupportedType)
    }

    fn read_char(&mut self) -> Result<char, Self::Error> {
        Err(TreeNodeDecodingError::UnsupportedType)
    }

    fn read_enum<T, F>(&mut self, name: &str, f: F) -> Result<T, Self::Error> where F: FnOnce(&mut Self) -> Result<T, Self::Error> {
        Err(TreeNodeDecodingError::UnsupportedType)
    }

    fn read_enum_variant<T, F>(&mut self, names: &[&str], f: F) -> Result<T, Self::Error> where F: FnMut(&mut Self, usize) -> Result<T, Self::Error> {
        Err(TreeNodeDecodingError::UnsupportedType)
    }

    fn read_enum_variant_arg<T, F>(&mut self, a_idx: usize, f: F) -> Result<T, Self::Error> where F: FnOnce(&mut Self) -> Result<T, Self::Error> {
        Err(TreeNodeDecodingError::UnsupportedType)
    }

    fn read_enum_struct_variant<T, F>(&mut self, names: &[&str], f: F) -> Result<T, Self::Error> where F: FnMut(&mut Self, usize) -> Result<T, Self::Error> {
        Err(TreeNodeDecodingError::UnsupportedType)
    }

    fn read_enum_struct_variant_field<T, F>(&mut self, f_name: &str, f_idx: usize, f: F) -> Result<T, Self::Error> where F: FnOnce(&mut Self) -> Result<T, Self::Error> {
        Err(TreeNodeDecodingError::UnsupportedType)
    }

    fn read_tuple<T, F>(&mut self, len: usize, f: F) -> Result<T, Self::Error> where F: FnOnce(&mut Self) -> Result<T, Self::Error> {
        Err(TreeNodeDecodingError::UnsupportedType)
    }

    fn read_tuple_arg<T, F>(&mut self, a_idx: usize, f: F) -> Result<T, Self::Error> where F: FnOnce(&mut Self) -> Result<T, Self::Error> {
        Err(TreeNodeDecodingError::UnsupportedType)
    }

    fn read_tuple_struct<T, F>(&mut self, s_name: &str, len: usize, f: F) -> Result<T, Self::Error> where F: FnOnce(&mut Self) -> Result<T, Self::Error> {
        Err(TreeNodeDecodingError::UnsupportedType)
    }

    fn read_tuple_struct_arg<T, F>(&mut self, a_idx: usize, f: F) -> Result<T, Self::Error> where F: FnOnce(&mut Self) -> Result<T, Self::Error> {
        Err(TreeNodeDecodingError::UnsupportedType)
    }

    fn read_option<T, F>(&mut self, f: F) -> Result<T, Self::Error> where F: FnMut(&mut Self, bool) -> Result<T, Self::Error> {
        Err(TreeNodeDecodingError::UnsupportedType)
    }

    fn read_seq<T, F>(&mut self, f: F) -> Result<T, Self::Error> where F: FnOnce(&mut Self, usize) -> Result<T, Self::Error> {
        Err(TreeNodeDecodingError::UnsupportedType)
    }

    fn read_seq_elt<T, F>(&mut self, idx: usize, f: F) -> Result<T, Self::Error> where F: FnOnce(&mut Self) -> Result<T, Self::Error> {
        Err(TreeNodeDecodingError::UnsupportedType)
    }

    fn read_map<T, F>(&mut self, f: F) -> Result<T, Self::Error> where F: FnOnce(&mut Self, usize) -> Result<T, Self::Error> {
        Err(TreeNodeDecodingError::UnsupportedType)
    }

    fn read_map_elt_key<T, F>(&mut self, idx: usize, f: F) -> Result<T, Self::Error> where F: FnOnce(&mut Self) -> Result<T, Self::Error> {
        Err(TreeNodeDecodingError::UnsupportedType)
    }

    fn read_map_elt_val<T, F>(&mut self, idx: usize, f: F) -> Result<T, Self::Error> where F: FnOnce(&mut Self) -> Result<T, Self::Error> {
        Err(TreeNodeDecodingError::UnsupportedType)
    }

    fn error(&mut self, err: &str) -> Self::Error {
        TreeNodeDecodingError::GenericError(err.to_string())
    }
}

///
/// Trait implemented by things that can be decoded from a tree node
///
pub trait DecodeFromTreeNode : Sized {
    ///
    /// Creates a new object from a tree node
    ///
    fn new_from_tree(tree: &TreeRef) -> Result<Self, TreeNodeDecodingError>;
}

impl<T: Decodable + EncodeToTreeNode> DecodeFromTreeNode for T {
    ///
    /// Creates a new object from a tree node
    ///
    fn new_from_tree(tree: &TreeRef) -> Result<T, TreeNodeDecodingError> {
        let mut decoder = TreeNodeDecoder { current_node: tree.to_owned() };

        T::decode(&mut decoder)
    }
}

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

    #[derive(RustcEncodable, RustcDecodable)]
    struct Test {
        field1: i32,
        field2: String,
        field3: bool
    }

    impl EncodeToTreeNode for Test { }

    #[test]
    fn encode_decode_structure() {
        let initial_structure = Test { field1: 42, field2: "test string".to_string(), field3: true };

        let encoded = initial_structure.to_tree_node();
        let decoded = Test::new_from_tree(&encoded);

        assert!(decoded.is_ok());

        let result = decoded.unwrap();

        assert!(result.field1 == 42);
        assert!(result.field2 == "test string");
        assert!(result.field3);
    }
}
<|endoftext|>


<commit_before>// Disable this lint to avoid it wanting to change `0xABCDEF` to `0xAB_CDEF`.
#![allow(clippy::unreadable_literal)]

macro_rules! colour {
    ($(#[$attr:meta] $constname:ident, $name:ident, $val:expr;)*) => {
        impl Colour {
            $(
                #[$attr]
                pub const $constname: Colour = Colour($val);
            )*
        }
    }
}

/// A utility struct to help with working with the basic representation of a
/// colour. This is particularly useful when working with a [`Role`]'s colour,
/// as the API works with an integer value instead of an RGB value.
///
/// Instances can be created by using the struct's associated functions. These
/// produce presets equivalent to those found in the official client's colour
/// picker.
///
/// # Examples
///
/// Passing in a role's colour, and then retrieving its green component
/// via [`Self::g`]:
///
/// ```rust
/// # extern crate serde_json;
/// # extern crate serenity;
/// #
/// # use serde_json::json;
/// # use serenity::model::guild::Role;
/// # use serenity::model::id::RoleId;
/// # use serenity::model::id::GuildId;
/// # use serenity::model::permissions;
/// #
/// # fn main() {
/// # let role = serde_json::from_value::<Role>(json!({
/// #     "color": Colour::BLURPLE,
/// #     "hoist": false,
/// #     "id": RoleId(1),
/// #     "guild_id": GuildId(2),
/// #     "managed": false,
/// #     "mentionable": false,
/// #     "name": "test",
/// #     "permissions": permissions::PRESET_GENERAL,
/// #     "position": 7,
/// # })).unwrap();
/// #
/// use serenity::utils::Colour;
///
/// // assuming a `role` has already been bound
///
/// let green = role.colour.g();
///
/// println!("The green component is: {}", green);
/// # }
/// ```
///
/// Creating an instance with the [`Self::DARK_TEAL`] preset:
///
/// ```rust
/// use serenity::utils::Colour;
///
/// let colour = Colour::DARK_TEAL;
///
/// assert_eq!(colour.tuple(), (17, 128, 106));
/// ```
///
/// Colours can also be directly compared for equivalence:
///
/// ```rust
/// use serenity::utils::Colour;
///
/// let blitz_blue = Colour::BLITZ_BLUE;
/// let fooyoo = Colour::FOOYOO;
/// let fooyoo2 = Colour::FOOYOO;
/// assert!(blitz_blue != fooyoo);
/// assert_eq!(fooyoo, fooyoo2);
/// assert!(blitz_blue > fooyoo);
/// ```
///
/// [`Role`]: crate::model::guild::Role
#[derive(Clone, Copy, Debug, Deserialize, Eq, Ord, PartialEq, PartialOrd, Serialize)]
pub struct Colour(pub u32);

impl Colour {
    /// Generates a new Colour with the given integer value set.
    ///
    /// # Examples
    ///
    /// Create a new Colour, and then ensure that its inner value is equivalent
    /// to a specific RGB value, retrieved via [`Self::tuple`]:
    ///
    /// ```rust
    /// use serenity::utils::Colour;
    ///
    /// let colour = Colour::new(6573123);
    ///
    /// assert_eq!(colour.tuple(), (100, 76, 67));
    /// ```
    #[inline]
    pub const fn new(value: u32) -> Colour {
        Colour(value)
    }

    /// Generates a new Colour from an RGB value, creating an inner u32
    /// representation.
    ///
    /// # Examples
    ///
    /// Creating a [`Colour`] via its RGB values will set its inner u32 correctly:
    ///
    /// ```rust
    /// use serenity::utils::Colour;
    ///
    /// assert!(Colour::from_rgb(255, 0, 0).0 == 0xFF0000);
    /// assert!(Colour::from_rgb(217, 23, 211).0 == 0xD917D3);
    /// ```
    ///
    /// And you can then retrieve those same RGB values via its methods:
    ///
    /// ```rust
    /// use serenity::utils::Colour;
    ///
    /// let colour = Colour::from_rgb(217, 45, 215);
    ///
    /// assert_eq!(colour.r(), 217);
    /// assert_eq!(colour.g(), 45);
    /// assert_eq!(colour.b(), 215);
    /// assert_eq!(colour.tuple(), (217, 45, 215));
    /// ```
    // Clippy wants to use `u32::from` instead `as`-casts,
    // but this not doable as `u32::from` is not a const fn.
    #[allow(clippy::cast_lossless)]
    pub const fn from_rgb(red: u8, green: u8, blue: u8) -> Colour {
        Colour((red as u32) << 16 | (green as u32) << 8 | blue as u32)
    }

    /// Returns the red RGB component of this Colour.
    ///
    /// # Examples
    ///
    /// ```rust
    /// use serenity::utils::Colour;
    ///
    /// assert_eq!(Colour::new(6573123).r(), 100);
    /// ```
    pub const fn r(self) -> u8 {
        ((self.0 >> 16) & 255) as u8
    }

    /// Returns the green RGB component of this Colour.
    ///
    /// # Examples
    ///
    /// ```rust
    /// use serenity::utils::Colour;
    ///
    /// assert_eq!(Colour::new(6573123).g(), 76);
    /// ```
    pub const fn g(self) -> u8 {
        ((self.0 >> 8) & 255) as u8
    }

    /// Returns the blue RGB component of this Colour.
    ///
    /// # Examples
    ///
    /// ```rust
    /// use serenity::utils::Colour;
    ///
    /// assert_eq!(Colour::new(6573123).b(), 67);
    pub const fn b(self) -> u8 {
        (self.0 & 255) as u8
    }

    /// Returns a tuple of the red, green, and blue components of this Colour.
    ///
    /// This is equivalent to creating a tuple with the return values of
    /// [`Self::r`], [`Self::g`], and [`Self::b`].
    ///
    /// # Examples
    ///
    /// ```rust
    /// use serenity::utils::Colour;
    ///
    /// assert_eq!(Colour::new(6573123).tuple(), (100, 76, 67));
    /// ```
    pub const fn tuple(self) -> (u8, u8, u8) {
        (self.r(), self.g(), self.b())
    }

    /// Returns a hexadecimal string of this Colour.
    ///
    /// This is equivalent to passing the integer value through
    /// [`std::fmt::UpperHex`] with 0 padding and 6 width.
    ///
    /// # Examples
    ///
    /// ```rust
    /// use serenity::utils::Colour;
    ///
    /// assert_eq!(Colour::new(6573123).hex(), "644C43");
    /// ```
    pub fn hex(self) -> String {
        format!("{:06X}", self.0)
    }
}

impl From<i32> for Colour {
    /// Constructs a Colour from a i32.
    ///
    /// This is used for functions that accept `Into<Colour>`.
    ///
    /// This is useful when providing hex values.
    ///
    /// # Examples
    ///
    /// ```rust
    /// use serenity::utils::Colour;
    ///
    /// assert_eq!(Colour::from(0xDEA584).tuple(), (222, 165, 132));
    /// ```
    fn from(value: i32) -> Colour {
        Colour(value as u32)
    }
}

impl From<u32> for Colour {
    /// Constructs a Colour from a u32.
    ///
    /// This is used for functions that accept `Into<Colour>`.
    ///
    /// # Examples
    ///
    /// ```rust
    /// use serenity::utils::Colour;
    ///
    /// assert_eq!(Colour::from(6573123u32).r(), 100);
    /// ```
    fn from(value: u32) -> Colour {
        Colour(value)
    }
}

impl From<u64> for Colour {
    /// Constructs a Colour from a u32.
    ///
    /// This is used for functions that accept `Into<Colour>`.
    ///
    /// # Examples
    ///
    /// ```rust
    /// use serenity::utils::Colour;
    ///
    /// assert_eq!(Colour::from(6573123u64).r(), 100);
    /// ```
    fn from(value: u64) -> Colour {
        Colour(value as u32)
    }
}

impl From<(u8, u8, u8)> for Colour {
    /// Constructs a Colour from RGB.
    fn from((red, green, blue): (u8, u8, u8)) -> Self {
        Colour::from_rgb(red, green, blue)
    }
}

colour! {
    /// Creates a new [`Colour`], setting its RGB value to `(111, 198, 226)`.
    BLITZ_BLUE, blitz_blue, 0x6FC6E2;
    /// Creates a new [`Colour`], setting its RGB value to `(52, 152, 219)`.
    BLUE, blue, 0x3498DB;
    /// Creates a new [`Colour`], setting its RGB value to `(114, 137, 218)`.
    BLURPLE, blurple, 0x7289DA;
    /// Creates a new [`Colour`], setting its RGB value to `(32, 102, 148)`.
    DARK_BLUE, dark_blue, 0x206694;
    /// Creates a new [`Colour`], setting its RGB value to `(194, 124, 14)`.
    DARK_GOLD, dark_gold, 0xC27C0E;
    /// Creates a new [`Colour`], setting its RGB value to `(31, 139, 76)`.
    DARK_GREEN, dark_green, 0x1F8B4C;
    /// Creates a new [`Colour`], setting its RGB value to `(96, 125, 139)`.
    DARK_GREY, dark_grey, 0x607D8B;
    /// Creates a new [`Colour`], setting its RGB value to `(173, 20, 87)`.
    DARK_MAGENTA, dark_magenta, 0xAD1457;
    /// Creates a new [`Colour`], setting its RGB value to `(168, 67, 0)`.
    DARK_ORANGE, dark_orange, 0xA84300;
    /// Creates a new [`Colour`], setting its RGB value to `(113, 54, 138)`.
    DARK_PURPLE, dark_purple, 0x71368A;
    /// Creates a new [`Colour`], setting its RGB value to `(153, 45, 34)`.
    DARK_RED, dark_red, 0x992D22;
    /// Creates a new [`Colour`], setting its RGB value to `(17, 128, 106)`.
    DARK_TEAL, dark_teal, 0x11806A;
    /// Creates a new [`Colour`], setting its RGB value to `(84, 110, 122)`.
    DARKER_GREY, darker_grey, 0x546E7A;
    /// Creates a new [`Colour`], setting its RGB value to `(250, 177, 237)`.
    FABLED_PINK, fabled_pink, 0xFAB1ED;
    /// Creates a new [`Colour`], setting its RGB value to `(136, 130, 196)`.
    FADED_PURPLE, faded_purple, 0x8882C4;
    /// Creates a new [`Colour`], setting its RGB value to `(17, 202, 128)`.
    FOOYOO, fooyoo, 0x11CA80;
    /// Creates a new [`Colour`], setting its RGB value to `(241, 196, 15)`.
    GOLD, gold, 0xF1C40F;
    /// Creates a new [`Colour`], setting its RGB value to `(186, 218, 85)`.
    KERBAL, kerbal, 0xBADA55;
    /// Creates a new [`Colour`], setting its RGB value to `(151, 156, 159)`.
    LIGHT_GREY, light_grey, 0x979C9F;
    /// Creates a new [`Colour`], setting its RGB value to `(149, 165, 166)`.
    LIGHTER_GREY, lighter_grey, 0x95A5A6;
    /// Creates a new [`Colour`], setting its RGB value to `(233, 30, 99)`.
    MAGENTA, magenta, 0xE91E63;
    /// Creates a new [`Colour`], setting its RGB value to `(230, 131, 151)`.
    MEIBE_PINK, meibe_pink, 0xE68397;
    /// Creates a new [`Colour`], setting its RGB value to `(230, 126, 34)`.
    ORANGE, orange, 0xE67E22;
    /// Creates a new [`Colour`], setting its RGB value to `(155, 89, 182)`.
    PURPLE, purple, 0x9B59B6;
    /// Creates a new [`Colour`], setting its RGB value to `(231, 76, 60)`.
    RED, red, 0xE74C3C;
    /// Creates a new [`Colour`], setting its RGB value to `(117, 150, 255)`.
    ROHRKATZE_BLUE, rohrkatze_blue, 0x7596FF;
    /// Creates a new [`Colour`], setting its RGB value to `(246, 219, 216)`.
    ROSEWATER, rosewater, 0xF6DBD8;
    /// Creates a new [`Colour`], setting its RGB value to `(26, 188, 156)`.
    TEAL, teal, 0x1ABC9C;
}

impl Default for Colour {
    /// Creates a default value for a [`Colour`], setting the inner value to `0`.
    fn default() -> Colour {
        Colour(0)
    }
}

#[cfg(test)]
mod test {
    use std::u32;

    use super::Colour;

    #[test]
    fn new() {
        assert_eq!(Colour::new(1).0, 1);
        assert_eq!(Colour::new(u32::MIN).0, u32::MIN);
        assert_eq!(Colour::new(u32::MAX).0, u32::MAX);
    }

    #[test]
    fn from_rgb() {
        assert_eq!(Colour::from_rgb(255, 0, 0).0, 0xFF0000);
        assert_eq!(Colour::from_rgb(0, 255, 0).0, 0x00FF00);
        assert_eq!(Colour::from_rgb(0, 0, 255).0, 0x0000FF);
    }

    #[test]
    fn r() {
        assert_eq!(Colour::new(0x336123).r(), 0x33);
    }

    #[test]
    fn g() {
        assert_eq!(Colour::new(0x336123).g(), 0x61);
    }

    #[test]
    fn b() {
        assert_eq!(Colour::new(0x336123).b(), 0x23);
    }

    #[test]
    fn tuple() {
        assert_eq!(Colour::new(0x336123).tuple(), (0x33, 0x61, 0x23));
    }

    #[test]
    fn default() {
        assert_eq!(Colour::default().0, 0);
    }

    #[test]
    fn from() {
        assert_eq!(Colour::from(7i32).0, 7);
        assert_eq!(Colour::from(7u32).0, 7);
        assert_eq!(Colour::from(7u64).0, 7);
    }
}
<commit_msg>Remove unused function names from the `colour!` macro (#1527)<commit_after>// Disable this lint to avoid it wanting to change `0xABCDEF` to `0xAB_CDEF`.
#![allow(clippy::unreadable_literal)]

/// A utility struct to help with working with the basic representation of a
/// colour. This is particularly useful when working with a [`Role`]'s colour,
/// as the API works with an integer value instead of an RGB value.
///
/// Instances can be created by using the struct's associated functions. These
/// produce presets equivalent to those found in the official client's colour
/// picker.
///
/// # Examples
///
/// Passing in a role's colour, and then retrieving its green component
/// via [`Self::g`]:
///
/// ```rust
/// # extern crate serde_json;
/// # extern crate serenity;
/// #
/// # use serde_json::json;
/// # use serenity::model::guild::Role;
/// # use serenity::model::id::RoleId;
/// # use serenity::model::id::GuildId;
/// # use serenity::model::permissions;
/// #
/// # fn main() {
/// # let role = serde_json::from_value::<Role>(json!({
/// #     "color": Colour::BLURPLE,
/// #     "hoist": false,
/// #     "id": RoleId(1),
/// #     "guild_id": GuildId(2),
/// #     "managed": false,
/// #     "mentionable": false,
/// #     "name": "test",
/// #     "permissions": permissions::PRESET_GENERAL,
/// #     "position": 7,
/// # })).unwrap();
/// #
/// use serenity::utils::Colour;
///
/// // assuming a `role` has already been bound
///
/// let green = role.colour.g();
///
/// println!("The green component is: {}", green);
/// # }
/// ```
///
/// Creating an instance with the [`Self::DARK_TEAL`] preset:
///
/// ```rust
/// use serenity::utils::Colour;
///
/// let colour = Colour::DARK_TEAL;
///
/// assert_eq!(colour.tuple(), (17, 128, 106));
/// ```
///
/// Colours can also be directly compared for equivalence:
///
/// ```rust
/// use serenity::utils::Colour;
///
/// let blitz_blue = Colour::BLITZ_BLUE;
/// let fooyoo = Colour::FOOYOO;
/// let fooyoo2 = Colour::FOOYOO;
/// assert!(blitz_blue != fooyoo);
/// assert_eq!(fooyoo, fooyoo2);
/// assert!(blitz_blue > fooyoo);
/// ```
///
/// [`Role`]: crate::model::guild::Role
#[derive(Clone, Copy, Debug, Deserialize, Eq, Ord, PartialEq, PartialOrd, Serialize)]
pub struct Colour(pub u32);

impl Colour {
    /// Generates a new Colour with the given integer value set.
    ///
    /// # Examples
    ///
    /// Create a new Colour, and then ensure that its inner value is equivalent
    /// to a specific RGB value, retrieved via [`Self::tuple`]:
    ///
    /// ```rust
    /// use serenity::utils::Colour;
    ///
    /// let colour = Colour::new(6573123);
    ///
    /// assert_eq!(colour.tuple(), (100, 76, 67));
    /// ```
    #[inline]
    pub const fn new(value: u32) -> Colour {
        Colour(value)
    }

    /// Generates a new Colour from an RGB value, creating an inner u32
    /// representation.
    ///
    /// # Examples
    ///
    /// Creating a [`Colour`] via its RGB values will set its inner u32 correctly:
    ///
    /// ```rust
    /// use serenity::utils::Colour;
    ///
    /// assert!(Colour::from_rgb(255, 0, 0).0 == 0xFF0000);
    /// assert!(Colour::from_rgb(217, 23, 211).0 == 0xD917D3);
    /// ```
    ///
    /// And you can then retrieve those same RGB values via its methods:
    ///
    /// ```rust
    /// use serenity::utils::Colour;
    ///
    /// let colour = Colour::from_rgb(217, 45, 215);
    ///
    /// assert_eq!(colour.r(), 217);
    /// assert_eq!(colour.g(), 45);
    /// assert_eq!(colour.b(), 215);
    /// assert_eq!(colour.tuple(), (217, 45, 215));
    /// ```
    // Clippy wants to use `u32::from` instead `as`-casts,
    // but this not doable as `u32::from` is not a const fn.
    #[allow(clippy::cast_lossless)]
    pub const fn from_rgb(red: u8, green: u8, blue: u8) -> Colour {
        Colour((red as u32) << 16 | (green as u32) << 8 | blue as u32)
    }

    /// Returns the red RGB component of this Colour.
    ///
    /// # Examples
    ///
    /// ```rust
    /// use serenity::utils::Colour;
    ///
    /// assert_eq!(Colour::new(6573123).r(), 100);
    /// ```
    pub const fn r(self) -> u8 {
        ((self.0 >> 16) & 255) as u8
    }

    /// Returns the green RGB component of this Colour.
    ///
    /// # Examples
    ///
    /// ```rust
    /// use serenity::utils::Colour;
    ///
    /// assert_eq!(Colour::new(6573123).g(), 76);
    /// ```
    pub const fn g(self) -> u8 {
        ((self.0 >> 8) & 255) as u8
    }

    /// Returns the blue RGB component of this Colour.
    ///
    /// # Examples
    ///
    /// ```rust
    /// use serenity::utils::Colour;
    ///
    /// assert_eq!(Colour::new(6573123).b(), 67);
    pub const fn b(self) -> u8 {
        (self.0 & 255) as u8
    }

    /// Returns a tuple of the red, green, and blue components of this Colour.
    ///
    /// This is equivalent to creating a tuple with the return values of
    /// [`Self::r`], [`Self::g`], and [`Self::b`].
    ///
    /// # Examples
    ///
    /// ```rust
    /// use serenity::utils::Colour;
    ///
    /// assert_eq!(Colour::new(6573123).tuple(), (100, 76, 67));
    /// ```
    pub const fn tuple(self) -> (u8, u8, u8) {
        (self.r(), self.g(), self.b())
    }

    /// Returns a hexadecimal string of this Colour.
    ///
    /// This is equivalent to passing the integer value through
    /// [`std::fmt::UpperHex`] with 0 padding and 6 width.
    ///
    /// # Examples
    ///
    /// ```rust
    /// use serenity::utils::Colour;
    ///
    /// assert_eq!(Colour::new(6573123).hex(), "644C43");
    /// ```
    pub fn hex(self) -> String {
        format!("{:06X}", self.0)
    }
}

impl From<i32> for Colour {
    /// Constructs a Colour from a i32.
    ///
    /// This is used for functions that accept `Into<Colour>`.
    ///
    /// This is useful when providing hex values.
    ///
    /// # Examples
    ///
    /// ```rust
    /// use serenity::utils::Colour;
    ///
    /// assert_eq!(Colour::from(0xDEA584).tuple(), (222, 165, 132));
    /// ```
    fn from(value: i32) -> Colour {
        Colour(value as u32)
    }
}

impl From<u32> for Colour {
    /// Constructs a Colour from a u32.
    ///
    /// This is used for functions that accept `Into<Colour>`.
    ///
    /// # Examples
    ///
    /// ```rust
    /// use serenity::utils::Colour;
    ///
    /// assert_eq!(Colour::from(6573123u32).r(), 100);
    /// ```
    fn from(value: u32) -> Colour {
        Colour(value)
    }
}

impl From<u64> for Colour {
    /// Constructs a Colour from a u32.
    ///
    /// This is used for functions that accept `Into<Colour>`.
    ///
    /// # Examples
    ///
    /// ```rust
    /// use serenity::utils::Colour;
    ///
    /// assert_eq!(Colour::from(6573123u64).r(), 100);
    /// ```
    fn from(value: u64) -> Colour {
        Colour(value as u32)
    }
}

impl From<(u8, u8, u8)> for Colour {
    /// Constructs a Colour from RGB.
    fn from((red, green, blue): (u8, u8, u8)) -> Self {
        Colour::from_rgb(red, green, blue)
    }
}

macro_rules! colour {
    ($(#[$attr:meta] $constname:ident, $val:expr;)*) => {
        impl Colour {
            $(
                #[$attr]
                pub const $constname: Colour = Colour($val);
            )*
        }
    }
}

colour! {
    /// Creates a new [`Colour`], setting its RGB value to `(111, 198, 226)`.
    BLITZ_BLUE, 0x6FC6E2;
    /// Creates a new [`Colour`], setting its RGB value to `(52, 152, 219)`.
    BLUE, 0x3498DB;
    /// Creates a new [`Colour`], setting its RGB value to `(114, 137, 218)`.
    BLURPLE, 0x7289DA;
    /// Creates a new [`Colour`], setting its RGB value to `(32, 102, 148)`.
    DARK_BLUE, 0x206694;
    /// Creates a new [`Colour`], setting its RGB value to `(194, 124, 14)`.
    DARK_GOLD, 0xC27C0E;
    /// Creates a new [`Colour`], setting its RGB value to `(31, 139, 76)`.
    DARK_GREEN, 0x1F8B4C;
    /// Creates a new [`Colour`], setting its RGB value to `(96, 125, 139)`.
    DARK_GREY, 0x607D8B;
    /// Creates a new [`Colour`], setting its RGB value to `(173, 20, 87)`.
    DARK_MAGENTA, 0xAD1457;
    /// Creates a new [`Colour`], setting its RGB value to `(168, 67, 0)`.
    DARK_ORANGE, 0xA84300;
    /// Creates a new [`Colour`], setting its RGB value to `(113, 54, 138)`.
    DARK_PURPLE, 0x71368A;
    /// Creates a new [`Colour`], setting its RGB value to `(153, 45, 34)`.
    DARK_RED, 0x992D22;
    /// Creates a new [`Colour`], setting its RGB value to `(17, 128, 106)`.
    DARK_TEAL, 0x11806A;
    /// Creates a new [`Colour`], setting its RGB value to `(84, 110, 122)`.
    DARKER_GREY, 0x546E7A;
    /// Creates a new [`Colour`], setting its RGB value to `(250, 177, 237)`.
    FABLED_PINK, 0xFAB1ED;
    /// Creates a new [`Colour`], setting its RGB value to `(136, 130, 196)`.
    FADED_PURPLE, 0x8882C4;
    /// Creates a new [`Colour`], setting its RGB value to `(17, 202, 128)`.
    FOOYOO, 0x11CA80;
    /// Creates a new [`Colour`], setting its RGB value to `(241, 196, 15)`.
    GOLD, 0xF1C40F;
    /// Creates a new [`Colour`], setting its RGB value to `(186, 218, 85)`.
    KERBAL, 0xBADA55;
    /// Creates a new [`Colour`], setting its RGB value to `(151, 156, 159)`.
    LIGHT_GREY, 0x979C9F;
    /// Creates a new [`Colour`], setting its RGB value to `(149, 165, 166)`.
    LIGHTER_GREY, 0x95A5A6;
    /// Creates a new [`Colour`], setting its RGB value to `(233, 30, 99)`.
    MAGENTA, 0xE91E63;
    /// Creates a new [`Colour`], setting its RGB value to `(230, 131, 151)`.
    MEIBE_PINK, 0xE68397;
    /// Creates a new [`Colour`], setting its RGB value to `(230, 126, 34)`.
    ORANGE, 0xE67E22;
    /// Creates a new [`Colour`], setting its RGB value to `(155, 89, 182)`.
    PURPLE, 0x9B59B6;
    /// Creates a new [`Colour`], setting its RGB value to `(231, 76, 60)`.
    RED, 0xE74C3C;
    /// Creates a new [`Colour`], setting its RGB value to `(117, 150, 255)`.
    ROHRKATZE_BLUE, 0x7596FF;
    /// Creates a new [`Colour`], setting its RGB value to `(246, 219, 216)`.
    ROSEWATER, 0xF6DBD8;
    /// Creates a new [`Colour`], setting its RGB value to `(26, 188, 156)`.
    TEAL, 0x1ABC9C;
}

impl Default for Colour {
    /// Creates a default value for a [`Colour`], setting the inner value to `0`.
    fn default() -> Colour {
        Colour(0)
    }
}

#[cfg(test)]
mod test {
    use std::u32;

    use super::Colour;

    #[test]
    fn new() {
        assert_eq!(Colour::new(1).0, 1);
        assert_eq!(Colour::new(u32::MIN).0, u32::MIN);
        assert_eq!(Colour::new(u32::MAX).0, u32::MAX);
    }

    #[test]
    fn from_rgb() {
        assert_eq!(Colour::from_rgb(255, 0, 0).0, 0xFF0000);
        assert_eq!(Colour::from_rgb(0, 255, 0).0, 0x00FF00);
        assert_eq!(Colour::from_rgb(0, 0, 255).0, 0x0000FF);
    }

    #[test]
    fn r() {
        assert_eq!(Colour::new(0x336123).r(), 0x33);
    }

    #[test]
    fn g() {
        assert_eq!(Colour::new(0x336123).g(), 0x61);
    }

    #[test]
    fn b() {
        assert_eq!(Colour::new(0x336123).b(), 0x23);
    }

    #[test]
    fn tuple() {
        assert_eq!(Colour::new(0x336123).tuple(), (0x33, 0x61, 0x23));
    }

    #[test]
    fn default() {
        assert_eq!(Colour::default().0, 0);
    }

    #[test]
    fn from() {
        assert_eq!(Colour::from(7i32).0, 7);
        assert_eq!(Colour::from(7u32).0, 7);
        assert_eq!(Colour::from(7u64).0, 7);
    }
}
<|endoftext|>


<commit_before>extern crate lp_modeler;

use lp_modeler::dsl::*;
use lp_modeler::dsl::LpExpression::*;

use lp_modeler::format::lp_format::LpFileFormat;

#[test]
fn expressions_creation() {
    let ref a = LpInteger::new("a").lower_bound(10.0).upper_bound(20.0);
    let ref b = LpInteger::new("b");

    assert_eq!(
        a + b,
        AddExpr(Box::new(ConsInt(a.clone())), Box::new(ConsInt(b.clone())))
    );
}

#[test]
fn distributivity() {
    let ref a = LpInteger::new("a");
    let ref b = LpInteger::new("b");
    let ref c = LpInteger::new("c");

    let test = a * (2 + b) * 3;
    let test2 = test.clone();
    assert_eq!((2 * (2 + a)).to_lp_file_format(), "2 a + 4");
    assert_eq!(
        ((2 + a) * (2 + b)).to_lp_file_format(),
        "2 a + 2 b + b a + 4"
    );
    assert_eq!(test.to_lp_file_format(), "6 a + 3 a b");
    assert_eq!((10 * test).to_lp_file_format(), "60 a + 30 a b");
    assert_eq!(
        ((c + 10) * test2).to_lp_file_format(),
        "6 c a + 3 c a b + 60 a + 30 a b"
    );

    let ref x = LpContinuous::new("x");
    let ref y = LpContinuous::new("y");
    let ref z = LpContinuous::new("z");

    let test3 = x * (y - z);
    assert_eq!((3 * (3 - a)).to_lp_file_format(), "-3 a + 9");
    assert_eq!(test3.to_lp_file_format(), "x y - x z");
    assert_eq!((4 * test3).to_lp_file_format(), "4 x y - 4 x z");
}

#[test]
fn associativity() {
    let ref a = LpInteger::new("a");
    let ref b = LpInteger::new("b");
    let ref c = LpInteger::new("c");

    assert_eq!((a + (b + 2)).to_lp_file_format(), "a + b + 2");
    assert_eq!(((a + b) + 2).to_lp_file_format(), "a + b + 2");

    assert_eq!((a + (b - 2)).to_lp_file_format(), "a + b - 2");
    assert_eq!(((a + b) - 2).to_lp_file_format(), "a + b - 2");

    assert_eq!((a - (b + 2)).to_lp_file_format(), "a - b - 2");
    assert_eq!(((a - b) + 2).to_lp_file_format(), "a - b + 2");

    assert_eq!((a - (b - 2)).to_lp_file_format(), "a - b + 2");
    assert_eq!(((a - b) - 2).to_lp_file_format(), "a - b - 2");

    assert_eq!((a - (b - 2) + c).to_lp_file_format(), "a - b + c + 2");
    assert_eq!(((a - b) - 2 + c).to_lp_file_format(), "a - b + c - 2");

    let ref x = LpBinary::new("x");
    let ref y = LpBinary::new("y");
    assert_eq!((x + (y + 1)).to_lp_file_format(), "x + y + 1");
    assert_eq!(((x + y) + 1).to_lp_file_format(), "x + y + 1");
}

#[test]
fn literal_first_with_accumulation() {
    let ref a = LpInteger::new("a");
    let ref b = LpInteger::new("b");
    let ref c = LpInteger::new("c");

    assert_eq!(
        (a + 1 + b + 2 + c + 3 + a + 4).to_lp_file_format(),
        "a + b + c + a + 10"
    );
    assert_eq!(
        (a - 1 + b - 2 - c + 3 + a - 4).to_lp_file_format(),
        "a + b - c + a - 4"
    );
    assert_eq!(
        (a + b + 1 - c - a - 3).to_lp_file_format(),
        "a + b - c - a - 2"
    );
    assert_eq!(
        (a + b + (c - 1) * 2 - a - 3).to_lp_file_format(),
        "a + b + 2 c - a - 5"
    );
    assert_eq!(
        (a + b + (1 - c) * 2 - a - 3).to_lp_file_format(),
        "a + b - 2 c - a - 1"
    );
    assert_eq!((2 * (a + 5)).to_lp_file_format(), "2 a + 10");
    assert_eq!(
        ((2 + b) * (a + 5)).to_lp_file_format(),
        "2 a + a b + 5 b + 10"
    );
    assert_eq!((2 + (a + b) + 3).to_lp_file_format(), "a + b + 5");
}

#[test]
fn trivial_rules() {
    let ref a = LpInteger::new("a");
    let ref b = LpInteger::new("b");

    assert_eq!(((a + b) * 0).to_lp_file_format(), "0");
    assert_eq!((0 * (a + b)).to_lp_file_format(), "0");
    assert_eq!((0 * a * b * 3).to_lp_file_format(), "0");
    assert_eq!(((a + b) + 0).to_lp_file_format(), "a + b");
    assert_eq!((0 + (a + b) + 0).to_lp_file_format(), "a + b");
    assert_eq!((0 + (a + b)).to_lp_file_format(), "a + b");
    assert_eq!(((a + b) - 0).to_lp_file_format(), "a + b");
    assert_eq!((0 - (a + b)).to_lp_file_format(), "-a - b");
    assert_eq!((0 + (a + b)).to_lp_file_format(), "a + b");
}

#[test]
fn expressions_to_lp_file_format() {
    let ref a = LpInteger::new("a");
    let ref b = LpInteger::new("b");
    let ref c = LpInteger::new("c");

    // Expressions
    assert_eq!((a + 2 * b + c).to_lp_file_format(), "a + 2 b + c");
    assert_eq!((a + b * 2 + c).to_lp_file_format(), "a + 2 b + c");
    assert_eq!((a + b * 2 + 3 * 2 * c).to_lp_file_format(), "a + 2 b + 6 c");
    assert_eq!((a + 2).to_lp_file_format(), "a + 2");
    assert_eq!(
        (2 * a + 2 * b - 4 * c).to_lp_file_format(),
        "2 a + 2 b - 4 c"
    );
    assert_eq!((-2 * a).to_lp_file_format(), "-2 a");

    // Constraints
    assert_eq!((a + b).equal(10).to_lp_file_format(), "a + b = 10");
    assert_eq!((2 * a + b).ge(10).to_lp_file_format(), "2 a + b >= 10");
    assert_eq!(
        (2 * a + b + 20).ge(c).to_lp_file_format(),
        "2 a + b - c >= -20"
    );
    assert_eq!((-a).ge(10).to_lp_file_format(), "-a >= 10");
    assert_eq!(
        (2 * a - 20 + b).ge(-c).to_lp_file_format(),
        "2 a + b + c >= 20"
    );
    assert_eq!((a + b + 10).ge(0).to_lp_file_format(), "a + b >= -10");
    assert_eq!(
        (3 * (a + b + 10)).le(0).to_lp_file_format(),
        "3 a + 3 b <= -30"
    );
    assert_eq!(
        (3 * (a + b + 10)).le(a + b).to_lp_file_format(),
        "3 a + 3 b - a - b <= -30"
    );
}

#[test]
fn expression_with_lp_sum() {
    let ref a = LpBinary::new("a");
    let ref b = LpBinary::new("b");
    let ref c = LpBinary::new("c");
    let ref d = LpBinary::new("d");

    let ref expr1 = vec!(a,b,c);
    let ref expr2 = vec!(a,b,c,d);
    let ref expr3 = vec!(a);
    let ref empty: Vec<&LpBinary> = vec!();
    assert_eq!(
        lp_sum(expr1).equal(10.0).to_lp_file_format(),
        "a + b + c = 10"
    );
    assert_eq!(
        lp_sum(expr2).equal(10.0).to_lp_file_format(),
        "a + b + c + d = 10"
    );
    assert_eq!(
        lp_sum(expr3).le(5.5).to_lp_file_format(),
        "a <= 5.5"
    );
    assert!(
        std::panic::catch_unwind( || lp_sum(empty)).is_err(),
        "should panic if empty vec"
    );
}

#[test]
fn simplifications() {
    let a = &LpInteger::new("a");

    let expr1 = a - 2f32;
    let expr2 = 1f32 - a;

    let (c, _) = split_constant_and_expr(&simplify(&(&expr1 + &expr2)));
    assert_eq!(c, -1f32);

    let (c, _) = split_constant_and_expr(&simplify(&(&expr2 + &expr1)));
    assert_eq!(c, -1f32);
}<commit_msg>uhh newline added automatically<commit_after>extern crate lp_modeler;

use lp_modeler::dsl::*;
use lp_modeler::dsl::LpExpression::*;

use lp_modeler::format::lp_format::LpFileFormat;

#[test]
fn expressions_creation() {
    let ref a = LpInteger::new("a").lower_bound(10.0).upper_bound(20.0);
    let ref b = LpInteger::new("b");

    assert_eq!(
        a + b,
        AddExpr(Box::new(ConsInt(a.clone())), Box::new(ConsInt(b.clone())))
    );
}

#[test]
fn distributivity() {
    let ref a = LpInteger::new("a");
    let ref b = LpInteger::new("b");
    let ref c = LpInteger::new("c");

    let test = a * (2 + b) * 3;
    let test2 = test.clone();
    assert_eq!((2 * (2 + a)).to_lp_file_format(), "2 a + 4");
    assert_eq!(
        ((2 + a) * (2 + b)).to_lp_file_format(),
        "2 a + 2 b + b a + 4"
    );
    assert_eq!(test.to_lp_file_format(), "6 a + 3 a b");
    assert_eq!((10 * test).to_lp_file_format(), "60 a + 30 a b");
    assert_eq!(
        ((c + 10) * test2).to_lp_file_format(),
        "6 c a + 3 c a b + 60 a + 30 a b"
    );

    let ref x = LpContinuous::new("x");
    let ref y = LpContinuous::new("y");
    let ref z = LpContinuous::new("z");

    let test3 = x * (y - z);
    assert_eq!((3 * (3 - a)).to_lp_file_format(), "-3 a + 9");
    assert_eq!(test3.to_lp_file_format(), "x y - x z");
    assert_eq!((4 * test3).to_lp_file_format(), "4 x y - 4 x z");
}

#[test]
fn associativity() {
    let ref a = LpInteger::new("a");
    let ref b = LpInteger::new("b");
    let ref c = LpInteger::new("c");

    assert_eq!((a + (b + 2)).to_lp_file_format(), "a + b + 2");
    assert_eq!(((a + b) + 2).to_lp_file_format(), "a + b + 2");

    assert_eq!((a + (b - 2)).to_lp_file_format(), "a + b - 2");
    assert_eq!(((a + b) - 2).to_lp_file_format(), "a + b - 2");

    assert_eq!((a - (b + 2)).to_lp_file_format(), "a - b - 2");
    assert_eq!(((a - b) + 2).to_lp_file_format(), "a - b + 2");

    assert_eq!((a - (b - 2)).to_lp_file_format(), "a - b + 2");
    assert_eq!(((a - b) - 2).to_lp_file_format(), "a - b - 2");

    assert_eq!((a - (b - 2) + c).to_lp_file_format(), "a - b + c + 2");
    assert_eq!(((a - b) - 2 + c).to_lp_file_format(), "a - b + c - 2");

    let ref x = LpBinary::new("x");
    let ref y = LpBinary::new("y");
    assert_eq!((x + (y + 1)).to_lp_file_format(), "x + y + 1");
    assert_eq!(((x + y) + 1).to_lp_file_format(), "x + y + 1");
}

#[test]
fn literal_first_with_accumulation() {
    let ref a = LpInteger::new("a");
    let ref b = LpInteger::new("b");
    let ref c = LpInteger::new("c");

    assert_eq!(
        (a + 1 + b + 2 + c + 3 + a + 4).to_lp_file_format(),
        "a + b + c + a + 10"
    );
    assert_eq!(
        (a - 1 + b - 2 - c + 3 + a - 4).to_lp_file_format(),
        "a + b - c + a - 4"
    );
    assert_eq!(
        (a + b + 1 - c - a - 3).to_lp_file_format(),
        "a + b - c - a - 2"
    );
    assert_eq!(
        (a + b + (c - 1) * 2 - a - 3).to_lp_file_format(),
        "a + b + 2 c - a - 5"
    );
    assert_eq!(
        (a + b + (1 - c) * 2 - a - 3).to_lp_file_format(),
        "a + b - 2 c - a - 1"
    );
    assert_eq!((2 * (a + 5)).to_lp_file_format(), "2 a + 10");
    assert_eq!(
        ((2 + b) * (a + 5)).to_lp_file_format(),
        "2 a + a b + 5 b + 10"
    );
    assert_eq!((2 + (a + b) + 3).to_lp_file_format(), "a + b + 5");
}

#[test]
fn trivial_rules() {
    let ref a = LpInteger::new("a");
    let ref b = LpInteger::new("b");

    assert_eq!(((a + b) * 0).to_lp_file_format(), "0");
    assert_eq!((0 * (a + b)).to_lp_file_format(), "0");
    assert_eq!((0 * a * b * 3).to_lp_file_format(), "0");
    assert_eq!(((a + b) + 0).to_lp_file_format(), "a + b");
    assert_eq!((0 + (a + b) + 0).to_lp_file_format(), "a + b");
    assert_eq!((0 + (a + b)).to_lp_file_format(), "a + b");
    assert_eq!(((a + b) - 0).to_lp_file_format(), "a + b");
    assert_eq!((0 - (a + b)).to_lp_file_format(), "-a - b");
    assert_eq!((0 + (a + b)).to_lp_file_format(), "a + b");
}

#[test]
fn expressions_to_lp_file_format() {
    let ref a = LpInteger::new("a");
    let ref b = LpInteger::new("b");
    let ref c = LpInteger::new("c");

    // Expressions
    assert_eq!((a + 2 * b + c).to_lp_file_format(), "a + 2 b + c");
    assert_eq!((a + b * 2 + c).to_lp_file_format(), "a + 2 b + c");
    assert_eq!((a + b * 2 + 3 * 2 * c).to_lp_file_format(), "a + 2 b + 6 c");
    assert_eq!((a + 2).to_lp_file_format(), "a + 2");
    assert_eq!(
        (2 * a + 2 * b - 4 * c).to_lp_file_format(),
        "2 a + 2 b - 4 c"
    );
    assert_eq!((-2 * a).to_lp_file_format(), "-2 a");

    // Constraints
    assert_eq!((a + b).equal(10).to_lp_file_format(), "a + b = 10");
    assert_eq!((2 * a + b).ge(10).to_lp_file_format(), "2 a + b >= 10");
    assert_eq!(
        (2 * a + b + 20).ge(c).to_lp_file_format(),
        "2 a + b - c >= -20"
    );
    assert_eq!((-a).ge(10).to_lp_file_format(), "-a >= 10");
    assert_eq!(
        (2 * a - 20 + b).ge(-c).to_lp_file_format(),
        "2 a + b + c >= 20"
    );
    assert_eq!((a + b + 10).ge(0).to_lp_file_format(), "a + b >= -10");
    assert_eq!(
        (3 * (a + b + 10)).le(0).to_lp_file_format(),
        "3 a + 3 b <= -30"
    );
    assert_eq!(
        (3 * (a + b + 10)).le(a + b).to_lp_file_format(),
        "3 a + 3 b - a - b <= -30"
    );
}

#[test]
fn expression_with_lp_sum() {
    let ref a = LpBinary::new("a");
    let ref b = LpBinary::new("b");
    let ref c = LpBinary::new("c");
    let ref d = LpBinary::new("d");

    let ref expr1 = vec!(a,b,c);
    let ref expr2 = vec!(a,b,c,d);
    let ref expr3 = vec!(a);
    let ref empty: Vec<&LpBinary> = vec!();
    assert_eq!(
        lp_sum(expr1).equal(10.0).to_lp_file_format(),
        "a + b + c = 10"
    );
    assert_eq!(
        lp_sum(expr2).equal(10.0).to_lp_file_format(),
        "a + b + c + d = 10"
    );
    assert_eq!(
        lp_sum(expr3).le(5.5).to_lp_file_format(),
        "a <= 5.5"
    );
    assert!(
        std::panic::catch_unwind( || lp_sum(empty)).is_err(),
        "should panic if empty vec"
    );
}

#[test]
fn simplifications() {
    let a = &LpInteger::new("a");

    let expr1 = a - 2f32;
    let expr2 = 1f32 - a;

    let (c, _) = split_constant_and_expr(&simplify(&(&expr1 + &expr2)));
    assert_eq!(c, -1f32);

    let (c, _) = split_constant_and_expr(&simplify(&(&expr2 + &expr1)));
    assert_eq!(c, -1f32);
}
<|endoftext|>


<commit_before>#![allow(clippy::zero_sized_map_values)]

use indoc::indoc;
use serde::de::{Deserialize, SeqAccess, Visitor};
use serde_derive::{Deserialize, Serialize};
use serde_yaml::Deserializer;
use std::collections::BTreeMap;
use std::fmt::{self, Debug};

fn test_error<'de, T>(yaml: &'de str, expected: &str)
where
    T: Deserialize<'de> + Debug,
{
    let result = serde_yaml::from_str::<T>(yaml);
    assert_eq!(expected, result.unwrap_err().to_string());
}

#[test]
fn test_incorrect_type() {
    let yaml = indoc! {"
        ---
        str
    "};
    let expected = "invalid type: string \"str\", expected i16 at line 2 column 1";
    test_error::<i16>(yaml, expected);
}

#[test]
fn test_incorrect_nested_type() {
    #[derive(Deserialize, Debug)]
    struct A {
        #[allow(dead_code)]
        b: Vec<B>,
    }
    #[derive(Deserialize, Debug)]
    enum B {
        C(C),
    }
    #[derive(Deserialize, Debug)]
    struct C {
        #[allow(dead_code)]
        d: bool,
    }
    let yaml = indoc! {"
        b:
          - !C
            d: fase
    "};
    let expected = "b[0].d: invalid type: string \"fase\", expected a boolean at line 3 column 8";
    test_error::<A>(yaml, expected);
}

#[test]
fn test_empty() {
    let expected = "EOF while parsing a value";
    test_error::<String>("", expected);
}

#[test]
fn test_missing_field() {
    #[derive(Deserialize, Debug)]
    struct Basic {
        #[allow(dead_code)]
        v: bool,
        #[allow(dead_code)]
        w: bool,
    }
    let yaml = indoc! {"
        ---
        v: true
    "};
    let expected = "missing field `w` at line 2 column 1";
    test_error::<Basic>(yaml, expected);
}

#[test]
fn test_unknown_anchor() {
    let yaml = indoc! {"
        ---
        *some
    "};
    let expected = "unknown anchor at line 2 column 1";
    test_error::<String>(yaml, expected);
}

#[test]
fn test_ignored_unknown_anchor() {
    #[derive(Deserialize, Debug)]
    struct Wrapper {
        #[allow(dead_code)]
        c: (),
    }
    let yaml = indoc! {"
        b: [*a]
        c: ~
    "};
    let expected = "unknown anchor at line 1 column 5";
    test_error::<Wrapper>(yaml, expected);
}

#[test]
fn test_bytes() {
    let expected = "serialization and deserialization of bytes in YAML is not implemented";
    test_error::<&[u8]>("...", expected);
}

#[test]
fn test_two_documents() {
    let yaml = indoc! {"
        ---
        0
        ---
        1
    "};
    let expected = "deserializing from YAML containing more than one document is not supported";
    test_error::<usize>(yaml, expected);
}

#[test]
fn test_second_document_syntax_error() {
    let yaml = indoc! {"
        ---
        0
        ---
        ]
    "};

    let mut de = Deserializer::from_str(yaml);
    let first_doc = de.next().unwrap();
    let result = <usize as serde::Deserialize>::deserialize(first_doc);
    assert_eq!(0, result.unwrap());

    let second_doc = de.next().unwrap();
    let result = <usize as serde::Deserialize>::deserialize(second_doc);
    let expected = "did not find expected node content at line 4 column 1, while parsing a block node";
    assert_eq!(expected, result.unwrap_err().to_string());
}

#[test]
fn test_missing_enum_tag() {
    #[derive(Deserialize, Debug)]
    enum E {
        V(usize),
    }
    let yaml = indoc! {r#"
        "V": 16
        "other": 32
    "#};
    let expected = "invalid type: map, expected a YAML tag starting with '!' at position 0";
    test_error::<E>(yaml, expected);
}

#[test]
fn test_serialize_nested_enum() {
    #[derive(Serialize, Debug)]
    enum Outer {
        Inner(Inner),
    }
    #[derive(Serialize, Debug)]
    enum Inner {
        Newtype(usize),
        Tuple(usize, usize),
        Struct { x: usize },
    }

    let expected = "serializing nested enums in YAML is not supported yet";

    let e = Outer::Inner(Inner::Newtype(0));
    let error = serde_yaml::to_string(&e).unwrap_err();
    assert_eq!(error.to_string(), expected);

    let e = Outer::Inner(Inner::Tuple(0, 0));
    let error = serde_yaml::to_string(&e).unwrap_err();
    assert_eq!(error.to_string(), expected);

    let e = Outer::Inner(Inner::Struct { x: 0 });
    let error = serde_yaml::to_string(&e).unwrap_err();
    assert_eq!(error.to_string(), expected);
}

#[test]
fn test_deserialize_nested_enum() {
    #[derive(Deserialize, Debug)]
    enum Outer {
        Inner(Inner),
    }
    #[derive(Deserialize, Debug)]
    enum Inner {
        Variant(Vec<usize>),
    }

    let yaml = indoc! {"
        ---
        !Inner []
    "};
    let expected = "deserializing nested enum in Outer::Inner from YAML is not supported yet at line 2 column 1";
    test_error::<Outer>(yaml, expected);

    let yaml = indoc! {"
        ---
        !Variant []
    "};
    let expected = "unknown variant `Variant`, expected `Inner`";
    test_error::<Outer>(yaml, expected);

    let yaml = indoc! {"
        ---
        !Inner !Variant []
    "};
    let expected = "deserializing nested enum in Outer::Inner from YAML is not supported yet at line 2 column 1";
    test_error::<Outer>(yaml, expected);
}

#[test]
fn test_variant_not_a_seq() {
    #[derive(Deserialize, Debug)]
    enum E {
        V(usize),
    }
    let yaml = indoc! {r#"
        ---
        !V
        value: 0
    "#};
    let expected = "invalid type: map, expected usize at line 2 column 1";
    test_error::<E>(yaml, expected);
}

#[test]
fn test_struct_from_sequence() {
    #[allow(dead_code)]
    #[derive(Deserialize, Debug)]
    struct Struct {
        x: usize,
        y: usize,
    }
    let yaml = indoc! {"
        [0, 0]
    "};
    let expected = "invalid type: sequence, expected struct Struct at position 0";
    test_error::<Struct>(yaml, expected);
}

#[test]
fn test_bad_bool() {
    let yaml = indoc! {"
        ---
        !!bool str
    "};
    let expected = "invalid value: string \"str\", expected a boolean at line 2 column 1";
    test_error::<bool>(yaml, expected);
}

#[test]
fn test_bad_int() {
    let yaml = indoc! {"
        ---
        !!int str
    "};
    let expected = "invalid value: string \"str\", expected an integer at line 2 column 1";
    test_error::<i64>(yaml, expected);
}

#[test]
fn test_bad_float() {
    let yaml = indoc! {"
        ---
        !!float str
    "};
    let expected = "invalid value: string \"str\", expected a float at line 2 column 1";
    test_error::<f64>(yaml, expected);
}

#[test]
fn test_bad_null() {
    let yaml = indoc! {"
        ---
        !!null str
    "};
    let expected = "invalid value: string \"str\", expected null at line 2 column 1";
    test_error::<()>(yaml, expected);
}

#[test]
fn test_short_tuple() {
    let yaml = indoc! {"
        ---
        [0, 0]
    "};
    let expected = "invalid length 2, expected a tuple of size 3 at line 2 column 1";
    test_error::<(u8, u8, u8)>(yaml, expected);
}

#[test]
fn test_long_tuple() {
    let yaml = indoc! {"
        ---
        [0, 0, 0]
    "};
    let expected = "invalid length 3, expected sequence of 2 elements at line 2 column 1";
    test_error::<(u8, u8)>(yaml, expected);
}

#[test]
fn test_invalid_scalar_type() {
    #[derive(Deserialize, Debug)]
    struct S {
        #[allow(dead_code)]
        x: [(); 1],
    }

    let yaml = "x:\n";
    let expected = "x: invalid type: unit value, expected an array of length 1 at line 1 column 3";
    test_error::<S>(yaml, expected);
}

#[cfg(not(miri))]
#[test]
fn test_infinite_recursion_objects() {
    #[derive(Deserialize, Debug)]
    struct S {
        #[allow(dead_code)]
        x: Option<Box<S>>,
    }

    let yaml = "&a {'x': *a}";
    let expected = "recursion limit exceeded at position 0";
    test_error::<S>(yaml, expected);
}

#[cfg(not(miri))]
#[test]
fn test_infinite_recursion_arrays() {
    #[derive(Deserialize, Debug)]
    struct S(usize, Option<Box<S>>);

    let yaml = "&a [0, *a]";
    let expected = "recursion limit exceeded at position 0";
    test_error::<S>(yaml, expected);
}

#[cfg(not(miri))]
#[test]
fn test_infinite_recursion_newtype() {
    #[derive(Deserialize, Debug)]
    struct S(Option<Box<S>>);

    let yaml = "&a [*a]";
    let expected = "recursion limit exceeded at position 0";
    test_error::<S>(yaml, expected);
}

#[cfg(not(miri))]
#[test]
fn test_finite_recursion_objects() {
    #[derive(Deserialize, Debug)]
    struct S {
        #[allow(dead_code)]
        x: Option<Box<S>>,
    }

    let yaml = "{'x':".repeat(1_000) + &"}".repeat(1_000);
    let expected = "recursion limit exceeded at line 1 column 641";
    test_error::<S>(&yaml, expected);
}

#[cfg(not(miri))]
#[test]
fn test_finite_recursion_arrays() {
    #[derive(Deserialize, Debug)]
    struct S(usize, Option<Box<S>>);

    let yaml = "[0, ".repeat(1_000) + &"]".repeat(1_000);
    let expected = "recursion limit exceeded at line 1 column 513";
    test_error::<S>(&yaml, expected);
}

#[cfg(not(miri))]
#[test]
fn test_billion_laughs() {
    #[derive(Debug)]
    struct X;

    impl<'de> Deserialize<'de> for X {
        fn deserialize<D>(deserializer: D) -> Result<X, D::Error>
        where
            D: serde::Deserializer<'de>,
        {
            impl<'de> Visitor<'de> for X {
                type Value = X;

                fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
                    formatter.write_str("exponential blowup")
                }

                fn visit_unit<E>(self) -> Result<X, E> {
                    Ok(X)
                }

                fn visit_seq<S>(self, mut seq: S) -> Result<X, S::Error>
                where
                    S: SeqAccess<'de>,
                {
                    while let Some(X) = seq.next_element()? {}
                    Ok(X)
                }
            }

            deserializer.deserialize_any(X)
        }
    }

    let yaml = indoc! {"
        a: &a ~
        b: &b [*a,*a,*a,*a,*a,*a,*a,*a,*a]
        c: &c [*b,*b,*b,*b,*b,*b,*b,*b,*b]
        d: &d [*c,*c,*c,*c,*c,*c,*c,*c,*c]
        e: &e [*d,*d,*d,*d,*d,*d,*d,*d,*d]
        f: &f [*e,*e,*e,*e,*e,*e,*e,*e,*e]
        g: &g [*f,*f,*f,*f,*f,*f,*f,*f,*f]
        h: &h [*g,*g,*g,*g,*g,*g,*g,*g,*g]
        i: &i [*h,*h,*h,*h,*h,*h,*h,*h,*h]
    "};
    let expected = "repetition limit exceeded";
    test_error::<BTreeMap<String, X>>(yaml, expected);
}
<commit_msg>Add test of scan error<commit_after>#![allow(clippy::zero_sized_map_values)]

use indoc::indoc;
use serde::de::{Deserialize, SeqAccess, Visitor};
use serde_derive::{Deserialize, Serialize};
use serde_yaml::{Deserializer, Value};
use std::collections::BTreeMap;
use std::fmt::{self, Debug};

fn test_error<'de, T>(yaml: &'de str, expected: &str)
where
    T: Deserialize<'de> + Debug,
{
    let result = serde_yaml::from_str::<T>(yaml);
    assert_eq!(expected, result.unwrap_err().to_string());
}

#[test]
fn test_scan_error() {
    let yaml = ">\n@";
    let expected = "deserializing from YAML containing more than one document is not supported";
    test_error::<Value>(yaml, expected);
}

#[test]
fn test_incorrect_type() {
    let yaml = indoc! {"
        ---
        str
    "};
    let expected = "invalid type: string \"str\", expected i16 at line 2 column 1";
    test_error::<i16>(yaml, expected);
}

#[test]
fn test_incorrect_nested_type() {
    #[derive(Deserialize, Debug)]
    struct A {
        #[allow(dead_code)]
        b: Vec<B>,
    }
    #[derive(Deserialize, Debug)]
    enum B {
        C(C),
    }
    #[derive(Deserialize, Debug)]
    struct C {
        #[allow(dead_code)]
        d: bool,
    }
    let yaml = indoc! {"
        b:
          - !C
            d: fase
    "};
    let expected = "b[0].d: invalid type: string \"fase\", expected a boolean at line 3 column 8";
    test_error::<A>(yaml, expected);
}

#[test]
fn test_empty() {
    let expected = "EOF while parsing a value";
    test_error::<String>("", expected);
}

#[test]
fn test_missing_field() {
    #[derive(Deserialize, Debug)]
    struct Basic {
        #[allow(dead_code)]
        v: bool,
        #[allow(dead_code)]
        w: bool,
    }
    let yaml = indoc! {"
        ---
        v: true
    "};
    let expected = "missing field `w` at line 2 column 1";
    test_error::<Basic>(yaml, expected);
}

#[test]
fn test_unknown_anchor() {
    let yaml = indoc! {"
        ---
        *some
    "};
    let expected = "unknown anchor at line 2 column 1";
    test_error::<String>(yaml, expected);
}

#[test]
fn test_ignored_unknown_anchor() {
    #[derive(Deserialize, Debug)]
    struct Wrapper {
        #[allow(dead_code)]
        c: (),
    }
    let yaml = indoc! {"
        b: [*a]
        c: ~
    "};
    let expected = "unknown anchor at line 1 column 5";
    test_error::<Wrapper>(yaml, expected);
}

#[test]
fn test_bytes() {
    let expected = "serialization and deserialization of bytes in YAML is not implemented";
    test_error::<&[u8]>("...", expected);
}

#[test]
fn test_two_documents() {
    let yaml = indoc! {"
        ---
        0
        ---
        1
    "};
    let expected = "deserializing from YAML containing more than one document is not supported";
    test_error::<usize>(yaml, expected);
}

#[test]
fn test_second_document_syntax_error() {
    let yaml = indoc! {"
        ---
        0
        ---
        ]
    "};

    let mut de = Deserializer::from_str(yaml);
    let first_doc = de.next().unwrap();
    let result = <usize as serde::Deserialize>::deserialize(first_doc);
    assert_eq!(0, result.unwrap());

    let second_doc = de.next().unwrap();
    let result = <usize as serde::Deserialize>::deserialize(second_doc);
    let expected = "did not find expected node content at line 4 column 1, while parsing a block node";
    assert_eq!(expected, result.unwrap_err().to_string());
}

#[test]
fn test_missing_enum_tag() {
    #[derive(Deserialize, Debug)]
    enum E {
        V(usize),
    }
    let yaml = indoc! {r#"
        "V": 16
        "other": 32
    "#};
    let expected = "invalid type: map, expected a YAML tag starting with '!' at position 0";
    test_error::<E>(yaml, expected);
}

#[test]
fn test_serialize_nested_enum() {
    #[derive(Serialize, Debug)]
    enum Outer {
        Inner(Inner),
    }
    #[derive(Serialize, Debug)]
    enum Inner {
        Newtype(usize),
        Tuple(usize, usize),
        Struct { x: usize },
    }

    let expected = "serializing nested enums in YAML is not supported yet";

    let e = Outer::Inner(Inner::Newtype(0));
    let error = serde_yaml::to_string(&e).unwrap_err();
    assert_eq!(error.to_string(), expected);

    let e = Outer::Inner(Inner::Tuple(0, 0));
    let error = serde_yaml::to_string(&e).unwrap_err();
    assert_eq!(error.to_string(), expected);

    let e = Outer::Inner(Inner::Struct { x: 0 });
    let error = serde_yaml::to_string(&e).unwrap_err();
    assert_eq!(error.to_string(), expected);
}

#[test]
fn test_deserialize_nested_enum() {
    #[derive(Deserialize, Debug)]
    enum Outer {
        Inner(Inner),
    }
    #[derive(Deserialize, Debug)]
    enum Inner {
        Variant(Vec<usize>),
    }

    let yaml = indoc! {"
        ---
        !Inner []
    "};
    let expected = "deserializing nested enum in Outer::Inner from YAML is not supported yet at line 2 column 1";
    test_error::<Outer>(yaml, expected);

    let yaml = indoc! {"
        ---
        !Variant []
    "};
    let expected = "unknown variant `Variant`, expected `Inner`";
    test_error::<Outer>(yaml, expected);

    let yaml = indoc! {"
        ---
        !Inner !Variant []
    "};
    let expected = "deserializing nested enum in Outer::Inner from YAML is not supported yet at line 2 column 1";
    test_error::<Outer>(yaml, expected);
}

#[test]
fn test_variant_not_a_seq() {
    #[derive(Deserialize, Debug)]
    enum E {
        V(usize),
    }
    let yaml = indoc! {r#"
        ---
        !V
        value: 0
    "#};
    let expected = "invalid type: map, expected usize at line 2 column 1";
    test_error::<E>(yaml, expected);
}

#[test]
fn test_struct_from_sequence() {
    #[allow(dead_code)]
    #[derive(Deserialize, Debug)]
    struct Struct {
        x: usize,
        y: usize,
    }
    let yaml = indoc! {"
        [0, 0]
    "};
    let expected = "invalid type: sequence, expected struct Struct at position 0";
    test_error::<Struct>(yaml, expected);
}

#[test]
fn test_bad_bool() {
    let yaml = indoc! {"
        ---
        !!bool str
    "};
    let expected = "invalid value: string \"str\", expected a boolean at line 2 column 1";
    test_error::<bool>(yaml, expected);
}

#[test]
fn test_bad_int() {
    let yaml = indoc! {"
        ---
        !!int str
    "};
    let expected = "invalid value: string \"str\", expected an integer at line 2 column 1";
    test_error::<i64>(yaml, expected);
}

#[test]
fn test_bad_float() {
    let yaml = indoc! {"
        ---
        !!float str
    "};
    let expected = "invalid value: string \"str\", expected a float at line 2 column 1";
    test_error::<f64>(yaml, expected);
}

#[test]
fn test_bad_null() {
    let yaml = indoc! {"
        ---
        !!null str
    "};
    let expected = "invalid value: string \"str\", expected null at line 2 column 1";
    test_error::<()>(yaml, expected);
}

#[test]
fn test_short_tuple() {
    let yaml = indoc! {"
        ---
        [0, 0]
    "};
    let expected = "invalid length 2, expected a tuple of size 3 at line 2 column 1";
    test_error::<(u8, u8, u8)>(yaml, expected);
}

#[test]
fn test_long_tuple() {
    let yaml = indoc! {"
        ---
        [0, 0, 0]
    "};
    let expected = "invalid length 3, expected sequence of 2 elements at line 2 column 1";
    test_error::<(u8, u8)>(yaml, expected);
}

#[test]
fn test_invalid_scalar_type() {
    #[derive(Deserialize, Debug)]
    struct S {
        #[allow(dead_code)]
        x: [(); 1],
    }

    let yaml = "x:\n";
    let expected = "x: invalid type: unit value, expected an array of length 1 at line 1 column 3";
    test_error::<S>(yaml, expected);
}

#[cfg(not(miri))]
#[test]
fn test_infinite_recursion_objects() {
    #[derive(Deserialize, Debug)]
    struct S {
        #[allow(dead_code)]
        x: Option<Box<S>>,
    }

    let yaml = "&a {'x': *a}";
    let expected = "recursion limit exceeded at position 0";
    test_error::<S>(yaml, expected);
}

#[cfg(not(miri))]
#[test]
fn test_infinite_recursion_arrays() {
    #[derive(Deserialize, Debug)]
    struct S(usize, Option<Box<S>>);

    let yaml = "&a [0, *a]";
    let expected = "recursion limit exceeded at position 0";
    test_error::<S>(yaml, expected);
}

#[cfg(not(miri))]
#[test]
fn test_infinite_recursion_newtype() {
    #[derive(Deserialize, Debug)]
    struct S(Option<Box<S>>);

    let yaml = "&a [*a]";
    let expected = "recursion limit exceeded at position 0";
    test_error::<S>(yaml, expected);
}

#[cfg(not(miri))]
#[test]
fn test_finite_recursion_objects() {
    #[derive(Deserialize, Debug)]
    struct S {
        #[allow(dead_code)]
        x: Option<Box<S>>,
    }

    let yaml = "{'x':".repeat(1_000) + &"}".repeat(1_000);
    let expected = "recursion limit exceeded at line 1 column 641";
    test_error::<S>(&yaml, expected);
}

#[cfg(not(miri))]
#[test]
fn test_finite_recursion_arrays() {
    #[derive(Deserialize, Debug)]
    struct S(usize, Option<Box<S>>);

    let yaml = "[0, ".repeat(1_000) + &"]".repeat(1_000);
    let expected = "recursion limit exceeded at line 1 column 513";
    test_error::<S>(&yaml, expected);
}

#[cfg(not(miri))]
#[test]
fn test_billion_laughs() {
    #[derive(Debug)]
    struct X;

    impl<'de> Deserialize<'de> for X {
        fn deserialize<D>(deserializer: D) -> Result<X, D::Error>
        where
            D: serde::Deserializer<'de>,
        {
            impl<'de> Visitor<'de> for X {
                type Value = X;

                fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
                    formatter.write_str("exponential blowup")
                }

                fn visit_unit<E>(self) -> Result<X, E> {
                    Ok(X)
                }

                fn visit_seq<S>(self, mut seq: S) -> Result<X, S::Error>
                where
                    S: SeqAccess<'de>,
                {
                    while let Some(X) = seq.next_element()? {}
                    Ok(X)
                }
            }

            deserializer.deserialize_any(X)
        }
    }

    let yaml = indoc! {"
        a: &a ~
        b: &b [*a,*a,*a,*a,*a,*a,*a,*a,*a]
        c: &c [*b,*b,*b,*b,*b,*b,*b,*b,*b]
        d: &d [*c,*c,*c,*c,*c,*c,*c,*c,*c]
        e: &e [*d,*d,*d,*d,*d,*d,*d,*d,*d]
        f: &f [*e,*e,*e,*e,*e,*e,*e,*e,*e]
        g: &g [*f,*f,*f,*f,*f,*f,*f,*f,*f]
        h: &h [*g,*g,*g,*g,*g,*g,*g,*g,*g]
        i: &i [*h,*h,*h,*h,*h,*h,*h,*h,*h]
    "};
    let expected = "repetition limit exceeded";
    test_error::<BTreeMap<String, X>>(yaml, expected);
}
<|endoftext|>


<commit_before>/// Sends a message to an object. The first argument should implement the
/// `ToMessage` trait, and the syntax is similar to the message syntax in
/// Objective-C.
///
/// Variadic arguments are not currently supported. This macro should only be
/// used in cases where `objc_msgSend` would be used, as opposed to
/// `objc_msgSend_stret` or `objc_msgSend_fpret`.
/// For more information, see Apple's documenation:
/// https://developer.apple.com/library/mac/documentation/Cocoa/Reference/ObjCRuntimeRef/index.html#//apple_ref/doc/uid/TP40001418-CH1g-88778
///
/// # Example
/// ```
/// let description = msg_send![obj, description];
/// msg_send![obj, setArg1:1u arg2:2u];
/// ```
#[macro_export]
macro_rules! msg_send {
    ($obj:expr, $name:ident) => ({
        let sel_name = stringify!($name);
        let sel = $crate::runtime::Sel::register(sel_name);
        let ptr = $crate::to_obj_ptr(&$obj);
        $crate::runtime::objc_msgSend(ptr, sel)
    });
    ($obj:expr, $($name:ident : $arg:expr)+) => ({
        let sel_name = concat!($(stringify!($name), ':'),+);
        let sel = $crate::runtime::Sel::register(sel_name);
        let ptr = $crate::to_obj_ptr(&$obj);
        $crate::runtime::objc_msgSend(ptr, sel $(,$arg)+)
    });
}

/// Implements the `Encode` trait for a `Message` type.
/// Specifically, this will implement `Encode` for reference, pointers, and
/// `Option` references of the given type.
///
/// The first argument should be a static string that is the type encoding
/// to use in the implementation. The second argument is the ident of the name
/// of the type to implement `Encode` for, and any further arguments are
/// used as type parameters for the type.
///
/// # Example
/// ```
/// impl Message for Object { }
/// encode_message_impl!("@", Object)
///
/// impl<T> Message for Array<T> { }
/// encode_message_impl!("@", Array, T)
/// ```
#[macro_export]
macro_rules! encode_message_impl {
    ($code:expr, $name:ident) => (
        encode_message_impl!($code, $name,);
    );
    ($code:expr, $name:ident, $($t:ident),*) => (
        impl<'a $(, $t)*> $crate::Encode for &'a $name<$($t),*> {
            fn code() -> $crate::Encoding<&'a $name<$($t),*>> {
                $crate::Encoding($code)
            }
        }

        impl<'a $(, $t)*> $crate::Encode for &'a mut $name<$($t),*> {
            fn code() -> $crate::Encoding<&'a mut $name<$($t),*>> {
                $crate::Encoding($code)
            }
        }

        impl<'a $(, $t)*> $crate::Encode for Option<&'a $name<$($t),*>> {
            fn code() -> $crate::Encoding<Option<&'a $name<$($t),*>>> {
                $crate::Encoding($code)
            }
        }

        impl<'a $(, $t)*> $crate::Encode for Option<&'a mut $name<$($t),*>> {
            fn code() -> $crate::Encoding<Option<&'a mut $name<$($t),*>>> {
                $crate::Encoding($code)
            }
        }

        impl<$($t),*> $crate::Encode for *const $name<$($t),*> {
            fn code() -> $crate::Encoding<*const $name<$($t),*>> {
                $crate::Encoding($code)
            }
        }

        impl<$($t),*> $crate::Encode for *mut $name<$($t),*> {
            fn code() -> $crate::Encoding<*mut $name<$($t),*>> {
                $crate::Encoding($code)
            }
        }
    );
}

/*
/// Declares a method, returning a `MethodDecl`.
/// The syntax is a combination of Objective-C's syntax and Rust's:
///
/// * The first part is the type and name of the self variable for the method
/// followed by a comma, like: `(&MyObject)this,`.
/// * Then, the parts of the selector and arguments follow, separated by commas,
/// like `setArg1:(uint)arg1, arg2:(uint)arg2`.
/// * After this, if the method has a return type, it should be followed by an
/// arrow ("->"), otherwise it should be terminated by a semicolon.
/// * Then a block declares the implementation of the method using the provided
/// arguments.
///
/// # Example
/// ```
/// method!(
///     (&mut MYObject)this, setNumber:(uint)number; {
///         this.set_number(number);
///     }
/// )
///
/// method!(
///     (&MYObject)this, number -> uint {
///         this.number()
///     }
/// )
/// ```
#[macro_export]
macro_rules! method {
    // Void no arguments
    (
        ($self_ty:ty)$self_name:ident
        , $name:ident;
        $body:block
    ) => ({
        method!(, stringify!($name), $body, $name, (), $self_name: $self_ty,)
    });
    // No arguments
    (
        ($self_ty:ty)$self_name:ident
        , $name:ident
        -> $ret_ty:ty $body:block
    ) => ({
        method!(, stringify!($name), $body, $name, $ret_ty, $self_name: $self_ty,)
    });
    // Void with arguments
    (
        ($self_ty:ty)$self_name:ident
        , $name:ident : ($first_arg_ty:ty) $first_arg_name:ident
        $(, $next_name:ident : ($next_arg_ty:ty) $next_arg_name:ident)*;
        $body:block
    ) => ({
        let sel_name = concat!(stringify!($name), ':', $(stringify!($next_name), ':'),*);
        method!(, sel_name, $body, $name, (), $self_name: $self_ty,
            $first_arg_name: $first_arg_ty$(, $next_arg_name: $next_arg_ty)*)
    });
    // Arguments
    (
        ($self_ty:ty)$self_name:ident
        , $name:ident : ($first_arg_ty:ty) $first_arg_name:ident
        $(, $next_name:ident : ($next_arg_ty:ty) $next_arg_name:ident)*
        -> $ret_ty:ty $body:block
    ) => ({
        let sel_name = concat!(stringify!($name), ':', $(stringify!($next_name), ':'),*);
        method!(, sel_name, $body, $name, $ret_ty, $self_name: $self_ty,
            $first_arg_name: $first_arg_ty$(, $next_arg_name: $next_arg_ty)*)
    });
    // Preceding comma is necessary to disambiguate
    (, $sel_name:expr, $body:block, $fn_name:ident, $ret_ty:ty, $self_name:ident : $self_ty:ty, $($arg_name:ident : $arg_ty:ty),*) => ({
        let sel = $crate::runtime::Sel::register($sel_name);

        #[allow(non_snake_case)]
        extern fn $fn_name($self_name: $self_ty, _cmd: $crate::runtime::Sel $(, $arg_name: $arg_ty)*) -> $ret_ty $body
        let imp: $crate::runtime::Imp = unsafe { ::std::mem::transmute($fn_name) };

        let mut types = $crate::encode::<$ret_ty>().to_string();
        types.push_str($crate::encode::<$self_ty>());
        types.push_str($crate::encode::<$crate::runtime::Sel>());
        $(types.push_str($crate::encode::<$arg_ty>());)*

        $crate::MethodDecl { sel: sel, imp: imp, types: types }
    });
}
*/
<commit_msg>Brought back the method! macro with some tweaks.<commit_after>/// Sends a message to an object. The first argument should implement the
/// `ToMessage` trait, and the syntax is similar to the message syntax in
/// Objective-C.
///
/// Variadic arguments are not currently supported. This macro should only be
/// used in cases where `objc_msgSend` would be used, as opposed to
/// `objc_msgSend_stret` or `objc_msgSend_fpret`.
/// For more information, see Apple's documenation:
/// https://developer.apple.com/library/mac/documentation/Cocoa/Reference/ObjCRuntimeRef/index.html#//apple_ref/doc/uid/TP40001418-CH1g-88778
///
/// # Example
/// ```
/// let description = msg_send![obj, description];
/// msg_send![obj, setArg1:1u arg2:2u];
/// ```
#[macro_export]
macro_rules! msg_send {
    ($obj:expr, $name:ident) => ({
        let sel_name = stringify!($name);
        let sel = $crate::runtime::Sel::register(sel_name);
        let ptr = $crate::to_obj_ptr(&$obj);
        $crate::runtime::objc_msgSend(ptr, sel)
    });
    ($obj:expr, $($name:ident : $arg:expr)+) => ({
        let sel_name = concat!($(stringify!($name), ':'),+);
        let sel = $crate::runtime::Sel::register(sel_name);
        let ptr = $crate::to_obj_ptr(&$obj);
        $crate::runtime::objc_msgSend(ptr, sel $(,$arg)+)
    });
}

/// Implements the `Encode` trait for a `Message` type.
/// Specifically, this will implement `Encode` for reference, pointers, and
/// `Option` references of the given type.
///
/// The first argument should be a static string that is the type encoding
/// to use in the implementation. The second argument is the ident of the name
/// of the type to implement `Encode` for, and any further arguments are
/// used as type parameters for the type.
///
/// # Example
/// ```
/// impl Message for Object { }
/// encode_message_impl!("@", Object)
///
/// impl<T> Message for Array<T> { }
/// encode_message_impl!("@", Array, T)
/// ```
#[macro_export]
macro_rules! encode_message_impl {
    ($code:expr, $name:ident) => (
        encode_message_impl!($code, $name,);
    );
    ($code:expr, $name:ident, $($t:ident),*) => (
        impl<'a $(, $t)*> $crate::Encode for &'a $name<$($t),*> {
            fn code() -> $crate::Encoding<&'a $name<$($t),*>> {
                $crate::Encoding($code)
            }
        }

        impl<'a $(, $t)*> $crate::Encode for &'a mut $name<$($t),*> {
            fn code() -> $crate::Encoding<&'a mut $name<$($t),*>> {
                $crate::Encoding($code)
            }
        }

        impl<'a $(, $t)*> $crate::Encode for Option<&'a $name<$($t),*>> {
            fn code() -> $crate::Encoding<Option<&'a $name<$($t),*>>> {
                $crate::Encoding($code)
            }
        }

        impl<'a $(, $t)*> $crate::Encode for Option<&'a mut $name<$($t),*>> {
            fn code() -> $crate::Encoding<Option<&'a mut $name<$($t),*>>> {
                $crate::Encoding($code)
            }
        }

        impl<$($t),*> $crate::Encode for *const $name<$($t),*> {
            fn code() -> $crate::Encoding<*const $name<$($t),*>> {
                $crate::Encoding($code)
            }
        }

        impl<$($t),*> $crate::Encode for *mut $name<$($t),*> {
            fn code() -> $crate::Encoding<*mut $name<$($t),*>> {
                $crate::Encoding($code)
            }
        }
    );
}

/// Declares a method, returning a `MethodDecl`.
/// The syntax is a combination of Objective-C's syntax and Rust's:
///
/// * The first part is the type and name of the self variable for the method
/// followed by a comma, like: `(&MyObject)this,`.
/// * Then, the parts of the selector and arguments follow, separated by commas,
/// like `setArg1:(uint)arg1, arg2:(uint)arg2`.
/// * After this, if the method has a return type, it should be followed by an
/// arrow ("->"), otherwise it should be terminated by a semicolon.
/// * Then a block declares the implementation of the method using the provided
/// arguments.
///
/// # Example
/// ```
/// method!(
///     (&mut MYObject)this, setNumber:(uint)number; {
///         this.set_number(number);
///     }
/// )
///
/// method!(
///     (&MYObject)this, number -> uint, {
///         this.number()
///     }
/// )
/// ```
#[macro_export]
macro_rules! method {
    // Void no arguments
    (
        ($self_ty:ty)$self_name:ident,
        $name:ident
        ; $body:block
    ) => ({
        method!(-$name,; stringify!($name), $body, (), $self_name: $self_ty,)
    });
    // No arguments
    (
        ($self_ty:ty)$self_name:ident,
        $name:ident
        -> $ret_ty:ty, $body:block
    ) => ({
        method!(-$name,; stringify!($name), $body, $ret_ty, $self_name: $self_ty,)
    });
    // Void with arguments
    (
        ($self_ty:ty)$self_name:ident,
        $($name:ident : ($arg_ty:ty) $arg_name:ident),+
        ; $body:block
    ) => ({
        let sel_name = concat!($(stringify!($name), ':'),*);
        method!($(-$name,)+; sel_name, $body, (), $self_name: $self_ty, $($arg_name: $arg_ty),+)
    });
    // Arguments
    (
        ($self_ty:ty)$self_name:ident,
        $($name:ident : ($arg_ty:ty) $arg_name:ident),+
        -> $ret_ty:ty, $body:block
    ) => ({
        let sel_name = concat!($(stringify!($name), ':'),*);
        method!($(-$name,)+; sel_name, $body, $ret_ty, $self_name: $self_ty, $($arg_name: $arg_ty),+)
    });
    (
        // Preceding dash is necessary to disambiguate
        -$first_name:ident, $(-$next_name:ident,)*;
        $sel_name:expr, $body:block, $ret_ty:ty,
        $self_name:ident : $self_ty:ty, $($arg_name:ident : $arg_ty:ty),*
    ) => ({
        let sel = $crate::runtime::Sel::register($sel_name);

        #[allow(non_snake_case)]
        extern fn $first_name($self_name: $self_ty, _cmd: $crate::runtime::Sel $(, $arg_name: $arg_ty)*) -> $ret_ty $body
        let imp: $crate::runtime::Imp = unsafe { ::std::mem::transmute($first_name) };

        let mut types = $crate::encode::<$ret_ty>().to_string();
        types.push_str($crate::encode::<$self_ty>());
        types.push_str($crate::encode::<$crate::runtime::Sel>());
        $(types.push_str($crate::encode::<$arg_ty>());)*

        $crate::MethodDecl { sel: sel, imp: imp, types: types }
    });
}
<|endoftext|>