use std::fmt::Display;
use std::fmt::Formatter;
use std::fmt::Result as FmtResult;
use std::fmt::Write;
use pest::iterators::Pair;
use url::Url;
use crate::ast::*;
use crate::error::Error;
use crate::error::Result;
use crate::parser::FromPair;
use crate::parser::Rule;
#[derive(Clone, Debug, Eq, Hash, PartialEq, Ord, PartialOrd)]
pub enum SynonymScope {
Broad,
Exact,
Narrow,
Related,
}
impl Display for SynonymScope {
fn fmt(&self, f: &mut Formatter) -> FmtResult {
use self::SynonymScope::*;
match self {
Exact => f.write_str("EXACT"),
Broad => f.write_str("BROAD"),
Narrow => f.write_str("NARROW"),
Related => f.write_str("RELATED"),
}
}
}
impl<'i> FromPair<'i> for SynonymScope {
const RULE: Rule = Rule::SynonymScope;
unsafe fn from_pair_unchecked(pair: Pair<'i, Rule>) -> Result<Self> {
match pair.as_str() {
"EXACT" => Ok(SynonymScope::Exact),
"BROAD" => Ok(SynonymScope::Broad),
"NARROW" => Ok(SynonymScope::Narrow),
"RELATED" => Ok(SynonymScope::Related),
_ => unreachable!(),
}
}
}
impl_fromstr!(SynonymScope);
#[derive(Clone, Debug, Eq, Hash, PartialEq, PartialOrd, Ord)]
pub struct Synonym {
desc: QuotedString,
scope: SynonymScope,
ty: Option<SynonymTypeIdent>,
xrefs: XrefList,
}
impl Synonym {
pub fn new<D>(desc: D, scope: SynonymScope) -> Self
where
D: Into<QuotedString>,
{
Self {
desc: desc.into(),
scope,
ty: Default::default(),
xrefs: Default::default(),
}
}
pub fn with_type<D, T>(desc: D, scope: SynonymScope, ty: T) -> Self
where
D: Into<QuotedString>,
T: Into<Option<SynonymTypeIdent>>,
{
Self {
desc: desc.into(),
scope,
ty: ty.into(),
xrefs: Default::default(),
}
}
pub fn with_xrefs<D, L>(desc: D, scope: SynonymScope, xrefs: L) -> Self
where
D: Into<QuotedString>,
L: Into<XrefList>,
{
Self {
desc: desc.into(),
scope,
ty: None,
xrefs: xrefs.into(),
}
}
pub fn with_type_and_xrefs<D, T, L>(
desc: D,
scope: SynonymScope,
ty: T,
xrefs: L,
) -> Self
where
D: Into<QuotedString>,
T: Into<Option<SynonymTypeIdent>>,
L: Into<XrefList>,
{
Self {
desc: desc.into(),
scope,
ty: ty.into(),
xrefs: xrefs.into(),
}
}
}
impl Synonym {
pub fn description(&self) -> &QuotedString {
&self.desc
}
pub fn description_mut(&mut self) -> &mut QuotedString {
&mut self.desc
}
pub fn scope(&self) -> &SynonymScope {
&self.scope
}
pub fn scope_mut(&mut self) -> &mut SynonymScope {
&mut self.scope
}
pub fn ty(&self) -> Option<&SynonymTypeIdent> {
match self.ty {
Some(ref id) => Some(id),
None => None,
}
}
pub fn ty_mut(&mut self) -> Option<&mut SynonymTypeIdent> {
match self.ty {
Some(ref mut id) => Some(id),
None => None,
}
}
pub fn xrefs(&self) -> &XrefList {
&self.xrefs
}
pub fn xrefs_mut(&mut self) -> &mut XrefList {
&mut self.xrefs
}
}
impl Display for Synonym {
fn fmt(&self, f: &mut Formatter) -> FmtResult {
self.desc
.fmt(f)
.and(f.write_char(' '))
.and(self.scope.fmt(f))
.and(f.write_char(' '))?;
if let Some(ref syntype) = self.ty {
syntype.fmt(f).and(f.write_char(' '))?;
}
self.xrefs.fmt(f)
}
}
impl<'i> FromPair<'i> for Synonym {
const RULE: Rule = Rule::Synonym;
unsafe fn from_pair_unchecked(pair: Pair<'i, Rule>) -> Result<Self> {
let mut inner = pair.into_inner();
let desc = QuotedString::from_pair_unchecked(inner.next().unwrap())?;
let scope = SynonymScope::from_pair_unchecked(inner.next().unwrap())?;
let nxt = inner.next().unwrap();
match nxt.as_rule() {
Rule::SynonymTypeId => {
let ty = Some(SynonymTypeIdent::from_pair_unchecked(nxt)?);
let xrefs = XrefList::from_pair_unchecked(inner.next().unwrap())?;
Ok(Synonym {
desc,
scope,
ty,
xrefs,
})
}
Rule::XrefList => {
let ty = None;
let xrefs = XrefList::from_pair_unchecked(nxt)?;
Ok(Synonym {
desc,
scope,
ty,
xrefs,
})
}
_ => unreachable!(),
}
}
}
impl_fromstr!(Synonym);
#[cfg(test)]
mod tests {
use std::str::FromStr;
use pretty_assertions::assert_eq;
use super::*;
mod scope {
use super::*;
use self::SynonymScope::*;
#[test]
fn from_str() {
self::assert_eq!(SynonymScope::from_str("EXACT").unwrap(), Exact);
self::assert_eq!(SynonymScope::from_str("BROAD").unwrap(), Broad);
self::assert_eq!(SynonymScope::from_str("NARROW").unwrap(), Narrow);
self::assert_eq!(SynonymScope::from_str("RELATED").unwrap(), Related);
assert!(SynonymScope::from_str("something").is_err());
}
#[test]
fn to_string() {
self::assert_eq!(Exact.to_string(), "EXACT");
self::assert_eq!(Broad.to_string(), "BROAD");
self::assert_eq!(Narrow.to_string(), "NARROW");
self::assert_eq!(Related.to_string(), "RELATED");
}
}
mod synonym {
use super::*;
#[test]
fn from_str() {
let actual = Synonym::from_str("\"ssDNA-specific endodeoxyribonuclease activity\" RELATED [GOC:mah]").unwrap();
let expected = Synonym::with_xrefs(
"ssDNA-specific endodeoxyribonuclease activity",
SynonymScope::Related,
vec![Xref::new(PrefixedIdent::new("GOC", "mah"))],
);
self::assert_eq!(actual, expected);
}
#[test]
fn to_string() {
let s = Synonym::with_xrefs(
QuotedString::new(String::from("ssDNA-specific endodeoxyribonuclease activity")),
SynonymScope::Related,
vec![Xref::new(
Ident::from(
PrefixedIdent::new(
IdentPrefix::new(String::from("GOC")),
IdentLocal::new(String::from("mah"))
)
)
)]
);
self::assert_eq!(
s.to_string(),
"\"ssDNA-specific endodeoxyribonuclease activity\" RELATED [GOC:mah]"
);
}
}
}