use serde::{Deserialize, Serialize};
use std::{
cmp::Ordering,
collections::{BTreeMap, BTreeSet},
ops::{Deref, DerefMut},
};
#[derive(Serialize, Deserialize, Default, Clone, PartialEq)]
#[cfg_attr(feature = "debug", derive(Debug))]
pub struct Servers(pub BTreeSet<Server>);
impl Deref for Servers {
type Target = BTreeSet<Server>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl DerefMut for Servers {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
impl IntoIterator for Servers {
type Item = Server;
type IntoIter = <BTreeSet<Server> as IntoIterator>::IntoIter;
fn into_iter(self) -> Self::IntoIter {
self.0.into_iter()
}
}
impl Servers {
pub fn new() -> Self {
Default::default()
}
pub fn is_empty(&self) -> bool {
self.0.is_empty()
}
pub fn server<S: Into<Server>>(mut self, server: S) -> Self {
self.insert(server);
self
}
pub fn insert<S: Into<Server>>(&mut self, server: S) {
let server = server.into();
let exist_server = self.0.iter().find(|s| s.url == server.url).cloned();
if let Some(mut exist_server) = exist_server {
let Server {
description,
mut variables,
..
} = server;
exist_server.variables.append(&mut variables);
if description.is_some() {
exist_server.description = description;
}
self.0.remove(&exist_server);
self.0.insert(exist_server);
} else {
self.0.insert(server);
}
}
pub fn append(&mut self, other: &mut Servers) {
let servers = std::mem::take(&mut other.0);
for server in servers {
self.insert(server);
}
}
pub fn extend<I>(&mut self, iter: I)
where
I: IntoIterator<Item = Server>,
{
for server in iter.into_iter() {
self.insert(server);
}
}
}
#[non_exhaustive]
#[derive(Serialize, Deserialize, Default, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "debug", derive(Debug))]
#[serde(rename_all = "camelCase")]
pub struct Server {
pub url: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub description: Option<String>,
#[serde(skip_serializing_if = "ServerVariables::is_empty")]
pub variables: ServerVariables,
}
impl Ord for Server {
fn cmp(&self, other: &Self) -> Ordering {
self.url.cmp(&other.url)
}
}
impl PartialOrd for Server {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl Server {
pub fn new<S: Into<String>>(url: S) -> Self {
Self {
url: url.into(),
..Default::default()
}
}
pub fn url<U: Into<String>>(mut self, url: U) -> Self {
self.url = url.into();
self
}
pub fn description<S: Into<String>>(mut self, description: S) -> Self {
self.description = Some(description.into());
self
}
pub fn add_variable<N: Into<String>, V: Into<ServerVariable>>(
mut self,
name: N,
variable: V,
) -> Self {
self.variables.insert(name.into(), variable.into());
self
}
}
#[derive(Serialize, Deserialize, Default, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "debug", derive(Debug))]
pub struct ServerVariables(pub BTreeMap<String, ServerVariable>);
impl Deref for ServerVariables {
type Target = BTreeMap<String, ServerVariable>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl DerefMut for ServerVariables {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
impl ServerVariables {
pub fn new() -> Self {
Default::default()
}
pub fn is_empty(&self) -> bool {
self.0.is_empty()
}
pub fn server_varible<K: Into<String>, V: Into<ServerVariable>>(
mut self,
key: K,
variable: V,
) -> Self {
self.insert(key, variable);
self
}
pub fn insert<K: Into<String>, V: Into<ServerVariable>>(&mut self, key: K, variable: V) {
let key = key.into();
let mut variable = variable.into();
self.0
.entry(key)
.and_modify(|item| {
if variable.description.is_some() {
item.description = variable.description.take();
}
item.default_value.clone_from(&variable.default_value);
item.enum_values.append(&mut variable.enum_values);
})
.or_insert(variable);
}
pub fn append(&mut self, other: &mut ServerVariables) {
let variables = std::mem::take(&mut other.0);
for (key, variable) in variables {
self.insert(key, variable);
}
}
pub fn extend<I>(&mut self, iter: I)
where
I: IntoIterator<Item = (String, ServerVariable)>,
{
for (key, variable) in iter.into_iter() {
self.insert(key, variable);
}
}
}
#[non_exhaustive]
#[derive(Serialize, Deserialize, Default, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "debug", derive(Debug))]
pub struct ServerVariable {
#[serde(rename = "default")]
default_value: String,
#[serde(skip_serializing_if = "Option::is_none")]
description: Option<String>,
#[serde(rename = "enum", skip_serializing_if = "BTreeSet::is_empty")]
enum_values: BTreeSet<String>,
}
impl ServerVariable {
pub fn new() -> Self {
Default::default()
}
pub fn default_value<S: Into<String>>(mut self, default_value: S) -> Self {
self.default_value = default_value.into();
self
}
pub fn description<S: Into<String>>(mut self, description: S) -> Self {
self.description = Some(description.into());
self
}
pub fn enum_values<I: IntoIterator<Item = V>, V: Into<String>>(
mut self,
enum_values: I,
) -> Self {
self.enum_values = enum_values.into_iter().map(|value| value.into()).collect();
self
}
}
#[cfg(test)]
mod tests {
use super::*;
use assert_json_diff::assert_json_eq;
use serde_json::json;
macro_rules! test_fn {
($name:ident: $schema:expr; $expected:literal) => {
#[test]
fn $name() {
let value = serde_json::to_value($schema).unwrap();
let expected_value: serde_json::Value = serde_json::from_str($expected).unwrap();
assert_eq!(
value,
expected_value,
"testing serializing \"{}\": \nactual:\n{}\nexpected:\n{}",
stringify!($name),
value,
expected_value
);
println!("{}", &serde_json::to_string_pretty(&$schema).unwrap());
}
};
}
test_fn! {
create_server_with_builder_and_variable_substitution:
Server::new("/api/{version}/{username}")
.add_variable(
"version",
ServerVariable::new()
.enum_values(["v1", "v2"])
.description("api version")
.default_value("v1")
)
.add_variable(
"username",
ServerVariable::new().default_value("the_user")
);
r###"{
"url": "/api/{version}/{username}",
"variables": {
"version": {
"enum": ["v1", "v2"],
"default": "v1",
"description": "api version"
},
"username": {
"default": "the_user"
}
}
}"###
}
#[test]
fn test_servers_is_empty() {
let servers = Servers::new();
assert!(servers.is_empty());
}
#[test]
fn test_servers_server() {
let servers = Servers::new();
let server = Server::new("/api/v1").description("api v1");
let servers = servers.server(server);
assert!(servers.len() == 1);
}
#[test]
fn test_servers_insert() {
let mut servers = Servers::new();
let server = Server::new("/api/v1").description("api v1");
servers.insert(server);
assert!(servers.len() == 1);
}
#[test]
fn test_servers_insert_existed_server() {
let mut servers = Servers::new();
let server1 = Server::new("/api/v1".to_string())
.description("api v1")
.add_variable("key1", ServerVariable::new());
servers.insert(server1);
let server2 = Server::new("/api/v1".to_string())
.description("api v1 new description")
.add_variable("key2", ServerVariable::new());
servers.insert(server2);
assert!(servers.len() == 1);
assert_json_eq!(
servers,
json!([
{
"description": "api v1 new description",
"url": "/api/v1",
"variables": {
"key1": {
"default": ""
},
"key2": {
"default": ""
}
}
}
])
)
}
#[test]
fn test_servers_append() {
let mut servers = Servers::new();
let server = Server::new("/api/v1").description("api v1");
let mut other_servers: Servers = Servers::new();
other_servers.insert(server);
assert!(!other_servers.is_empty());
servers.append(&mut other_servers);
assert!(!servers.is_empty());
}
#[test]
fn test_servers_extend() {
let mut servers = Servers::new();
let server = Server::new("/api/v1").description("api v1");
let mut other_servers: Servers = Servers::new();
other_servers.insert(server);
assert!(!other_servers.is_empty());
servers.extend(other_servers);
assert!(!servers.is_empty());
}
#[test]
fn test_servers_deref() {
let mut servers = Servers::new();
let server = Server::new("/api/v1").description("api v1");
servers.insert(server);
assert!(servers.len() == 1);
assert!(servers.deref().len() == 1);
servers.deref_mut().clear();
assert!(servers.is_empty());
}
#[test]
fn test_server_set_url() {
let server = Server::new("/api/v1");
assert_eq!(server.url, "/api/v1");
let server = server.url("/new/api/v1");
assert_eq!(server.url, "/new/api/v1");
}
#[test]
fn test_server_cmp() {
let server_a = Server::new("/api/v1");
let server_b = Server::new("/api/v2");
assert!(server_a < server_b);
}
#[test]
fn test_server_variables_is_empty() {
let server_variables = ServerVariables::new();
assert!(server_variables.is_empty());
}
#[test]
fn test_server_variables_server_varible() {
let server_variables = ServerVariables::new();
let variable = ServerVariable::new();
let server_variables = server_variables.server_varible("key", variable);
assert!(!server_variables.is_empty());
}
#[test]
fn test_server_variables_insert() {
let mut server_variables = ServerVariables::new();
let variable = ServerVariable::new();
server_variables.insert("key", variable);
assert!(server_variables.len() == 1);
let new_variable = ServerVariable::new().description("description");
server_variables.insert("key", new_variable);
assert!(server_variables.len() == 1);
}
#[test]
fn test_server_variables_append() {
let mut server_variables = ServerVariables::new();
let mut other_server_variables = ServerVariables::new();
let variable = ServerVariable::new();
other_server_variables.insert("key", variable);
server_variables.append(&mut other_server_variables);
assert!(server_variables.len() == 1);
}
#[test]
fn test_server_variables_extend() {
let mut server_variables = ServerVariables::new();
let mut other_server_variables = ServerVariables::new();
let variable = ServerVariable::new();
other_server_variables.insert("key", variable);
server_variables.extend(other_server_variables.0);
assert!(server_variables.len() == 1);
}
#[test]
fn test_server_variables_deref() {
let mut server_variables = ServerVariables::new();
let variable = ServerVariable::new().default_value("default_value");
server_variables.insert("key", variable);
assert!(!server_variables.is_empty());
assert!(server_variables.deref().len() == 1);
server_variables.deref_mut().clear();
assert!(server_variables.is_empty());
}
}