<commit_before>//! Types of the Telegram API.
//!
//! This module contains definitions of the types defined
//! [here](https://core.telegram.org/bots/api/#available-types). Many Telegram
//! types, like "Location", map directly to Rust-structs. Other Telegram types,
//! like "Message", was made more rusty by using enums.
//!
//! All types implement `Decodable` and `Encodable`, so they can be serialized
//! as JSON. Non existing JSON-fields will result in `None` values for `Option`
//! types. `None` values don't result in JSON fields.
//!

use rustc_serialize::{Decodable, Encodable, Decoder, Encoder};
use std::convert::Into;
use std::fmt;

// ===========================================================================
// Helpers
// ===========================================================================
// Macro to implement "Encodable" quickly. "None" fields won't be encoded.
macro_rules! impl_encode {
    (
        $ty:ident, $count:expr,
        [$($id:expr => $field:ident),*],
        [$($o_id:expr => $o_field:ident),*]
    ) => {
        impl Encodable for $ty {
            fn encode<E: Encoder>(&self, e: &mut E) -> Result<(), E::Error> {
                e.emit_struct(stringify!($ty), $count, |e| {
                    $(
                        try!(e.emit_struct_field(stringify!($field), $id, |e| {
                            self.$field.encode(e)
                        }));
                    )*
                    $(
                        if let Some(ref v) = self.$o_field {
                            try!(e.emit_struct_field(
                                stringify!($o_field), $o_id, |e| {
                                v.encode(e)
                            }));
                        }
                    )*

                    Ok(())
                })
            }
        }
    }
}

// Decodes a field with a given name. If successful: Return decoded
// value. If not: Exit function with error value.
macro_rules! try_field {
    ($d:ident, $name:expr) => {
        try!($d.read_struct_field($name, 0, Decodable::decode))
    }
}


// ===========================================================================
// Telegram primitive types
// ===========================================================================
/// The Telegram "Integer": Currently i64.
pub type Integer = i64;
/// The Telegram "Float": Currently f32.
pub type Float = f32;


// ===========================================================================
// Types not explicitly mentioned or somehow different from Telegram types
// ===========================================================================
/// All API responses are from this type. Mostly used internal.
#[derive(RustcDecodable, Debug, PartialEq, Clone)]
pub struct Response<T: Decodable> {
    pub ok: bool,
    pub error_code: Option<Integer>,
    pub description: Option<String>,
    pub result: Option<T>,
}

// ---------------------------------------------------------------------------
/// Represents one of "ReplyKeyboardMarkup", "ReplyKeyboardHide" or
/// "ForceReply". Used for the "reply_markup" field.
#[derive(Debug, PartialEq, Clone)]
pub enum ReplyMarkup {
    Keyboard(ReplyKeyboardMarkup),
    /// The boolean corresponds to the "selective" field of "ReplyKeyboardHide"
    KeyboardHide(bool),
    /// The boolean corresponds to the "selective" field of "ForceReply"
    ForceReply(bool),
}

impl From<ReplyKeyboardMarkup> for ReplyMarkup {
    fn from(keyboard: ReplyKeyboardMarkup) -> ReplyMarkup {
        ReplyMarkup::Keyboard(keyboard)
    }
}

impl Encodable for ReplyMarkup {
    fn encode<E: Encoder>(&self, e: &mut E) -> Result<(), E::Error> {
        match *self {
            ReplyMarkup::Keyboard(ref k) => k.encode(e),
            ReplyMarkup::KeyboardHide(b) => {
                e.emit_struct("ReplyKeyboardHide", 2, |e| {
                    try!(e.emit_struct_field("hide_keyboard", 0, |e| {
                        true.encode(e)
                    }));
                    e.emit_struct_field("selective", 1, |e| b.encode(e))
                })
            },
            ReplyMarkup::ForceReply(b) => {
                e.emit_struct("ForceReply", 2, |e| {
                    try!(e.emit_struct_field("force_reply", 0, |e| {
                        true.encode(e)
                    }));
                    e.emit_struct_field("selective", 1, |e| b.encode(e))
                })
            },
        }
    }
}

// ---------------------------------------------------------------------------
/// Strongly typed ChatAction. Instead of passing a String to the
/// `send_chat_action` method, this is used.
#[derive(Debug, PartialEq, Clone, Copy)]
pub enum ChatAction {
    Typing,
    UploadPhoto,
    RecordVideo,
    UploadVideo,
    RecordAudio,
    UploadAudio,
    UploadDocument,
    FindLocation,
}

