1use futures_util::TryStreamExt;
3use serde_derive::Deserialize;
4
5use crate::prelude::*;
6use crate::types::id::{GameId, ModId};
7pub use crate::types::mods::MetadataMap;
8
9#[derive(Clone)]
10pub struct Metadata {
11 modio: Modio,
12 game: GameId,
13 mod_id: ModId,
14}
15
16impl Metadata {
17 pub(crate) fn new(modio: Modio, game: GameId, mod_id: ModId) -> Self {
18 Self {
19 modio,
20 game,
21 mod_id,
22 }
23 }
24
25 pub async fn get(self) -> Result<MetadataMap> {
27 #[derive(Deserialize)]
28 struct KV {
29 metakey: String,
30 metavalue: String,
31 }
32
33 let route = Route::GetModMetadata {
34 game_id: self.game,
35 mod_id: self.mod_id,
36 };
37 let filter = Filter::default();
38 let mut it = Query::<KV>::new(self.modio, route, filter).iter().await?;
39
40 let (size, _) = it.size_hint();
41 let mut map = MetadataMap::with_capacity(size);
42
43 while let Some(kv) = it.try_next().await? {
44 map.entry(kv.metakey).or_default().push(kv.metavalue);
45 }
46 Ok(map)
47 }
48
49 #[allow(clippy::should_implement_trait)]
51 pub async fn add(self, metadata: MetadataMap) -> Result<()> {
52 let route = Route::AddModMetadata {
53 game_id: self.game,
54 mod_id: self.mod_id,
55 };
56 self.modio
57 .request(route)
58 .form(&metadata)
59 .send::<Message>()
60 .await?;
61 Ok(())
62 }
63
64 pub async fn delete(self, metadata: MetadataMap) -> Result<Deletion> {
66 let route = Route::DeleteModMetadata {
67 game_id: self.game,
68 mod_id: self.mod_id,
69 };
70 self.modio.request(route).form(&metadata).send().await
71 }
72}
73
74#[doc(hidden)]
75impl serde::ser::Serialize for MetadataMap {
76 fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
77 where
78 S: serde::ser::Serializer,
79 {
80 use serde::ser::SerializeMap;
81
82 let len = self.values().map(|v| std::cmp::max(1, v.len())).sum();
83 let mut map = serializer.serialize_map(Some(len))?;
84 for (k, vals) in self.iter() {
85 if vals.is_empty() {
86 map.serialize_entry("metadata[]", k)?;
87 }
88 for v in vals {
89 map.serialize_entry("metadata[]", &format!("{k}:{v}"))?;
90 }
91 }
92 map.end()
93 }
94}