modio/
metadata.rs

1//! Mod metadata KVP interface
2use 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    /// Return the metadata key value pairs for a mod that this `Metadata` refers to.
26    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    /// Add metadata for a mod that this `Metadata` refers to.
50    #[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    /// Delete metadata for a mod that this `Metadata` refers to.
65    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}