impl Decodable for ChatAction {
    fn decode<D: Decoder>(d: &mut D) -> Result<Self, D::Error> {
        Ok(match &*try!(d.read_str()) {
            "typing" => ChatAction::Typing,
            "upload_photo" => ChatAction::UploadPhoto,
            "record_video" => ChatAction::RecordVideo,
            "upload_video" => ChatAction::UploadVideo,
            "record_audio" => ChatAction::RecordAudio,
            "upload_audio" => ChatAction::UploadAudio,
            "upload_document" => ChatAction::UploadDocument,
            "find_location" => ChatAction::FindLocation,
            _ => return Err(d.error("Not a valid chat action")),
        })
    }
}

impl Into<&'static str> for ChatAction {
    fn into(self) -> &'static str {
        match self {
             ChatAction::Typing => "typing",
             ChatAction::UploadPhoto => "upload_photo",
             ChatAction::RecordVideo => "record_video",
             ChatAction::UploadVideo => "upload_video",
             ChatAction::RecordAudio => "record_audio",
             ChatAction::UploadAudio => "upload_audio",
             ChatAction::UploadDocument => "upload_document",
             ChatAction::FindLocation => "find_location",
        }
    }
}

impl ToString for ChatAction {
    fn to_string(&self) -> String {
        Into::<&str>::into(*self).into()
    }
}

impl Encodable for ChatAction {
    fn encode<E: Encoder>(&self, e: &mut E) -> Result<(), E::Error> {
        e.emit_str((*self).into())
    }
}

