rust_anilist/models/relation.rs
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2022-2025 Andriel Ferreira <https://github.com/AndrielFR>
3
4//! This module contains the `Relation` struct and its related types.
5
6use serde::{Deserialize, Serialize};
7use serde_json::Value;
8
9use super::{Anime, Cover, Format, Manga, Media, Status, Title};
10
11/// Represents a relation between different media types.
12///
13/// The `Relation` struct contains information about the relationship
14/// between different media types, such as anime and manga, including
15/// the related media, relation ID, relation type, and whether it is
16/// the main studio.
17///
18/// # Fields
19///
20/// * `id` - The ID of the relation.
21/// * `relation_type` - The type of relation (e.g., adaptation, sequel).
22/// * `is_main_studio` - Whether the relation is the main studio.
23#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
24#[serde(rename_all(deserialize = "camelCase"))]
25pub struct Relation {
26 /// The related media.
27 pub(crate) node: Value,
28 /// The ID of the relation.
29 pub id: i64,
30 /// The type of relation (e.g., adaptation, sequel).
31 pub relation_type: RelationType,
32 /// Whether the relation is the main studio.
33 pub is_main_studio: bool,
34}
35
36impl Relation {
37 /// Returns the related media.
38 pub fn media(&self) -> Media {
39 let media = self.node.clone();
40
41 match self.node["type"].as_str() {
42 Some("ANIME") => Media::Anime(Anime {
43 id: media["id"].as_i64().unwrap(),
44 id_mal: media["idMal"].as_i64(),
45 title: Title::deserialize(&media["title"]).unwrap(),
46 format: Format::deserialize(&media["format"]).unwrap(),
47 status: Status::deserialize(&media["status"]).unwrap(),
48 description: media["description"].as_str().unwrap().to_string(),
49 cover: Cover::deserialize(&media["coverImage"]).unwrap(),
50 banner: media["bannerImage"].as_str().map(String::from),
51 average_score: media["averageScore"].as_u64().map(|x| x as u8),
52 mean_score: media["meanScore"].as_u64().map(|x| x as u8),
53 url: media["siteUrl"].as_str().unwrap().to_string(),
54
55 ..Default::default()
56 }),
57 Some("MANGA") => Media::Manga(Manga {
58 id: media["id"].as_i64().unwrap(),
59 id_mal: media["idMal"].as_i64(),
60 title: Title::deserialize(&media["title"]).unwrap(),
61 format: Format::deserialize(&media["format"]).unwrap(),
62 status: Status::deserialize(&media["status"]).unwrap(),
63 description: media["description"].as_str().unwrap().to_string(),
64 cover: Cover::deserialize(&media["coverImage"]).unwrap(),
65 banner: media["bannerImage"].as_str().map(String::from),
66 average_score: media["averageScore"].as_u64().map(|x| x as u8),
67 mean_score: media["meanScore"].as_u64().map(|x| x as u8),
68 url: media["siteUrl"].as_str().unwrap().to_string(),
69
70 ..Default::default()
71 }),
72 _ => Media::Unknown,
73 }
74 }
75}
76
77/// Represents the type of relation between different media.
78///
79/// The `RelationType` enum defines various types of relationships that
80/// can exist between different media, such as adaptations, sequels,
81/// prequels, and more.
82///
83/// # Variants
84///
85/// * `Adaptation` - The media is an adaptation of another work.
86/// * `Prequel` - The media is a prequel to another work.
87/// * `Sequel` - The media is a sequel to another work.
88/// * `Parent` - The media is a parent story to another work.
89/// * `SideStory` - The media is a side story to another work.
90/// * `Character` - The media shares characters with another work.
91/// * `Summary` - The media is a summary of another work.
92/// * `Alternative` - The media is an alternative version of another work.
93/// * `SpinOff` - The media is a spin-off of another work.
94/// * `Other` - The media has some other type of relation to another work.
95/// * `Source` - The media is the source material for another work.
96/// * `Compilation` - The media is a compilation of another work.
97/// * `Contains` - The media contains another work.
98#[derive(Debug, Default, Clone, Eq, Hash, PartialEq, Deserialize, Serialize)]
99#[serde(rename_all(deserialize = "SCREAMING_SNAKE_CASE"))]
100pub enum RelationType {
101 /// The media is an adaptation of another work.
102 Adaptation,
103 /// The media is a prequel to another work.
104 Prequel,
105 /// The media is a sequel to another work.
106 Sequel,
107 /// The media is a parent story to another work.
108 Parent,
109 /// The media is a side story to another work.
110 SideStory,
111 /// The media shares characters with another work.
112 Character,
113 /// The media is a summary of another work.
114 Summary,
115 /// The media is an alternative version of another work.
116 Alternative,
117 /// The media is a spin-off of another work.
118 SpinOff,
119 /// The media has some other type of relation to another work.
120 #[default]
121 Other,
122 /// The media is the source material for another work.
123 Source,
124 /// The media is a compilation of another work.
125 Compilation,
126 /// The media contains another work.
127 Contains,
128}
129
130impl RelationType {
131 /// Returns a summary of the relation type.
132 pub fn summary(&self) -> &str {
133 match self {
134 RelationType::Adaptation => "An adaption of this media into a different format",
135 RelationType::Prequel => "Released before the relation",
136 RelationType::Sequel => "Released after the relation",
137 RelationType::Parent => "The media a side story is from",
138 RelationType::SideStory => "A side story of the parent media",
139 RelationType::Character => "Shares at least 1 character",
140 RelationType::Summary => "A shortened and summarized version",
141 RelationType::Alternative => "An alternative version of the same media",
142 RelationType::SpinOff => {
143 "An alternative version of the media with a different primary focus"
144 }
145 RelationType::Other => "Other",
146 RelationType::Source => "The source material the media was adapted from",
147 RelationType::Compilation => "A compilation of the media",
148 RelationType::Contains => "A media that contains the relation",
149 }
150 }
151}