1use am_api_proc_macro::Context;
3
4use serde::{Deserialize, Serialize};
5
6pub mod artwork;
7pub mod attributes;
8pub mod catalog;
9pub mod genre;
10pub mod history;
11pub mod library;
12pub mod personal_recommendation;
13pub mod rating;
14pub mod relationship;
15pub mod search;
16pub mod storefront;
17pub mod view;
18
19#[derive(Serialize, Deserialize, Default, Debug, Clone, PartialEq, Eq, Hash)]
21#[serde(rename_all = "camelCase", default)]
22pub struct ResourceHeader {
23 pub id: String,
25 pub href: String,
27}
28
29pub trait ResourceInfo {
31 fn get_header(&self) -> &ResourceHeader;
33}
34
35pub(crate) trait ResourceType {
37 fn get_type(&self) -> &'static str;
39}
40
41macro_rules! resource {
42 ($($name:literal => $enum_name:ident : $data_type:path),*) => {
43 #[derive(Context, Serialize, Deserialize, Debug, Clone, PartialEq, Eq, Hash)]
45 #[serde(tag = "type")]
46 pub enum Resource {
47 $(
48 #[doc = $name]
49 #[serde(rename = $name)]
50 $enum_name {
51 #[serde(flatten)]
53 data: $data_type
54 }
55 ),*
56 }
57
58 impl ResourceInfo for Resource {
59 fn get_header(&self) -> &ResourceHeader {
60 match self {
61 $(Self::$enum_name { data } => &data.header),*
62 }
63 }
64 }
65
66 impl ResourceType for Resource {
67 fn get_type(&self) -> &'static str {
68 match self {
69 $(Self::$enum_name { .. } => $name),*
70 }
71 }
72 }
73
74 $(
75 impl From<$data_type> for Resource {
76 fn from(data: $data_type) -> Self {
77 Self::$enum_name { data }
78 }
79 }
80 )*
81 }
82}
83
84resource! {
85 "activities" => Activity : catalog::activity::Activity,
86 "albums" => Album : catalog::album::Album,
87 "artists" => Artist : catalog::artist::Artist,
88 "apple-curators" => AppleCurator : catalog::curator::AppleCurator,
89 "curators" => Curator : catalog::curator::Curator,
90 "genres" => Genre : genre::Genre,
91 "music-videos" => MusicVideo : catalog::music_video::MusicVideo,
92 "personal-recommendation" => PersonalRecommendation : personal_recommendation::PersonalRecommendation,
93 "playlists" => Playlist : catalog::playlist::Playlist,
94 "ratings" => Rating : rating::Rating,
95 "record-labels" => RecordLabel : catalog::record_label::RecordLabel,
96 "songs" => Song : catalog::song::Song,
97 "stations" => Station : catalog::station::Station,
98 "station-genres" => StationGenre : catalog::station::StationGenre,
99 "library-albums" => LibraryAlbum : library::album::LibraryAlbum,
100 "library-artists" => LibraryArtist : library::artist::LibraryArtist,
101 "library-music-videos" => LibraryMusicVideo : library::music_video::LibraryMusicVideo,
102 "library-playlists" => LibraryPlaylist : library::playlist::LibraryPlaylist,
103 "library-playlist-folders" => LibraryPlaylistFolder : library::playlist::LibraryPlaylistFolder,
104 "library-songs" => LibrarySong : library::song::LibrarySong
105}
106
107#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, Hash)]
109#[serde(rename_all = "camelCase")]
110pub struct ResourceResponse<R = Resource> {
111 pub data: Vec<R>,
113}
114
115#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, Hash)]
117#[serde(rename_all = "camelCase")]
118pub struct ErrorResponse {
119 #[serde(default)]
121 pub code: Option<i32>,
122 #[serde(default)]
124 pub message: Option<String>,
125 #[serde(default)]
127 pub errors: Vec<MusicError>,
128}
129
130#[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq, Eq, Hash)]
132#[serde(rename_all = "camelCase", default)]
133pub struct MusicError {
134 pub id: String,
136 pub title: String,
138 pub detail: String,
140 pub status: String,
142 pub code: String,
144}