use crate::types::{
file::InputFile,
photo_size::PhotoSize,
primitive::{Float, Integer},
};
use serde::{Deserialize, Serialize};
use serde_json::Error as JsonError;
use std::{error::Error as StdError, fmt};
#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize)]
#[serde(rename_all = "lowercase")]
pub enum MaskPositionPoint {
Forehead,
Eyes,
Mouth,
Chin,
}
#[derive(Clone, Copy, Debug, Deserialize, Serialize)]
pub struct MaskPosition {
pub point: MaskPositionPoint,
pub x_shift: Float,
pub y_shift: Float,
pub scale: Float,
}
impl MaskPosition {
pub(crate) fn serialize(&self) -> Result<String, MaskPositionError> {
serde_json::to_string(self).map_err(MaskPositionError::Serialize)
}
}
#[derive(Debug)]
pub enum MaskPositionError {
Serialize(JsonError),
}
impl StdError for MaskPositionError {
fn source(&self) -> Option<&(dyn StdError + 'static)> {
match self {
MaskPositionError::Serialize(err) => Some(err),
}
}
}
impl fmt::Display for MaskPositionError {
fn fmt(&self, out: &mut fmt::Formatter) -> fmt::Result {
match self {
MaskPositionError::Serialize(err) => write!(out, "can not serialize mask position: {}", err),
}
}
}
#[derive(Clone, Debug, Deserialize)]
pub struct Sticker {
pub file_id: String,
pub file_unique_id: String,
pub width: Integer,
pub height: Integer,
pub thumb: Option<PhotoSize>,
pub emoji: Option<String>,
pub set_name: Option<String>,
pub mask_position: Option<MaskPosition>,
pub file_size: Option<Integer>,
pub is_animated: bool,
pub is_video: bool,
}
#[derive(Clone, Debug, Deserialize)]
pub struct StickerSet {
pub name: String,
pub title: String,
pub contains_masks: bool,
pub stickers: Vec<Sticker>,
pub is_animated: bool,
pub is_video: bool,
pub thumb: Option<PhotoSize>,
}
#[derive(Debug)]
pub struct NewSticker {
pub(crate) kind: NewStickerKind,
}
#[derive(Debug)]
pub(crate) enum NewStickerKind {
Png(InputFile),
Tgs(InputFile),
Video(InputFile),
}
impl NewSticker {
pub fn png<I>(file: I) -> Self
where
I: Into<InputFile>,
{
Self {
kind: NewStickerKind::Png(file.into()),
}
}
pub fn tgs<I>(file: I) -> Self
where
I: Into<InputFile>,
{
Self {
kind: NewStickerKind::Tgs(file.into()),
}
}
pub fn video<I>(file: I) -> Self
where
I: Into<InputFile>,
{
Self {
kind: NewStickerKind::Video(file.into()),
}
}
}
#[cfg(test)]
mod tests {
#![allow(clippy::float_cmp)]
use super::*;
#[test]
fn deserialize_sticker_full() {
let data: Sticker = serde_json::from_value(serde_json::json!({
"file_id": "test file id",
"file_unique_id": "unique-id",
"width": 512,
"height": 512,
"thumb": {
"file_id": "AdddddUuUUUUccccUUmm_PPP",
"file_unique_id": "unique-thumb-id",
"width": 24,
"height": 24,
"file_size": 12324
},
"emoji": ":D",
"set_name": "sticker set name",
"mask_position": {
"point": "forehead",
"x_shift": 3.0,
"y_shift": 2.0,
"scale": 3.0,
},
"file_size": 1234,
"is_animated": false,
"is_video": false
}))
.unwrap();
assert_eq!(data.file_id, "test file id");
assert_eq!(data.file_unique_id, "unique-id");
assert_eq!(data.width, 512);
assert_eq!(data.height, 512);
assert!(!data.is_animated);
assert!(!data.is_video);
let thumb = data.thumb.unwrap();
assert_eq!(thumb.file_id, "AdddddUuUUUUccccUUmm_PPP");
assert_eq!(thumb.file_unique_id, "unique-thumb-id");
assert_eq!(thumb.width, 24);
assert_eq!(thumb.height, 24);
assert_eq!(thumb.file_size.unwrap(), 12324);
assert_eq!(data.emoji.unwrap(), ":D");
assert_eq!(data.set_name.unwrap(), "sticker set name");
let mask_position = data.mask_position.unwrap();
assert_eq!(mask_position.point, MaskPositionPoint::Forehead);
assert_eq!(mask_position.x_shift, 3.0);
assert_eq!(mask_position.y_shift, 2.0);
assert_eq!(mask_position.scale, 3.0);
assert_eq!(data.file_size.unwrap(), 1234);
}
#[test]
fn deserialize_sticker_partial() {
let data: Sticker = serde_json::from_value(serde_json::json!({
"file_id": "test file id",
"file_unique_id": "unique-id",
"width": 512,
"height": 512,
"is_animated": true,
"is_video": false
}))
.unwrap();
assert_eq!(data.file_id, "test file id");
assert_eq!(data.file_unique_id, "unique-id");
assert_eq!(data.width, 512);
assert_eq!(data.height, 512);
assert!(data.is_animated);
assert!(!data.is_video);
assert!(data.thumb.is_none());
assert!(data.emoji.is_none());
assert!(data.set_name.is_none());
assert!(data.file_size.is_none());
}
#[test]
fn mask_position_point() {
assert_eq!(
serde_json::to_string(&MaskPositionPoint::Forehead).unwrap(),
r#""forehead""#
);
assert_eq!(serde_json::to_string(&MaskPositionPoint::Eyes).unwrap(), r#""eyes""#);
assert_eq!(serde_json::to_string(&MaskPositionPoint::Mouth).unwrap(), r#""mouth""#);
assert_eq!(serde_json::to_string(&MaskPositionPoint::Chin).unwrap(), r#""chin""#);
assert_eq!(
serde_json::from_str::<MaskPositionPoint>(r#""forehead""#).unwrap(),
MaskPositionPoint::Forehead
);
assert_eq!(
serde_json::from_str::<MaskPositionPoint>(r#""eyes""#).unwrap(),
MaskPositionPoint::Eyes
);
assert_eq!(
serde_json::from_str::<MaskPositionPoint>(r#""mouth""#).unwrap(),
MaskPositionPoint::Mouth
);
assert_eq!(
serde_json::from_str::<MaskPositionPoint>(r#""chin""#).unwrap(),
MaskPositionPoint::Chin
);
}
#[test]
fn deserialize_sticker_set() {
let data: StickerSet = serde_json::from_value(serde_json::json!({
"name": "test",
"title": "test",
"contains_masks": false,
"stickers": [],
"is_animated": false,
"is_video": false,
"thumb": {
"file_id": "thumb-file-id",
"file_unique_id": "thumb-file-unique-id",
"width": 512,
"height": 512,
"file_size": 2048,
}
}))
.unwrap();
assert_eq!(data.name, "test");
assert_eq!(data.title, "test");
assert!(!data.is_animated);
assert!(!data.is_video);
assert!(!data.contains_masks);
assert!(data.stickers.is_empty());
let thumb = data.thumb.unwrap();
assert_eq!(thumb.file_id, "thumb-file-id");
assert_eq!(thumb.file_unique_id, "thumb-file-unique-id");
assert_eq!(thumb.width, 512);
assert_eq!(thumb.height, 512);
assert_eq!(thumb.file_size.unwrap(), 2048);
}
}