use error::{Error, Result};
use serde_json::Value;
use utils::*;
#[derive(Copy, Clone, Hash, Eq, PartialEq, Debug, Ord, PartialOrd)]
pub enum AgeRating {
G,
None,
PG13,
PG,
R17Plus,
R17,
R18,
TvY7,
}
impl AgeRating {
pub fn name(&self) -> &str {
match *self {
AgeRating::G => "G",
AgeRating::None => "None",
AgeRating::PG13 => "PG13",
AgeRating::PG => "PG",
AgeRating::R17Plus => "R17+",
AgeRating::R17 => "R17",
AgeRating::R18 => "R18+",
AgeRating::TvY7 => "TV-Y7",
}
}
#[doc(hidden)]
pub fn decode(value: Value) -> Result<Self> {
match value.clone() {
Value::String(name) => match &name[..] {
"G" => Some(AgeRating::G),
"PG-13" => Some(AgeRating::PG13),
"PG13" => Some(AgeRating::PG13),
"PG" => Some(AgeRating::PG),
"R17+" => Some(AgeRating::R17Plus),
"R17" => Some(AgeRating::R17),
"R18+" => Some(AgeRating::R18),
"TV-Y7" => Some(AgeRating::TvY7),
_ => None,
},
Value::Null => Some(AgeRating::None),
_ => None,
}.ok_or(Error::Decode(concat!("Expected valid AgeRating"), value))
}
}
#[derive(Copy, Clone, Hash, Eq, PartialEq, Debug, Ord, PartialOrd)]
pub enum AnimeStatus {
CurrentlyAiring,
FinishedAiring,
NotYetAired,
}
map_names! { AnimeStatus;
CurrentlyAiring, "Currently Airing";
FinishedAiring, "Finished Airing";
NotYetAired, "Not Yet Aired";
}
#[derive(Copy, Clone, Hash, Eq, PartialEq, Debug, Ord, PartialOrd)]
pub enum ItemType {
Anime,
}
map_names! { ItemType;
Anime, "Anime";
}
#[derive(Copy, Clone, Hash, Eq, PartialEq, Debug, Ord, PartialOrd)]
pub enum LibraryRatingType {
Advanced,
Simple,
}
map_names! { LibraryRatingType;
Advanced, "advanced";
Simple, "simple";
}
#[derive(Copy, Clone, Hash, Eq, PartialEq, Debug, Ord, PartialOrd)]
pub enum LibraryStatus {
Completed,
CurrentlyWatching,
Dropped,
PlanToWatch,
OnHold,
}
impl LibraryStatus {
pub fn name(&self) -> &str {
match *self {
LibraryStatus::Completed => "Completed",
LibraryStatus::CurrentlyWatching => "Currently Watching",
LibraryStatus::Dropped => "Dropped",
LibraryStatus::PlanToWatch => "Plan To Watch",
LibraryStatus::OnHold => "On Hold",
}
}
#[doc(hidden)]
pub fn from_str(name: &str) -> Option<Self> {
match name {
"completed" => Some(LibraryStatus::Completed),
"currently_watching" | "currently-watching" => Some(LibraryStatus::CurrentlyWatching),
"dropped" => Some(LibraryStatus::Dropped),
"on_hold" | "on-hold" => Some(LibraryStatus::OnHold),
"plan_to_watch" | "plan-to-watch" => Some(LibraryStatus::PlanToWatch),
_ => None,
}
}
#[doc(hidden)]
pub fn decode(value: Value) -> Result<Self> {
let name = try!(into_string(value));
Self::from_str(&name)
.ok_or(Error::Decode("Expected valid AgeRating",
Value::String(name)))
}
}
#[derive(Copy, Clone, Hash, Eq, PartialEq, Debug, Ord, PartialOrd)]
pub enum RelationType {
Husbando,
Waifu,
}
map_names! { RelationType;
Husbando, "Husbando";
Waifu, "Waifu";
}
#[derive(Copy, Clone, Hash, Eq, PartialEq, Debug, Ord, PartialOrd)]
pub enum ShowType {
Movie,
Music,
ONA,
OVA,
Special,
TV,
}
map_names! { ShowType;
Movie, "Movie";
Music, "Music";
ONA, "ONA";
OVA, "OVA";
Special, "Special";
TV, "TV";
}
#[derive(Copy, Clone, Hash, Eq, PartialEq, Debug, Ord, PartialOrd)]
pub enum StoryType {
Comment,
MediaStory,
}
map_names! { StoryType;
Comment, "comment";
MediaStory, "media_story";
}
#[derive(Copy, Clone, Hash, Eq, PartialEq, Debug, Ord, PartialOrd)]
pub enum SubstoryType {
Comment,
Followed,
WatchedEpisode,
WatchlistStatusUpdate,
}
map_names! { SubstoryType;
Comment, "comment";
Followed, "followed";
WatchedEpisode, "watched_episode";
WatchlistStatusUpdate, "watchlist_status_update";
}
#[derive(Copy, Clone, Hash, Eq, PartialEq, Debug, Ord, PartialOrd)]
pub enum TitleLanguagePreference {
Canonical,
English,
Romanized,
}
map_names! { TitleLanguagePreference;
Canonical, "canonical";
English, "english";
Romanized, "romanized";
}
#[derive(Clone, Debug)]
pub struct Anime {
pub age_rating: AgeRating,
pub alternate_title: Option<String>,
pub community_rating: f64,
pub cover_image: String,
pub episode_count: u64,
pub episode_length: u64,
pub finished_airing: Option<String>,
pub genres: Vec<Genre>,
pub id: u64,
pub mal_id: Option<u64>,
pub kind: ShowType,
pub slug: String,
pub started_airing: Option<String>,
pub status: AnimeStatus,
pub synopsis: Option<String>,
pub title: String,
pub url: String,
}
impl Anime {
#[doc(hidden)]
pub fn decode(value: Value) -> Result<Anime> {
let mut value = try!(into_map(value));
Ok(Anime {
age_rating: try!(remove(&mut value, "age_rating").and_then(AgeRating::decode)),
alternate_title: try!(opt(&mut value, "alternate_title", into_string)),
community_rating: req!(try!(remove(&mut value, "community_rating")).as_f64()),
cover_image: try!(remove(&mut value, "cover_image").and_then(into_string)),
episode_count: req!(try!(remove(&mut value, "episode_count")).as_u64().or(Some(0))),
episode_length: req!(try!(remove(&mut value, "episode_length")).as_u64().or(Some(0))),
finished_airing: try!(opt(&mut value, "finished_airing", into_string)),
genres: try!(decode_array(try!(remove(&mut value, "genres")), Genre::decode)),
id: req!(try!(remove(&mut value, "id")).as_u64()),
mal_id: remove(&mut value, "mal_id").ok().and_then(|v| v.as_u64()),
kind: try!(remove(&mut value, "show_type").and_then(ShowType::decode)),
slug: try!(remove(&mut value, "slug").and_then(into_string)),
started_airing: try!(opt(&mut value, "started_airing", into_string)),
status: try!(remove(&mut value, "status").and_then(AnimeStatus::decode)),
synopsis: try!(opt(&mut value, "synopsis", into_string)),
title: try!(remove(&mut value, "title").and_then(into_string)),
url: try!(remove(&mut value, "url").and_then(into_string)),
})
}
}
#[derive(Clone, Debug)]
pub struct Favorite {
pub created_at: String,
pub id: u64,
pub item_id: u64,
pub item_type: ItemType,
pub updated_at: String,
pub user_id: u64,
}
impl Favorite {
#[doc(hidden)]
pub fn decode(value: Value) -> Result<Favorite> {
let mut value = try!(into_map(value));
Ok(Favorite {
created_at: try!(remove(&mut value, "created_at").and_then(into_string)),
id: req!(try!(remove(&mut value, "id")).as_u64()),
item_id: req!(try!(remove(&mut value, "item_id")).as_u64()),
item_type: try!(remove(&mut value, "item_type").and_then(ItemType::decode)),
updated_at: try!(remove(&mut value, "updated_at").and_then(into_string)),
user_id: req!(try!(remove(&mut value, "user_id")).as_u64()),
})
}
}
#[derive(Clone, Debug)]
pub struct Genre {
pub name: String,
}
impl Genre {
#[doc(hidden)]
pub fn decode(value: Value) -> Result<Genre> {
let mut value = try!(into_map(value));
Ok(Genre {
name: try!(remove(&mut value, "name").and_then(into_string)),
})
}
}
#[derive(Clone, Debug)]
pub struct LibraryRating {
pub kind: LibraryRatingType,
pub value: Option<f64>,
}
impl LibraryRating {
#[doc(hidden)]
pub fn decode(value: Value) -> Result<LibraryRating> {
let mut value = try!(into_map(value));
Ok(LibraryRating {
kind: try!(remove(&mut value, "type").and_then(LibraryRatingType::decode)),
value: remove(&mut value, "value").ok().and_then(|v| v.as_f64()),
})
}
}
#[derive(Clone, Debug)]
pub struct Library {
pub anime: Anime,
pub episodes_watched: u64,
pub last_watched: String,
pub notes_available: bool,
pub notes: Option<String>,
pub private: bool,
pub rating: LibraryRating,
pub rewatched_times: u64,
pub rewatching: bool,
pub status: LibraryStatus,
pub updated_at: String,
}
impl Library {
#[doc(hidden)]
pub fn decode(value: Value) -> Result<Library> {
let mut value = try!(into_map(value));
Ok(Library {
anime: try!(remove(&mut value, "anime").and_then(Anime::decode)),
episodes_watched: req!(try!(remove(&mut value, "episodes_watched")).as_u64()),
last_watched: try!(remove(&mut value, "last_watched").and_then(into_string)),
notes_available: try!(opt(&mut value, "notes_available", |v| Ok(req!(v.as_bool())))).unwrap_or(false),
notes: try!(opt(&mut value, "notes", into_string)),
private: req!(try!(remove(&mut value, "private")).as_bool()),
rating: try!(remove(&mut value, "rating").and_then(LibraryRating::decode)),
rewatched_times: req!(try!(remove(&mut value, "rewatched_times")).as_u64()),
rewatching: req!(try!(remove(&mut value, "rewatching")).as_bool()),
status: try!(remove(&mut value, "status").and_then(LibraryStatus::decode)),
updated_at: try!(remove(&mut value, "updated_at").and_then(into_string)),
})
}
}
#[derive(Clone, Debug)]
pub struct Story {
pub id: u64,
pub kind: StoryType,
pub media: Option<Anime>,
pub poster: Option<UserMini>,
pub self_post: bool,
pub substories_count: u64,
pub substories: Vec<Substory>,
pub updated_at: String,
pub user: UserMini,
}
impl Story {
#[doc(hidden)]
pub fn decode(value: Value) -> Result<Story> {
let mut value = try!(into_map(value));
println!("{:#?}", value);
Ok(Story {
id: req!(try!(remove(&mut value, "id")).as_u64()),
kind: try!(remove(&mut value, "story_type").and_then(StoryType::decode)),
media: try!(opt(&mut value, "media", Anime::decode)),
poster: try!(opt(&mut value, "poster", UserMini::decode)),
self_post: try!(opt(&mut value, "self_post", |v| Ok(req!(v.as_bool())))).unwrap_or(false),
substories_count: req!(try!(remove(&mut value, "substories_count")).as_u64()),
substories: try!(decode_array(try!(remove(&mut value, "substories")), Substory::decode)),
updated_at: try!(remove(&mut value, "updated_at").and_then(into_string)),
user: try!(remove(&mut value, "user").and_then(UserMini::decode)),
})
}
}
#[derive(Clone, Debug)]
pub struct Substory {
pub comment: Option<String>,
pub created_at: String,
pub episode_number: Option<u64>,
pub followed_user: Option<UserMini>,
pub id: u64,
pub kind: SubstoryType,
pub new_status: Option<LibraryStatus>,
}
impl Substory {
#[doc(hidden)]
pub fn decode(value: Value) -> Result<Substory> {
let mut value = try!(into_map(value));
Ok(Substory {
comment: try!(opt(&mut value, "comment", into_string)),
created_at: try!(remove(&mut value, "created_at").and_then(into_string)),
episode_number: remove(&mut value, "episode_number").ok().and_then(|v| v.as_u64()),
followed_user: try!(opt(&mut value, "followed_user", UserMini::decode)),
id: req!(try!(remove(&mut value, "id")).as_u64()),
kind: try!(remove(&mut value, "substory_type").and_then(SubstoryType::decode)),
new_status: try!(opt(&mut value, "new_status", LibraryStatus::decode)),
})
}
}
#[derive(Clone, Debug)]
pub struct UserMini {
pub avatar_small: String,
pub avatar: String,
pub name: String,
pub url: String,
}
impl UserMini {
#[doc(hidden)]
pub fn decode(value: Value) -> Result<UserMini> {
let mut value = try!(into_map(value));
Ok(UserMini {
avatar_small: try!(remove(&mut value, "avatar_small").and_then(into_string)),
avatar: try!(remove(&mut value, "avatar").and_then(into_string)),
name: try!(remove(&mut value, "name").and_then(into_string)),
url: try!(remove(&mut value, "url").and_then(into_string)),
})
}
}
#[derive(Clone, Debug)]
pub struct User {
pub avatar: String,
pub bio: String,
pub cover_image: String,
pub favorites: Vec<Favorite>,
pub last_library_update: String,
pub life_spent_on_anime: u64,
pub location: Option<String>,
pub name: String,
pub online: bool,
pub show_adult_content: bool,
pub title_language_preference: TitleLanguagePreference,
pub waifu_or_husbando: Option<RelationType>,
pub waifu_char_id: String,
pub waifu_slug: String,
pub waifu: Option<String>,
pub website: Option<String>,
}
impl User {
#[doc(hidden)]
pub fn decode(value: Value) -> Result<User> {
let mut value = try!(into_map(value));
Ok(User {
avatar: try!(remove(&mut value, "avatar").and_then(into_string)),
bio: try!(remove(&mut value, "bio").and_then(into_string)),
cover_image: try!(remove(&mut value, "cover_image").and_then(into_string)),
favorites: try!(decode_array(try!(remove(&mut value, "favorites")), Favorite::decode)),
last_library_update: try!(remove(&mut value, "last_library_update").and_then(into_string)),
life_spent_on_anime: req!(try!(remove(&mut value, "life_spent_on_anime")).as_u64()),
location: try!(opt(&mut value, "location", into_string)),
name: try!(remove(&mut value, "name").and_then(into_string)),
online: try!(opt(&mut value, "online", |v| Ok(req!(v.as_bool())))).unwrap_or(false),
show_adult_content: req!(try!(remove(&mut value, "show_adult_content")).as_bool()),
title_language_preference: try!(remove(&mut value, "title_language_preference").and_then(TitleLanguagePreference::decode)),
waifu_or_husbando: try!(opt(&mut value, "waifu_or_husbando", RelationType::decode)),
waifu_char_id: try!(remove(&mut value, "waifu_char_id").and_then(into_string)),
waifu_slug: try!(remove(&mut value, "waifu_slug").and_then(into_string)),
waifu: try!(opt(&mut value, "waifu", into_string)),
website: try!(opt(&mut value, "website", into_string)),
})
}
}