// ---------------------------------------------------------------------------
/// Either a User or a GroupChat. Used in "chat" field of Message. Has some
/// useful methods for less typing.
#[derive(Debug, PartialEq, Clone)]
pub enum Chat {
    Private {
        id: Integer,
        first_name: String,
        last_name: Option<String>,
        username: Option<String>,
    },
    Group {
        id: Integer,
        title: String,<commit_msg>Update docstring for Chat type<commit_after>//! Types of the Telegram API.
//!
//! This module contains definitions of the types defined
//! [here](https://core.telegram.org/bots/api/#available-types). Many Telegram
//! types, like "Location", map directly to Rust-structs. Other Telegram types,
//! like "Message", was made more rusty by using enums.
//!
//! All types implement `Decodable` and `Encodable`, so they can be serialized
//! as JSON. Non existing JSON-fields will result in `None` values for `Option`
//! types. `None` values don't result in JSON fields.
//!

use rustc_serialize::{Decodable, Encodable, Decoder, Encoder};
use std::convert::Into;
use std::fmt;

// ===========================================================================
// Helpers
// ===========================================================================
// Macro to implement "Encodable" quickly. "None" fields won't be encoded.
macro_rules! impl_encode {
    (
        $ty:ident, $count:expr,
        [$($id:expr => $field:ident),*],
        [$($o_id:expr => $o_field:ident),*]
    ) => {
        impl Encodable for $ty {
            fn encode<E: Encoder>(&self, e: &mut E) -> Result<(), E::Error> {
                e.emit_struct(stringify!($ty), $count, |e| {
                    $(
                        try!(e.emit_struct_field(stringify!($field), $id, |e| {
                            self.$field.encode(e)
                        }));
                    )*
                    $(
                        if let Some(ref v) = self.$o_field {
                            try!(e.emit_struct_field(
                                stringify!($o_field), $o_id, |e| {
                                v.encode(e)
                            }));
                        }
                    )*

                    Ok(())
                })
            }
        }
    }
}

// Decodes a field with a given name. If successful: Return decoded
// value. If not: Exit function with error value.
macro_rules! try_field {
    ($d:ident, $name:expr) => {
        try!($d.read_struct_field($name, 0, Decodable::decode))
    }
}


// ===========================================================================
// Telegram primitive types
// ===========================================================================
/// The Telegram "Integer": Currently i64.
pub type Integer = i64;
/// The Telegram "Float": Currently f32.
pub type Float = f32;


// ===========================================================================
// Types not explicitly mentioned or somehow different from Telegram types
// ===========================================================================
/// All API responses are from this type. Mostly used internal.
#[derive(RustcDecodable, Debug, PartialEq, Clone)]
pub struct Response<T: Decodable> {
    pub ok: bool,
    pub error_code: Option<Integer>,
    pub description: Option<String>,
    pub result: Option<T>,
}

// ---------------------------------------------------------------------------
/// Represents one of "ReplyKeyboardMarkup", "ReplyKeyboardHide" or
/// "ForceReply". Used for the "reply_markup" field.
#[derive(Debug, PartialEq, Clone)]
pub enum ReplyMarkup {
    Keyboard(ReplyKeyboardMarkup),
    /// The boolean corresponds to the "selective" field of "ReplyKeyboardHide"
    KeyboardHide(bool),
    /// The boolean corresponds to the "selective" field of "ForceReply"
    ForceReply(bool),
}

impl From<ReplyKeyboardMarkup> for ReplyMarkup {
    fn from(keyboard: ReplyKeyboardMarkup) -> ReplyMarkup {
        ReplyMarkup::Keyboard(keyboard)
    }
}

impl Encodable for ReplyMarkup {
    fn encode<E: Encoder>(&self, e: &mut E) -> Result<(), E::Error> {
        match *self {
            ReplyMarkup::Keyboard(ref k) => k.encode(e),
            ReplyMarkup::KeyboardHide(b) => {
                e.emit_struct("ReplyKeyboardHide", 2, |e| {
                    try!(e.emit_struct_field("hide_keyboard", 0, |e| {
                        true.encode(e)
                    }));
                    e.emit_struct_field("selective", 1, |e| b.encode(e))
                })
            },
            ReplyMarkup::ForceReply(b) => {
                e.emit_struct("ForceReply", 2, |e| {
                    try!(e.emit_struct_field("force_reply", 0, |e| {
                        true.encode(e)
                    }));
                    e.emit_struct_field("selective", 1, |e| b.encode(e))
                })
            },
        }
    }
}

// ---------------------------------------------------------------------------
/// Strongly typed ChatAction. Instead of passing a String to the
/// `send_chat_action` method, this is used.
#[derive(Debug, PartialEq, Clone, Copy)]
pub enum ChatAction {
    Typing,
    UploadPhoto,
    RecordVideo,
    UploadVideo,
    RecordAudio,
    UploadAudio,
    UploadDocument,
    FindLocation,
}

impl Decodable for ChatAction {
    fn decode<D: Decoder>(d: &mut D) -> Result<Self, D::Error> {
        Ok(match &*try!(d.read_str()) {
            "typing" => ChatAction::Typing,
            "upload_photo" => ChatAction::UploadPhoto,
            "record_video" => ChatAction::RecordVideo,
            "upload_video" => ChatAction::UploadVideo,
            "record_audio" => ChatAction::RecordAudio,
            "upload_audio" => ChatAction::UploadAudio,
            "upload_document" => ChatAction::UploadDocument,
            "find_location" => ChatAction::FindLocation,
            _ => return Err(d.error("Not a valid chat action")),
        })
    }
}

impl Into<&'static str> for ChatAction {
    fn into(self) -> &'static str {
        match self {
             ChatAction::Typing => "typing",
             ChatAction::UploadPhoto => "upload_photo",
             ChatAction::RecordVideo => "record_video",
             ChatAction::UploadVideo => "upload_video",
             ChatAction::RecordAudio => "record_audio",
             ChatAction::UploadAudio => "upload_audio",
             ChatAction::UploadDocument => "upload_document",
             ChatAction::FindLocation => "find_location",
        }
    }
}

impl ToString for ChatAction {
    fn to_string(&self) -> String {
        Into::<&str>::into(*self).into()
    }
}

impl Encodable for ChatAction {
    fn encode<E: Encoder>(&self, e: &mut E) -> Result<(), E::Error> {
        e.emit_str((*self).into())
    }
}

// ---------------------------------------------------------------------------
/// Either a Private or a Group or a Channel. Used in "chat" field of Message. Has some
/// useful methods for less typing.
#[derive(Debug, PartialEq, Clone)]
pub enum Chat {
    Private {
        id: Integer,
        first_name: String,
        last_name: Option<String>,
        username: Option<String>,
    },
    Group {
        id: Integer,
        title: String,
{'fraction_non_alphanumeric': 0.22358052875764048, 'fraction_numerical': 0.0022092937624272773, 'mean_word_length': 2.051685393258427, 'pattern_counts': {'":': 4, '<': 37, '<?xml version=': 0, '>': 99, 'https://': 2, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3169683', 'n_tokens_mistral': 3772, 'n_tokens_neox': 3601, 'n_words': 912}