use super::message::Geo;
use crate::Button;
use serde::de::{self, MapAccess, Visitor};
use serde::{Deserialize, Deserializer};
use std::fmt;
#[derive(Debug, Clone)]
pub struct Attachment<T> {
pub attachment_type: String,
pub item: AttachmentItem<T>,
}
#[derive(Debug, Deserialize, Clone)]
pub enum AttachmentItem<T> {
Photo(Photo),
Video(Video),
Audio(Audio),
Doc(Doc),
Link(Link<T>),
Market(Product),
Wall(Wall<T>),
Sticker(Sticker),
Gift(Gift),
}
#[derive(Debug, Deserialize, Clone)]
pub struct Photo {
pub id: i64,
pub album_id: i32,
pub owner_id: i32,
pub user_id: Option<i32>,
pub text: String,
pub date: i64,
pub sizes: Vec<PhotoSize>,
pub width: Option<i32>,
pub height: Option<i32>,
}
#[derive(Debug, Deserialize, Clone)]
pub struct PhotoSize {
#[serde(rename = "type")]
pub photo_type: String, pub url: String,
pub width: i32,
pub height: i32,
}
#[derive(Debug, Deserialize, Clone)]
pub struct Video {
pub id: i32,
pub owner_id: i32,
pub title: String,
pub description: Option<String>,
pub duration: i32,
pub image: Vec<VideoImage>,
pub first_frame: Vec<VideoImage>,
pub date: i64,
pub adding_date: i64,
pub views: i32,
pub player: String,
pub access_key: Option<String>,
pub is_private: Option<i32>,
pub width: i32,
pub height: i32,
pub can_add: i32,
}
#[derive(Debug, Deserialize, Clone)]
pub struct VideoImage {
pub height: i32,
pub url: String,
pub width: i32,
}
#[derive(Debug, Deserialize, Clone)]
pub struct Audio {
pub id: i32,
pub owner_id: i32,
pub artist: String,
pub title: String,
pub duration: i32,
pub url: String,
pub lyrics_id: Option<i32>,
pub album_id: Option<i32>,
pub genre_id: Option<i32>,
pub date: i64,
pub is_hq: Option<i32>,
}
#[derive(Debug, Deserialize, Clone)]
pub struct Doc {
pub id: i32,
pub owner_id: i32,
pub title: String,
pub size: isize,
pub ext: String,
pub url: String,
pub date: i64,
#[serde(rename = "type")]
pub doc_type: i32,
pub access_key: Option<String>,
}
#[derive(Debug, Deserialize, Clone)]
pub struct Link<T> {
pub url: String,
pub title: String,
pub caption: Option<String>,
pub description: String,
pub photo: Option<Photo>,
pub product: Option<Product>,
pub button: Option<Button<T>>,
pub preview_page: String,
pub preview_url: String,
}
#[derive(Debug, Deserialize, Clone)]
pub struct Product {
pub id: i32,
pub owner_id: i32,
pub title: String,
pub description: String,
pub price: Price,
pub dimensions: Option<Dimensions>,
pub weight: Option<i32>,
pub category: Category,
pub thumb_photo: String,
pub date: i64,
pub availability: i32,
pub is_favorite: bool,
pub sku: Option<String>,
}
#[derive(Debug, Deserialize, Clone)]
pub struct Price {
pub amount: String,
pub currency: Currency,
pub old_amount: Option<String>,
pub text: String,
}
#[derive(Debug, Deserialize, Clone)]
pub struct Currency {
pub id: i32,
pub name: String,
}
#[derive(Debug, Deserialize, Clone)]
pub struct Dimensions {
pub width: i32,
pub height: i32,
pub length: i32,
}
#[derive(Debug, Deserialize, Clone)]
pub struct Category {
pub id: i32,
pub name: String,
pub section: Section,
}
#[derive(Debug, Deserialize, Clone)]
pub struct Section {
pub id: i32,
pub name: String,
}
#[derive(Debug, Deserialize, Clone)]
pub struct Sticker {
pub product_id: i32,
pub sticker_id: i32,
pub images: Vec<StickerImage>,
pub images_with_background: Vec<StickerImage>,
pub animation_url: Option<String>,
pub is_allowed: bool,
}
#[derive(Debug, Deserialize, Clone)]
pub struct StickerImage {
pub url: String,
pub width: i32,
pub height: i32,
}
#[derive(Debug, Deserialize, Clone)]
pub struct Gift {
pub id: i32,
pub thumb_256: String,
pub thumb_96: String,
pub thumb_48: String,
}
#[derive(Debug, Deserialize, Clone)]
pub struct Wall<T> {
pub id: i32,
pub owner_id: i32,
pub from_id: i32,
pub created_by: Option<i32>,
pub date: i64,
pub text: String,
pub reply_owner_id: Option<i32>,
pub reply_post_id: Option<i32>,
pub friends_only: Option<i32>,
pub comments: Option<WallPostComments>,
pub likes: Option<WallPostLikes>,
pub reposts: Option<WallPostReposts>,
pub views: Option<WallPostViews>,
pub post_type: String,
pub attachments: Box<Option<Vec<Attachment<T>>>>,
pub geo: Option<Geo>,
pub signer_id: Option<i32>,
pub copy_history: Box<Option<Vec<Wall<T>>>>,
pub can_pin: Option<i32>,
pub can_delete: Option<i32>,
pub can_edit: Option<i32>,
pub is_pinned: Option<i32>,
pub marked_as_ads: Option<i32>,
pub is_favorite: bool,
pub donut: Option<WallPostDonut>,
pub postponed_id: Option<i32>,
}
#[derive(Debug, Deserialize, Clone)]
pub struct WallPostComments {
pub count: i32,
pub can_post: Option<i32>,
pub groups_can_post: bool,
pub can_close: bool,
pub can_open: bool,
}
#[derive(Debug, Deserialize, Clone)]
pub struct WallPostLikes {
pub count: i32,
pub user_likes: i32,
pub can_like: i32,
pub can_publish: i32,
}
#[derive(Debug, Deserialize, Clone)]
pub struct WallPostReposts {
pub count: i32,
pub user_reposted: i32,
}
#[derive(Debug, Deserialize, Clone)]
pub struct WallPostViews {
pub count: i32,
}
#[derive(Debug, Deserialize, Clone)]
pub struct WallPostDonut {
pub is_donut: bool,
pub paid_duration: Option<i32>,
pub can_publish_free_copy: bool,
pub edit_mode: String,
}
impl<'de, T> Deserialize<'de> for Attachment<T>
where
T: Deserialize<'de>,
{
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
struct AttachmentVisitor<T>(std::marker::PhantomData<T>);
impl<'de, T> Visitor<'de> for AttachmentVisitor<T>
where
T: Deserialize<'de>,
{
type Value = Attachment<T>;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("struct Attachment")
}
fn visit_map<V>(self, mut map: V) -> Result<Self::Value, V::Error>
where
V: MapAccess<'de>,
{
let mut attachment_type: Option<String> = None;
let mut item: Option<AttachmentItem<T>> = None;
while let Some(key) = map.next_key::<String>()? {
if key == "type" {
if attachment_type.is_some() {
return Err(de::Error::duplicate_field("type"));
}
attachment_type = Some(map.next_value()?);
} else {
if attachment_type.is_none() {
return Err(de::Error::missing_field("type"));
}
let attachment_type_ref = attachment_type.as_ref().unwrap();
match attachment_type_ref.as_str() {
"photo" => {
item = Some(AttachmentItem::Photo(map.next_value()?));
}
"video" => {
item = Some(AttachmentItem::Video(map.next_value()?));
}
"audio" => {
item = Some(AttachmentItem::Audio(map.next_value()?));
}
"doc" => {
item = Some(AttachmentItem::Doc(map.next_value()?));
}
"link" => {
item = Some(AttachmentItem::Link(map.next_value()?));
}
"market" => {
item = Some(AttachmentItem::Market(map.next_value()?));
}
"wall" => {
item = Some(AttachmentItem::Wall(map.next_value()?));
}
"sticker" => {
item = Some(AttachmentItem::Sticker(map.next_value()?));
}
"gift" => {
item = Some(AttachmentItem::Gift(map.next_value()?));
}
_ => {
return Err(de::Error::unknown_field(
&key,
&[
"photo", "video", "audio", "doc", "link", "market", "wall",
"sticker", "gift",
],
))
}
}
}
}
let attachment_type =
attachment_type.ok_or_else(|| de::Error::missing_field("type"))?;
let item = item.ok_or_else(|| de::Error::missing_field("item"))?;
Ok(Attachment {
attachment_type,
item,
})
}
}
deserializer.deserialize_map(AttachmentVisitor(std::marker::PhantomData))
}
}