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 #[must_use]
64 pub fn new(name: impl Into<String>) -> Self {
65 Self {
66 name: name.into(),
67 ..Default::default()
68 }
69 }
70 #[must_use]
72 pub fn name(mut self, name: impl Into<String>) -> Self {
73 self.name = name.into();
74 self
75 }
76
77 #[must_use]
79 pub fn description(mut self, description: impl Into<String>) -> Self {
80 self.description = Some(description.into());
81 self
82 }
83
84 #[must_use]
86 pub fn external_docs(mut self, external_docs: ExternalDocs) -> Self {
87 self.external_docs = Some(external_docs);
88 self
89 }
90
91 #[must_use]
93 pub fn add_extension<K: Into<String>>(mut self, key: K, value: serde_json::Value) -> Self {
94 self.extensions.insert(key.into(), value);
95 self
96 }
97}
98
99#[cfg(test)]
100mod tests {
101 use super::{ExternalDocs, Tag};
102
103 #[test]
104 fn tag_new() {
105 let tag = Tag::new("tag name");
106 assert_eq!(tag.name, "tag name");
107 assert!(tag.description.is_none());
108 assert!(tag.external_docs.is_none());
109 assert!(tag.extensions.is_empty());
110
111 let tag = tag.name("new tag name");
112 assert_eq!(tag.name, "new tag name");
113
114 let tag = tag.description("description");
115 assert!(tag.description.is_some());
116
117 let tag = tag.external_docs(ExternalDocs::new(""));
118 assert!(tag.external_docs.is_some());
119 }
120
121 #[test]
122 fn from_string() {
123 let name = "tag name".to_owned();
124 let tag = Tag::from(name);
125 assert_eq!(tag.name, "tag name".to_owned());
126 }
127
128 #[test]
129 fn from_string_ref() {
130 let name = "tag name".to_owned();
131 let tag = Tag::from(&name);
132 assert_eq!(tag.name, "tag name".to_owned());
133 }
134
135 #[test]
136 fn from_str() {
137 let name = "tag name";
138 let tag = Tag::from(name);
139 assert_eq!(tag.name, "tag name");
140 }
141
142 #[test]
143 fn cmp() {
144 let tag1 = Tag::new("a");
145 let tag2 = Tag::new("b");
146
147 assert!(tag1 < tag2);
148 }
149}