kmp_memory_api/
api_capabilities.rs1use std::collections::BTreeSet;
2
3use serde::{Deserialize, Serialize};
4
5#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
12pub struct ApiCapabilities {
13 contract_version: u32,
14 library_version: String,
15 capabilities: BTreeSet<String>,
16}
17
18impl ApiCapabilities {
19 pub fn new(
20 contract_version: u32,
21 library_version: impl Into<String>,
22 capabilities: impl IntoIterator<Item = impl Into<String>>,
23 ) -> Self {
24 Self {
25 contract_version,
26 library_version: library_version.into(),
27 capabilities: capabilities.into_iter().map(Into::into).collect(),
28 }
29 }
30
31 pub fn contract_version(&self) -> u32 {
32 self.contract_version
33 }
34
35 pub fn library_version(&self) -> &str {
36 &self.library_version
37 }
38
39 pub fn supports(&self, capability: &str) -> bool {
40 self.capabilities.contains(capability)
41 }
42
43 pub fn capabilities(&self) -> impl Iterator<Item = &str> {
44 self.capabilities.iter().map(String::as_str)
45 }
46}
47
48#[cfg(test)]
49mod tests {
50 use super::*;
51
52 #[test]
53 fn a_report_names_its_contract_its_release_and_what_it_can_do() {
54 let report = ApiCapabilities::new(1, "0.1.0", ["wake", "ask"]);
55 assert_eq!(report.contract_version(), 1);
56 assert_eq!(report.library_version(), "0.1.0");
57 assert!(report.supports("wake"));
58 assert!(
59 !report.supports("forget"),
60 "a capability nobody declared must read as absent, not assumed"
61 );
62 }
63
64 #[test]
65 fn a_report_survives_the_wire() {
66 let report = ApiCapabilities::new(1, "0.1.0", ["wake"]);
67 let bytes = serde_json::to_vec(&report).expect("serializes");
68 assert_eq!(
69 serde_json::from_slice::<ApiCapabilities>(&bytes).expect("deserializes"),
70 report
71 );
72 }
73}