use serde::{Deserialize, Serialize};
use crate::model::extensions::Extensions;
#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
pub struct Info {
pub title: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub summary: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub description: Option<String>,
#[serde(
rename = "termsOfService",
default,
skip_serializing_if = "Option::is_none"
)]
pub terms_of_service: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub contact: Option<Contact>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub license: Option<License>,
pub version: String,
#[serde(flatten)]
pub extensions: Extensions,
}
impl Info {
pub fn new(title: impl Into<String>, version: impl Into<String>) -> Self {
Self {
title: title.into(),
version: version.into(),
..Self::default()
}
}
#[must_use]
pub fn with_summary(mut self, summary: impl Into<String>) -> Self {
self.summary = Some(summary.into());
self
}
#[must_use]
pub fn with_description(mut self, description: impl Into<String>) -> Self {
self.description = Some(description.into());
self
}
#[must_use]
pub fn with_contact(mut self, contact: Contact) -> Self {
self.contact = Some(contact);
self
}
#[must_use]
pub fn with_license(mut self, license: License) -> Self {
self.license = Some(license);
self
}
}
#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
pub struct Contact {
#[serde(default, skip_serializing_if = "Option::is_none")]
pub name: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub url: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub email: Option<String>,
#[serde(flatten)]
pub extensions: Extensions,
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[serde(try_from = "RawLicense", into = "RawLicense")]
pub struct License {
name: String,
link: Option<LicenseLink>,
pub extensions: Extensions,
}
#[derive(Clone, Debug, PartialEq, Eq)]
enum LicenseLink {
Spdx(String),
Url(String),
}
impl License {
pub fn named(name: impl Into<String>) -> Self {
Self {
name: name.into(),
link: None,
extensions: Extensions::default(),
}
}
pub fn spdx(name: impl Into<String>, identifier: impl Into<String>) -> Self {
Self {
link: Some(LicenseLink::Spdx(identifier.into())),
..Self::named(name)
}
}
pub fn with_url(name: impl Into<String>, url: impl Into<String>) -> Self {
Self {
link: Some(LicenseLink::Url(url.into())),
..Self::named(name)
}
}
#[must_use]
pub fn name(&self) -> &str {
&self.name
}
#[must_use]
pub fn identifier(&self) -> Option<&str> {
match &self.link {
Some(LicenseLink::Spdx(identifier)) => Some(identifier),
_ => None,
}
}
#[must_use]
pub fn url(&self) -> Option<&str> {
match &self.link {
Some(LicenseLink::Url(url)) => Some(url),
_ => None,
}
}
}
#[derive(Serialize, Deserialize)]
struct RawLicense {
name: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
identifier: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
url: Option<String>,
#[serde(flatten)]
extensions: Extensions,
}
#[derive(Debug)]
struct LicenseConflict;
impl std::fmt::Display for LicenseConflict {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str("`identifier` and `url` are mutually exclusive on a License Object")
}
}
impl TryFrom<RawLicense> for License {
type Error = LicenseConflict;
fn try_from(raw: RawLicense) -> Result<Self, Self::Error> {
let link = match (raw.identifier, raw.url) {
(Some(_), Some(_)) => return Err(LicenseConflict),
(Some(identifier), None) => Some(LicenseLink::Spdx(identifier)),
(None, Some(url)) => Some(LicenseLink::Url(url)),
(None, None) => None,
};
Ok(Self {
name: raw.name,
link,
extensions: raw.extensions,
})
}
}
impl From<License> for RawLicense {
fn from(license: License) -> Self {
let (identifier, url) = match license.link {
Some(LicenseLink::Spdx(identifier)) => (Some(identifier), None),
Some(LicenseLink::Url(url)) => (None, Some(url)),
None => (None, None),
};
Self {
name: license.name,
identifier,
url,
extensions: license.extensions,
}
}
}
#[cfg(test)]
mod tests;