salvo_oapi/openapi/
tag.rs1use std::cmp::Ordering;
5
6use serde::{Deserialize, Serialize};
7
8use super::external_docs::ExternalDocs;
9use crate::PropMap;
10
11#[non_exhaustive]
17#[derive(Serialize, Deserialize, Default, Clone, Debug, PartialEq, Eq)]
18#[serde(rename_all = "camelCase")]
19pub struct Tag {
20 pub name: String,
22
23 #[serde(skip_serializing_if = "Option::is_none")]
25 pub description: Option<String>,
26
27 #[serde(skip_serializing_if = "Option::is_none")]
29 pub external_docs: Option<ExternalDocs>,
30
31 #[serde(skip_serializing_if = "PropMap::is_empty", flatten)]
33 pub extensions: PropMap<String, serde_json::Value>,
34}
35impl Ord for Tag {
36 fn cmp(&self, other: &Self) -> Ordering {
37 self.name.cmp(&other.name)
38 }
39}
40impl PartialOrd for Tag {
41 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
42 Some(self.cmp(other))
43 }
44}
45impl From<String> for Tag {
46 fn from(name: String) -> Self {
47 Self::new(name)
48 }
49}
50impl From<&String> for Tag {
51 fn from(name: &String) -> Self {
52 Self::new(name)
53 }
54}
55impl<'a> From<&'a str> for Tag {
56 fn from(name: &'a str) -> Self {
57 Self::new(name.to_owned())
58 }
59}
60
61impl Tag {
62 pub fn new(name: impl Into<String>) -> Self {
64 Self {
65 name: name.into(),
66 ..Default::default()
67 }
68 }
69 pub fn name(mut self, name: impl Into<String>) -> Self {
71 self.name = name.into();
72 self
73 }
74
75 pub fn description(mut self, description: impl Into<String>) -> Self {
77 self.description = Some(description.into());
78 self
79 }
80
81 pub fn external_docs(mut self, external_docs: ExternalDocs) -> Self {
83 self.external_docs = Some(external_docs);
84 self
85 }
86
87 pub fn add_extension<K: Into<String>>(mut self, key: K, value: serde_json::Value) -> Self {
89 self.extensions.insert(key.into(), value);
90 self
91 }
92}
93
94#[cfg(test)]
95mod tests {
96 use super::ExternalDocs;
97 use super::Tag;
98
99 #[test]
100 fn tag_new() {
101 let tag = Tag::new("tag name");
102 assert_eq!(tag.name, "tag name");
103 assert!(tag.description.is_none());
104 assert!(tag.external_docs.is_none());
105 assert!(tag.extensions.is_empty());
106
107 let tag = tag.name("new tag name");
108 assert_eq!(tag.name, "new tag name");
109
110 let tag = tag.description("description");
111 assert!(tag.description.is_some());
112
113 let tag = tag.external_docs(ExternalDocs::new(""));
114 assert!(tag.external_docs.is_some());
115 }
116
117 #[test]
118 fn from_string() {
119 let name = "tag name".to_string();
120 let tag = Tag::from(name);
121 assert_eq!(tag.name, "tag name".to_string());
122 }
123
124 #[test]
125 fn from_string_ref() {
126 let name = "tag name".to_string();
127 let tag = Tag::from(&name);
128 assert_eq!(tag.name, "tag name".to_string());
129 }
130
131 #[test]
132 fn from_str() {
133 let name = "tag name";
134 let tag = Tag::from(name);
135 assert_eq!(tag.name, "tag name");
136 }
137
138 #[test]
139 fn cmp() {
140 let tag1 = Tag::new("a");
141 let tag2 = Tag::new("b");
142
143 assert!(tag1 < tag2);
144 }
145}