use serde::{Deserialize, Serialize};
use serde_json::Value;
use super::content::Content;
use super::protocol::Cursor;
use super::protocol::RequestMeta;
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct ListResourcesRequest {
#[serde(skip_serializing_if = "Option::is_none")]
pub cursor: Cursor,
}
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
#[non_exhaustive]
#[serde(rename_all = "camelCase")]
pub struct ResourceInfo {
pub uri: String,
pub name: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub title: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub description: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub mime_type: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub icons: Option<Vec<super::protocol::IconInfo>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub annotations: Option<crate::types::content::Annotations>,
#[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
pub meta: Option<serde_json::Map<String, Value>>,
}
impl ResourceInfo {
pub fn new(uri: impl Into<String>, name: impl Into<String>) -> Self {
Self {
uri: uri.into(),
name: name.into(),
title: None,
description: None,
mime_type: None,
icons: None,
annotations: None,
meta: None,
}
}
pub fn with_title(mut self, title: impl Into<String>) -> Self {
self.title = Some(title.into());
self
}
pub fn with_description(mut self, description: impl Into<String>) -> Self {
self.description = Some(description.into());
self
}
pub fn with_mime_type(mut self, mime_type: impl Into<String>) -> Self {
self.mime_type = Some(mime_type.into());
self
}
pub fn with_icons(mut self, icons: Vec<super::protocol::IconInfo>) -> Self {
self.icons = Some(icons);
self
}
pub fn with_annotations(mut self, annotations: crate::types::content::Annotations) -> Self {
self.annotations = Some(annotations);
self
}
pub fn with_meta(mut self, meta: serde_json::Map<String, Value>) -> Self {
self.meta = Some(meta);
self
}
}
#[non_exhaustive]
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct ListResourcesResult {
pub resources: Vec<ResourceInfo>,
#[serde(skip_serializing_if = "Option::is_none")]
pub next_cursor: Cursor,
}
impl ListResourcesResult {
pub fn new(resources: Vec<ResourceInfo>) -> Self {
Self {
resources,
next_cursor: None,
}
}
pub fn with_next_cursor(mut self, cursor: impl Into<String>) -> Self {
self.next_cursor = Some(cursor.into());
self
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct ReadResourceRequest {
pub uri: String,
#[serde(skip_serializing_if = "Option::is_none")]
#[allow(clippy::pub_underscore_fields)] pub _meta: Option<RequestMeta>,
}
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct ListResourceTemplatesRequest {
#[serde(skip_serializing_if = "Option::is_none")]
pub cursor: Cursor,
}
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
#[non_exhaustive]
#[serde(rename_all = "camelCase")]
pub struct ResourceTemplate {
pub uri_template: String,
pub name: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub title: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub description: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub mime_type: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub icons: Option<Vec<super::protocol::IconInfo>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub annotations: Option<crate::types::content::Annotations>,
#[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
pub meta: Option<serde_json::Map<String, Value>>,
}
impl ResourceTemplate {
pub fn new(uri_template: impl Into<String>, name: impl Into<String>) -> Self {
Self {
uri_template: uri_template.into(),
name: name.into(),
title: None,
description: None,
mime_type: None,
icons: None,
annotations: None,
meta: None,
}
}
pub fn with_title(mut self, title: impl Into<String>) -> Self {
self.title = Some(title.into());
self
}
pub fn with_description(mut self, description: impl Into<String>) -> Self {
self.description = Some(description.into());
self
}
pub fn with_mime_type(mut self, mime_type: impl Into<String>) -> Self {
self.mime_type = Some(mime_type.into());
self
}
pub fn with_icons(mut self, icons: Vec<super::protocol::IconInfo>) -> Self {
self.icons = Some(icons);
self
}
pub fn with_annotations(mut self, annotations: crate::types::content::Annotations) -> Self {
self.annotations = Some(annotations);
self
}
pub fn with_meta(mut self, meta: serde_json::Map<String, Value>) -> Self {
self.meta = Some(meta);
self
}
}
#[non_exhaustive]
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct ListResourceTemplatesResult {
pub resource_templates: Vec<ResourceTemplate>,
#[serde(skip_serializing_if = "Option::is_none")]
pub next_cursor: Cursor,
}
impl ListResourceTemplatesResult {
pub fn new(resource_templates: Vec<ResourceTemplate>) -> Self {
Self {
resource_templates,
next_cursor: None,
}
}
pub fn with_next_cursor(mut self, cursor: impl Into<String>) -> Self {
self.next_cursor = Some(cursor.into());
self
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct SubscribeRequest {
pub uri: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct UnsubscribeRequest {
pub uri: String,
}
#[non_exhaustive]
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct ReadResourceResult {
#[serde(
serialize_with = "crate::types::content::resource_contents_serde::serialize",
deserialize_with = "crate::types::content::resource_contents_serde::deserialize"
)]
pub contents: Vec<Content>,
}
impl ReadResourceResult {
pub fn new(contents: Vec<Content>) -> Self {
Self { contents }
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_resource_types() {
let resource = ResourceInfo::new("file://test.txt", "test.txt")
.with_description("Test file")
.with_mime_type("text/plain");
let json = serde_json::to_value(&resource).unwrap();
assert_eq!(json["uri"], "file://test.txt");
assert_eq!(json["name"], "test.txt");
assert_eq!(json["description"], "Test file");
assert_eq!(json["mimeType"], "text/plain");
}
#[test]
fn test_resource_info_default() {
let resource = ResourceInfo::default();
assert!(resource.uri.is_empty());
assert!(resource.name.is_empty());
assert!(resource.description.is_none());
}
#[test]
fn test_resource_template_new() {
let template = ResourceTemplate::new("file://{path}", "File Template")
.with_description("Access files by path")
.with_mime_type("text/plain");
let json = serde_json::to_value(&template).unwrap();
assert_eq!(json["uriTemplate"], "file://{path}");
assert_eq!(json["name"], "File Template");
assert_eq!(json["description"], "Access files by path");
assert_eq!(json["mimeType"], "text/plain");
}
}