r402_core/extensions/
bazaar.rs1#![cfg(feature = "ext-bazaar")]
25#![cfg_attr(docsrs, doc(cfg(feature = "ext-bazaar")))]
26
27use compact_str::CompactString;
28use serde_json::Value;
29
30use super::{AdvertiseContext, Extension};
31use crate::wire::ExtensionEntry;
32
33#[derive(Debug, Clone, Default)]
35pub struct BazaarExtension {
36 pub catalog: Option<CompactString>,
38 pub categories: Vec<CompactString>,
40 pub registered: bool,
43}
44
45impl BazaarExtension {
46 #[must_use]
48 pub fn new() -> Self {
49 Self::default()
50 }
51
52 #[must_use]
54 pub fn with_catalog(mut self, catalog: impl Into<CompactString>) -> Self {
55 self.catalog = Some(catalog.into());
56 self
57 }
58
59 #[must_use]
61 pub fn with_category(mut self, category: impl Into<CompactString>) -> Self {
62 self.categories.push(category.into());
63 self
64 }
65
66 #[must_use]
68 pub const fn registered(mut self) -> Self {
69 self.registered = true;
70 self
71 }
72}
73
74impl Extension for BazaarExtension {
75 fn id(&self) -> &'static str {
76 "bazaar"
77 }
78
79 fn advertise(&self, _ctx: &AdvertiseContext<'_>) -> Option<ExtensionEntry> {
80 let mut info = serde_json::Map::new();
81 if let Some(catalog) = &self.catalog {
82 let _ = info.insert("catalog".to_owned(), Value::String(catalog.to_string()));
83 }
84 if !self.categories.is_empty() {
85 let cats: Vec<Value> = self
86 .categories
87 .iter()
88 .map(|c| Value::String(c.to_string()))
89 .collect();
90 let _ = info.insert("categories".to_owned(), Value::Array(cats));
91 }
92 let _ = info.insert("registered".to_owned(), Value::Bool(self.registered));
93 Some(ExtensionEntry::info(Value::Object(info)))
94 }
95}
96
97#[cfg(test)]
98mod tests {
99 use serde_json::json;
100
101 use super::*;
102
103 #[test]
104 fn advertise_includes_catalog_and_categories() {
105 let ext = BazaarExtension::new()
106 .with_catalog("https://example.com/catalog")
107 .with_category("data")
108 .with_category("api")
109 .registered();
110 let ctx = AdvertiseContext { requirement: None };
111 let entry = ext.advertise(&ctx).unwrap();
112 let info = entry.as_info().unwrap();
113 assert_eq!(info["catalog"], "https://example.com/catalog");
114 assert_eq!(info["registered"], true);
115 assert_eq!(info["categories"], json!(["data", "api"]));
116 }
117
118 #[test]
119 fn advertise_minimal_emits_registered_flag() {
120 let ext = BazaarExtension::new();
121 let ctx = AdvertiseContext { requirement: None };
122 let entry = ext.advertise(&ctx).unwrap();
123 let info = entry.as_info().unwrap();
124 assert_eq!(info["registered"], false);
125 assert!(info.get("catalog").is_none());
126 }
127}