use super::{
file::{self, id::AsFileId},
PhotoSize,
};
use is_macro::Is;
use serde::de::{Deserialize, Deserializer, IgnoredAny, MapAccess, Visitor};
use std::fmt::{self, Formatter};
pub mod mask_position;
pub mod set;
pub use {mask_position::MaskPosition, set::Set};
#[derive(Debug, PartialEq, Clone, Copy, Is)]
#[non_exhaustive]
pub enum Kind {
Plain,
Animated,
Mask(MaskPosition),
}
#[derive(Debug, PartialEq, Clone)]
#[non_exhaustive]
pub struct Sticker {
pub file_id: file::Id,
pub file_unique_id: String,
pub width: u32,
pub height: u32,
pub thumb: Option<PhotoSize>,
pub emoji: Option<String>,
pub set_name: Option<String>,
pub file_size: Option<u32>,
pub kind: Kind,
}
impl crate::internal::Sealed for Sticker {}
impl AsFileId for Sticker {
#[must_use]
fn as_file_id(&self) -> file::id::Ref<'_> {
self.file_id.as_ref()
}
}
const FILE_ID: &str = "file_id";
const FILE_UNIQUE_ID: &str = "file_unique_id";
const WIDTH: &str = "width";
const HEIGHT: &str = "height";
const IS_ANIMATED: &str = "is_animated";
const THUMB: &str = "thumb";
const EMOJI: &str = "emoji";
const SET_NAME: &str = "set_name";
const MASK_POSITION: &str = "mask_position";
const FILE_SIZE: &str = "file_size";
struct StickerVisitor;
impl<'v> Visitor<'v> for StickerVisitor {
type Value = Sticker;
fn expecting(&self, formatter: &mut Formatter) -> fmt::Result {
write!(formatter, "struct Sticker")
}
fn visit_map<V>(self, mut map: V) -> Result<Self::Value, V::Error>
where
V: MapAccess<'v>,
{
let mut file_id = None;
let mut file_unique_id = None;
let mut width = None;
let mut height = None;
let mut is_animated = None;
let mut thumb = None;
let mut emoji = None;
let mut set_name = None;
let mut mask_position = None;
let mut file_size = None;
while let Some(key) = map.next_key()? {
match key {
FILE_ID => file_id = Some(map.next_value()?),
FILE_UNIQUE_ID => file_unique_id = Some(map.next_value()?),
WIDTH => width = Some(map.next_value()?),
HEIGHT => height = Some(map.next_value()?),
IS_ANIMATED => is_animated = Some(map.next_value()?),
THUMB => thumb = Some(map.next_value()?),
EMOJI => emoji = Some(map.next_value()?),
SET_NAME => set_name = Some(map.next_value()?),
MASK_POSITION => mask_position = Some(map.next_value()?),
FILE_SIZE => file_size = Some(map.next_value()?),
_ => {
let _ = map.next_value::<IgnoredAny>()?;
}
}
}
let kind = if let Some(mask_position) = mask_position {
Kind::Mask(mask_position)
} else if is_animated == Some(true) {
Kind::Animated
} else {
Kind::Plain
};
Ok(Sticker {
file_id: file_id
.ok_or_else(|| serde::de::Error::missing_field(FILE_ID))?,
file_unique_id: file_unique_id.ok_or_else(|| {
serde::de::Error::missing_field(FILE_UNIQUE_ID)
})?,
width: width
.ok_or_else(|| serde::de::Error::missing_field(WIDTH))?,
height: height
.ok_or_else(|| serde::de::Error::missing_field(HEIGHT))?,
thumb,
emoji,
set_name,
file_size,
kind,
})
}
}
impl<'de> Deserialize<'de> for Sticker {
fn deserialize<D>(d: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
d.deserialize_struct(
"Sticker",
&[
FILE_ID,
FILE_UNIQUE_ID,
WIDTH,
HEIGHT,
IS_ANIMATED,
THUMB,
EMOJI,
SET_NAME,
MASK_POSITION,
FILE_SIZE,
],
StickerVisitor,
)
}
}