1use once_cell::sync::Lazy;
2use serde::{Deserialize, Serialize};
3use serde_json::Value;
4use std::collections::HashMap;
5use std::fmt;
6
7#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
9pub struct ProtocolCapabilities {
10 #[serde(flatten)]
11 pub fields: HashMap<String, Value>,
12}
13
14impl Default for ProtocolCapabilities {
15 fn default() -> Self {
16 Self::new()
17 }
18}
19
20impl ProtocolCapabilities {
21 pub fn new() -> Self {
23 Self {
24 fields: HashMap::new(),
25 }
26 }
27
28 pub fn with_fields(fields: HashMap<String, Value>) -> Self {
30 Self { fields }
31 }
32
33 pub fn set<K: Into<String>, V: Into<Value>>(&mut self, key: K, value: V) {
35 self.fields.insert(key.into(), value.into());
36 }
37
38 pub fn get(&self, key: &str) -> Option<&Value> {
40 self.fields.get(key)
41 }
42
43 pub fn has(&self, key: &str) -> bool {
45 self.fields.contains_key(key)
46 }
47
48 pub fn remove(&mut self, key: &str) -> Option<Value> {
50 self.fields.remove(key)
51 }
52
53 pub fn is_empty(&self) -> bool {
55 self.fields.is_empty()
56 }
57
58 pub fn fields(&self) -> &HashMap<String, Value> {
60 &self.fields
61 }
62
63 pub fn to_hashmap(&self) -> Option<HashMap<String, serde_json::Value>> {
65 if self.is_empty() {
66 None
67 } else {
68 Some(self.fields.clone())
69 }
70 }
71
72 pub fn to_option(self) -> Option<Self> {
74 if self.is_empty() {
75 None
76 } else {
77 Some(self)
78 }
79 }
80
81 pub fn from_hashmap(map: Option<HashMap<String, serde_json::Value>>) -> Self {
83 map.map(|fields| Self { fields }).unwrap_or_default()
84 }
85}
86
87impl From<HashMap<String, Value>> for ProtocolCapabilities {
88 fn from(fields: HashMap<String, Value>) -> Self {
89 Self { fields }
90 }
91}
92
93impl fmt::Display for ProtocolCapabilities {
94 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
95 if self.is_empty() {
96 write!(f, "No capabilities")
97 } else {
98 write!(
99 f,
100 "Capabilities: {:?}",
101 self.fields.keys().collect::<Vec<_>>()
102 )
103 }
104 }
105}
106
107#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
109pub struct ServerInfo {
110 pub name: String,
111 pub version: String,
112 #[serde(skip_serializing_if = "Option::is_none")]
113 pub protocol_version: Option<String>,
114 #[serde(skip_serializing_if = "Option::is_none")]
115 pub capabilities: Option<ProtocolCapabilities>,
116}
117
118impl ServerInfo {
119 pub fn new(name: impl Into<String>, version: impl Into<String>) -> Self {
121 Self {
122 name: name.into(),
123 version: version.into(),
124 protocol_version: None,
125 capabilities: None,
126 }
127 }
128
129 pub fn with_protocol_version(mut self, version: impl Into<String>) -> Self {
131 self.protocol_version = Some(version.into());
132 self
133 }
134
135 pub fn with_capabilities(mut self, capabilities: ProtocolCapabilities) -> Self {
137 self.capabilities = Some(capabilities);
138 self
139 }
140
141 pub fn capabilities_mut(&mut self) -> &mut ProtocolCapabilities {
143 self.capabilities
144 .get_or_insert_with(ProtocolCapabilities::new)
145 }
146}
147
148impl fmt::Display for ServerInfo {
149 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
150 write!(f, "{} v{}", self.name, self.version)?;
151 if let Some(proto) = &self.protocol_version {
152 write!(f, " (protocol: {})", proto)?;
153 }
154 Ok(())
155 }
156}
157
158#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
160pub struct ClientInfo {
161 pub name: String,
162 pub version: String,
163 #[serde(skip_serializing_if = "Option::is_none")]
164 pub protocol_version: Option<String>,
165 #[serde(skip_serializing_if = "Option::is_none")]
166 pub capabilities: Option<ProtocolCapabilities>,
167}
168
169impl ClientInfo {
170 pub fn new(name: impl Into<String>, version: impl Into<String>) -> Self {
172 Self {
173 name: name.into(),
174 version: version.into(),
175 protocol_version: None,
176 capabilities: None,
177 }
178 }
179
180 pub fn capabilities_to_hashmap(&self) -> Option<HashMap<String, serde_json::Value>> {
182 self.capabilities.as_ref().and_then(|c| c.to_hashmap())
183 }
184
185 pub fn with_protocol_version(mut self, version: impl Into<String>) -> Self {
187 self.protocol_version = Some(version.into());
188 self
189 }
190
191 pub fn with_capabilities(mut self, capabilities: ProtocolCapabilities) -> Self {
193 self.capabilities = Some(capabilities);
194 self
195 }
196
197 pub fn with_capabilities_hashmap(
199 mut self,
200 capabilities: Option<HashMap<String, serde_json::Value>>,
201 ) -> Self {
202 self.capabilities = capabilities.map(|fields| ProtocolCapabilities { fields });
203 self
204 }
205
206 pub fn capabilities_mut(&mut self) -> &mut ProtocolCapabilities {
208 self.capabilities
209 .get_or_insert_with(ProtocolCapabilities::new)
210 }
211}
212
213impl fmt::Display for ClientInfo {
214 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
215 write!(f, "{} v{}", self.name, self.version)?;
216 if let Some(proto) = &self.protocol_version {
217 write!(f, " (protocol: {})", proto)?;
218 }
219 Ok(())
220 }
221}
222
223pub static DEFAULT_PROTOCOL_VERSION: Lazy<String> = Lazy::new(|| "2024-11-05".to_string());
228
229pub fn default_protocol_version() -> String {
231 DEFAULT_PROTOCOL_VERSION.clone()
232}
233
234pub struct MetadataBuilder {
236 name: String,
237 version: String,
238 protocol_version: Option<String>,
239 capabilities: Option<ProtocolCapabilities>,
240}
241
242impl MetadataBuilder {
243 pub fn new(name: impl Into<String>, version: impl Into<String>) -> Self {
245 Self {
246 name: name.into(),
247 version: version.into(),
248 protocol_version: None,
249 capabilities: None,
250 }
251 }
252
253 pub fn protocol_version(mut self, version: impl Into<String>) -> Self {
255 self.protocol_version = Some(version.into());
256 self
257 }
258
259 pub fn capabilities(mut self, capabilities: ProtocolCapabilities) -> Self {
261 self.capabilities = Some(capabilities);
262 self
263 }
264
265 pub fn capability<K: Into<String>, V: Into<Value>>(mut self, key: K, value: V) -> Self {
267 let caps = self
268 .capabilities
269 .get_or_insert_with(ProtocolCapabilities::new);
270 caps.set(key, value);
271 self
272 }
273
274 pub fn build_server(self) -> ServerInfo {
276 ServerInfo {
277 name: self.name,
278 version: self.version,
279 protocol_version: self.protocol_version,
280 capabilities: self.capabilities,
281 }
282 }
283
284 pub fn build_client(self) -> ClientInfo {
286 ClientInfo {
287 name: self.name,
288 version: self.version,
289 protocol_version: self.protocol_version,
290 capabilities: self.capabilities,
291 }
292 }
293}
294
295#[cfg(test)]
296mod tests {
297 use super::*;
298 use crate::protocol::types::Implementation;
299
300 #[test]
301 fn test_protocol_capabilities() {
302 let mut caps = ProtocolCapabilities::new();
303 assert!(caps.is_empty());
304
305 caps.set("feature1", true);
306 caps.set("feature2", "value");
307 caps.set("feature3", 42);
308
309 assert!(caps.has("feature1"));
310 assert_eq!(
311 caps.get("feature2"),
312 Some(&Value::String("value".to_string()))
313 );
314 assert_eq!(caps.get("feature3"), Some(&Value::Number(42.into())));
315
316 let removed = caps.remove("feature1");
317 assert_eq!(removed, Some(Value::Bool(true)));
318 assert!(!caps.has("feature1"));
319 }
320
321 #[test]
322 fn test_server_info() {
323 let server = ServerInfo::new("test-server", "1.0.0").with_protocol_version("2024-11-05");
324
325 assert_eq!(server.name, "test-server");
326 assert_eq!(server.version, "1.0.0");
327 assert_eq!(server.protocol_version, Some("2024-11-05".to_string()));
328 assert_eq!(
329 server.to_string(),
330 "test-server v1.0.0 (protocol: 2024-11-05)"
331 );
332 }
333
334 #[test]
335 fn test_client_info() {
336 let mut client = ClientInfo::new("test-client", "2.0.0");
337 let caps = client.capabilities_mut();
338 caps.set("feature", true);
339
340 assert_eq!(client.name, "test-client");
341 assert_eq!(client.version, "2.0.0");
342 assert!(client.capabilities.as_ref().unwrap().has("feature"));
343 }
344
345 #[test]
346 fn test_implementation() {
347 let impl_info = Implementation::new("custom-impl", "3.0.0");
348 assert_eq!(impl_info.name, "custom-impl");
349 assert_eq!(impl_info.version, "3.0.0");
350 assert_eq!(impl_info.title, None);
351
352 let impl_with_title = Implementation::with_title("my-impl", "2.0.0", "My Implementation");
353 assert_eq!(impl_with_title.name, "my-impl");
354 assert_eq!(impl_with_title.version, "2.0.0");
355 assert_eq!(impl_with_title.title, Some("My Implementation".to_string()));
356 }
357
358 #[test]
359 fn test_metadata_builder() {
360 let server = MetadataBuilder::new("builder-test", "1.0.0")
361 .protocol_version("2024-11-05")
362 .capability("feature1", true)
363 .capability("feature2", "enabled")
364 .build_server();
365
366 assert_eq!(server.name, "builder-test");
367 assert_eq!(server.version, "1.0.0");
368 assert_eq!(server.protocol_version, Some("2024-11-05".to_string()));
369 assert!(server.capabilities.as_ref().unwrap().has("feature1"));
370 assert!(server.capabilities.as_ref().unwrap().has("feature2"));
371 }
372
373 #[test]
374 fn test_capabilities_serialization() {
375 let mut caps = ProtocolCapabilities::new();
376 caps.set("test", true);
377
378 let json = serde_json::to_string(&caps).unwrap();
379 let deserialized: ProtocolCapabilities = serde_json::from_str(&json).unwrap();
380
381 assert_eq!(caps, deserialized);
382 }
383
384 #[test]
385 fn test_empty_capabilities_to_option() {
386 let caps = ProtocolCapabilities::new();
387 assert_eq!(caps.to_option(), None);
388
389 let mut caps = ProtocolCapabilities::new();
390 caps.set("feature", true);
391 assert!(caps.to_option().is_some());
392 }
393
394 #[test]
395 fn test_capabilities_from_hashmap() {
396 let mut map = HashMap::new();
397 map.insert("key1".to_string(), Value::Bool(true));
398 map.insert("key2".to_string(), Value::String("value".to_string()));
399
400 let caps = ProtocolCapabilities::from_hashmap(Some(map.clone()));
401 assert_eq!(caps.fields, map);
402
403 let empty_caps = ProtocolCapabilities::from_hashmap(None);
404 assert!(empty_caps.is_empty());
405 }
406}