use std::cmp::Ordering;
use std::cmp::Ordering::Equal;
use std::fmt::{Debug, Display, Formatter};
use serde::{Deserialize, Serialize};
use crate::helpers::{check_character_collision, remove_first_and_last_characters};
pub use self::{fmri_list::FMRIList, publisher::Publisher, version::Version};
pub mod fmri_list;
mod helpers;
pub mod publisher;
#[cfg(test)]
mod tests;
pub mod version;
#[derive(PartialEq, Serialize, Deserialize, Clone, Eq, Hash)]
pub struct FMRI {
publisher: Option<Publisher>,
package_name: String,
version: Option<Version>,
}
impl FMRI {
pub fn new_from_package_name(mut package_name: String) -> Result<Self, String> {
if package_name.is_empty() {
panic!("package name can't be empty")
}
check_character_collision(&package_name)?;
package_name = remove_first_and_last_characters(&package_name, '/').to_owned();
Ok(Self {
publisher: None,
package_name,
version: None,
})
}
pub fn parse_raw(raw_fmri: &str) -> Result<Self, String> {
let mut publisher: Option<Publisher> = None;
let mut version: Option<Version> = None;
let mut package_name: String = raw_fmri.to_owned().trim_start_matches("fmri=").to_owned();
match Publisher::parse_publisher_from_raw_fmri(raw_fmri.to_owned()) {
Ok(None) => {
package_name = package_name.trim_start_matches("pkg:/").to_owned();
}
Ok(Some(p)) => {
publisher = Some(p);
let (_, end_str) = package_name
.trim_start_matches("pkg://")
.split_once('/')
.expect("Fmri must contain \"/package_name\"");
package_name = end_str.to_owned()
}
Err(e) => return Err(e),
}
match Version::parse_version_from_raw_fmri(raw_fmri.to_owned()) {
Ok(None) => {}
Ok(Some(v)) => {
version = Some(v);
let (start_str, _) = package_name.split_once('@').expect("error");
package_name = start_str.to_owned()
}
Err(e) => return Err(e),
}
let mut fmri = Self::new_from_package_name(package_name)?;
if let Some(p) = publisher {
fmri.change_publisher(p);
}
if let Some(v) = version {
fmri.change_version(v);
}
Ok(fmri)
}
pub fn package_name_eq(&self, comparing_to: &FMRI) -> bool {
self.get_package_name_as_ref_string()
.eq(comparing_to.get_package_name_as_ref_string())
}
pub fn get_package_name_as_string(self) -> String {
self.package_name
}
pub fn get_package_name_as_ref_string(&self) -> &String {
&self.package_name
}
pub fn get_package_name_as_ref_mut_string(&mut self) -> &mut String {
&mut self.package_name
}
pub fn get_publisher(self) -> Option<Publisher> {
self.publisher
}
pub fn get_publisher_ref(&self) -> &Option<Publisher> {
&self.publisher
}
pub fn get_publisher_ref_mut(&mut self) -> &mut Option<Publisher> {
&mut self.publisher
}
pub fn has_publisher(&self) -> bool {
self.publisher.is_some()
}
pub fn change_publisher(&mut self, publisher: Publisher) {
self.publisher = Some(publisher);
}
pub fn get_publisher_as_ref_string(&self) -> Option<&String> {
if let Some(publisher) = &self.publisher {
return Some(publisher.get_as_ref_string());
}
None
}
pub fn remove_publisher(&mut self) {
self.publisher = None
}
pub fn get_version(self) -> Option<Version> {
self.version
}
pub fn get_version_ref(&self) -> &Option<Version> {
&self.version
}
pub fn get_version_ref_mut(&mut self) -> &mut Option<Version> {
&mut self.version
}
pub fn has_version(&self) -> bool {
self.version.is_some()
}
pub fn change_version(&mut self, version: Version) {
self.version = Some(version)
}
pub fn get_version_as_string(&self) -> Option<String> {
if let Some(version) = &self.version {
return Some(format!("{}", version));
}
None
}
pub fn remove_version(&mut self) -> &mut FMRI {
self.version = None;
self
}
}
impl PartialOrd<Self> for FMRI {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl Ord for FMRI {
fn cmp(&self, other: &Self) -> Ordering {
self.version
.as_ref()
.and_then(|ver| other.version.as_ref().map(|ver2| ver.cmp(ver2)))
.unwrap_or(Equal)
}
}
impl Display for FMRI {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
let mut string: String = "".to_owned();
if let Some(publisher) = self.get_publisher_as_ref_string() {
string.push_str("pkg://");
string.push_str(publisher);
string.push('/');
} else {
string.push_str("pkg:/");
}
string.push_str(self.get_package_name_as_ref_string());
if let Some(version) = self.get_version_as_string() {
string.push_str(&version)
}
write!(f, "{}", string)
}
}
impl Debug for FMRI {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self)
}
}