use std::str::FromStr;
use fastobo_derive_internal::FromStr;
use fastobo_derive_internal::OboClause;
use crate::ast::*;
use crate::error::SyntaxError;
use crate::parser::Cache;
use crate::parser::FromPair;
use crate::semantics::OboClause;
use crate::syntax::pest::iterators::Pair;
use crate::syntax::Rule;
#[derive(Clone, Debug, Eq, Hash, FromStr, OboClause, Ord, PartialEq, PartialOrd)]
pub enum HeaderClause {
#[clause(tag = "format-version", cardinality = "ZeroOrOne")]
FormatVersion(Box<UnquotedString>),
#[clause(tag = "data-version", cardinality = "ZeroOrOne")]
DataVersion(Box<UnquotedString>),
#[clause(cardinality = "ZeroOrOne")]
Date(Box<NaiveDateTime>),
#[clause(tag = "saved-by", cardinality = "ZeroOrOne")]
SavedBy(Box<UnquotedString>),
#[clause(tag = "auto-generated-by", cardinality = "ZeroOrOne")]
AutoGeneratedBy(Box<UnquotedString>),
Import(Box<Import>),
Subsetdef(Box<SubsetIdent>, Box<QuotedString>),
#[clause(tag = "synonymtypedef")]
SynonymTypedef(
Box<SynonymTypeIdent>,
Box<QuotedString>,
Option<Box<SynonymScope>>,
),
#[clause(tag = "default-namespace", cardinality = "ZeroOrOne")]
DefaultNamespace(Box<NamespaceIdent>),
#[clause(tag = "namespace-id-rule")]
NamespaceIdRule(Box<UnquotedString>),
Idspace(Box<IdentPrefix>, Box<Url>, Option<Box<QuotedString>>),
#[clause(tag = "treat-xrefs-as-equivalent")]
TreatXrefsAsEquivalent(Box<IdentPrefix>),
#[clause(tag = "treat-xrefs-as-genus-differentia")]
TreatXrefsAsGenusDifferentia(Box<IdentPrefix>, Box<RelationIdent>, Box<ClassIdent>),
#[clause(tag = "treat-xrefs-as-reverse-genus-differentia")]
TreatXrefsAsReverseGenusDifferentia(Box<IdentPrefix>, Box<RelationIdent>, Box<ClassIdent>),
#[clause(tag = "treat-xrefs-as-relationship")]
TreatXrefsAsRelationship(Box<IdentPrefix>, Box<RelationIdent>),
#[clause(tag = "treat-xrefs-as-is_a")]
TreatXrefsAsIsA(Box<IdentPrefix>),
#[clause(tag = "treat-xrefs-as-has-subclass")]
TreatXrefsAsHasSubclass(Box<IdentPrefix>),
PropertyValue(Box<PropertyValue>),
Remark(Box<UnquotedString>),
#[clause(cardinality = "ZeroOrOne")]
Ontology(Box<UnquotedString>),
#[clause(tag = "owl-axioms")]
OwlAxioms(Box<UnquotedString>),
#[clause(tag = 0, format = "{0}: {1}")]
Unreserved(Box<UnquotedString>, Box<UnquotedString>),
}
impl<'i> FromPair<'i> for HeaderClause {
const RULE: Rule = Rule::HeaderClause;
unsafe fn from_pair_unchecked(
pair: Pair<'i, Rule>,
cache: &Cache,
) -> Result<Self, SyntaxError> {
let mut inner = pair.into_inner();
let tag = inner.next().unwrap();
match tag.as_rule() {
Rule::FormatVersionTag => {
let version = UnquotedString::from_pair_unchecked(inner.next().unwrap(), cache)?;
Ok(HeaderClause::FormatVersion(Box::new(version)))
}
Rule::DataVersionTag => {
let version = UnquotedString::from_pair_unchecked(inner.next().unwrap(), cache)?;
Ok(HeaderClause::DataVersion(Box::new(version)))
}
Rule::DateTag => {
let date = NaiveDateTime::from_pair_unchecked(inner.next().unwrap(), cache)?;
Ok(HeaderClause::Date(Box::new(date)))
}
Rule::SavedByTag => {
let person = UnquotedString::from_pair_unchecked(inner.next().unwrap(), cache)?;
Ok(HeaderClause::SavedBy(Box::new(person)))
}
Rule::AutoGeneratedByTag => {
let soft = UnquotedString::from_pair_unchecked(inner.next().unwrap(), cache)?;
Ok(HeaderClause::AutoGeneratedBy(Box::new(soft)))
}
Rule::ImportTag => {
let import = Import::from_pair_unchecked(inner.next().unwrap(), cache)?;
Ok(HeaderClause::Import(Box::new(import)))
}
Rule::SubsetdefTag => {
let subset = SubsetIdent::from_pair_unchecked(inner.next().unwrap(), cache)?;
let desc = QuotedString::from_pair_unchecked(inner.next().unwrap(), cache)?;
Ok(HeaderClause::Subsetdef(Box::new(subset), Box::new(desc)))
}
Rule::SynonymTypedefTag => {
let id = SynonymTypeIdent::from_pair_unchecked(inner.next().unwrap(), cache)?;
let desc = QuotedString::from_pair_unchecked(inner.next().unwrap(), cache)?;
let scope = match inner.next() {
Some(pair) => Some(Box::new(SynonymScope::from_pair_unchecked(pair, cache)?)),
None => None,
};
Ok(HeaderClause::SynonymTypedef(
Box::new(id),
Box::new(desc),
scope,
))
}
Rule::DefaultNamespaceTag => {
let id = NamespaceIdent::from_pair_unchecked(inner.next().unwrap(), cache)?;
Ok(HeaderClause::DefaultNamespace(Box::new(id)))
}
Rule::NamespaceIdRuleTag => {
let value = UnquotedString::from_pair_unchecked(inner.next().unwrap(), cache)?;
Ok(HeaderClause::NamespaceIdRule(Box::new(value)))
}
Rule::IdspaceTag => {
let prefix = IdentPrefix::from_pair_unchecked(inner.next().unwrap(), cache)?;
let url = Url::from_pair_unchecked(inner.next().unwrap(), cache)?;
let desc = match inner.next() {
Some(pair) => Some(Box::new(QuotedString::from_pair_unchecked(pair, cache)?)),
None => None,
};
Ok(HeaderClause::Idspace(Box::new(prefix), Box::new(url), desc))
}
Rule::TreatXrefsAsEquivalentTag => {
let prefix = IdentPrefix::from_pair_unchecked(inner.next().unwrap(), cache)?;
Ok(HeaderClause::TreatXrefsAsEquivalent(Box::new(prefix)))
}
Rule::TreatXrefsAsGenusDifferentiaTag => {
let prefix = IdentPrefix::from_pair_unchecked(inner.next().unwrap(), cache)?;
let rel = RelationIdent::from_pair_unchecked(inner.next().unwrap(), cache)?;
let cls = ClassIdent::from_pair_unchecked(inner.next().unwrap(), cache)?;
Ok(HeaderClause::TreatXrefsAsGenusDifferentia(
Box::new(prefix),
Box::new(rel),
Box::new(cls),
))
}
Rule::TreatXrefsAsReverseGenusDifferentiaTag => {
let prefix = IdentPrefix::from_pair_unchecked(inner.next().unwrap(), cache)?;
let rel = RelationIdent::from_pair_unchecked(inner.next().unwrap(), cache)?;
let cls = ClassIdent::from_pair_unchecked(inner.next().unwrap(), cache)?;
Ok(HeaderClause::TreatXrefsAsReverseGenusDifferentia(
Box::new(prefix),
Box::new(rel),
Box::new(cls),
))
}
Rule::TreatXrefsAsRelationshipTag => {
let prefix = IdentPrefix::from_pair_unchecked(inner.next().unwrap(), cache)?;
let rel = RelationIdent::from_pair_unchecked(inner.next().unwrap(), cache)?;
Ok(HeaderClause::TreatXrefsAsRelationship(
Box::new(prefix),
Box::new(rel),
))
}
Rule::TreatXrefsAsIsATag => {
let prefix = IdentPrefix::from_pair_unchecked(inner.next().unwrap(), cache)?;
Ok(HeaderClause::TreatXrefsAsIsA(Box::new(prefix)))
}
Rule::TreatXrefsAsHasSubclassTag => {
let prefix = IdentPrefix::from_pair_unchecked(inner.next().unwrap(), cache)?;
Ok(HeaderClause::TreatXrefsAsHasSubclass(Box::new(prefix)))
}
Rule::PropertyValueTag => {
let pv = PropertyValue::from_pair_unchecked(inner.next().unwrap(), cache)?;
Ok(HeaderClause::PropertyValue(Box::new(pv)))
}
Rule::RemarkTag => {
let remark = UnquotedString::from_pair_unchecked(inner.next().unwrap(), cache)?;
Ok(HeaderClause::Remark(Box::new(remark)))
}
Rule::OntologyTag => {
let ont = UnquotedString::from_pair_unchecked(inner.next().unwrap(), cache)?;
Ok(HeaderClause::Ontology(Box::new(ont)))
}
Rule::OwlAxiomsTag => {
let axioms = UnquotedString::from_pair_unchecked(inner.next().unwrap(), cache)?;
Ok(HeaderClause::OwlAxioms(Box::new(axioms)))
}
Rule::Unreserved => {
let tag = UnquotedString::from_str(tag.as_str())?;
let value = UnquotedString::from_pair_unchecked(inner.next().unwrap(), cache)?;
Ok(HeaderClause::Unreserved(Box::new(tag), Box::new(value)))
}
_ => unreachable!(),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use pretty_assertions::assert_eq;
#[test]
fn tag() {
let clause = HeaderClause::FormatVersion(Box::new(UnquotedString::from("1.2")));
assert_eq!(clause.tag(), "format-version");
let clause = HeaderClause::Unreserved(
Box::new(UnquotedString::from("something")),
Box::new(UnquotedString::new(String::new())),
);
assert_eq!(clause.tag(), "something");
}
#[test]
fn cardinality() {
let clause = HeaderClause::FormatVersion(Box::new(UnquotedString::from("1.2")));
assert_eq!(
clause.cardinality(),
crate::semantics::Cardinality::ZeroOrOne
);
let clause = HeaderClause::Unreserved(
Box::new(UnquotedString::from("something")),
Box::new(UnquotedString::new(String::new())),
);
assert_eq!(clause.cardinality(), crate::semantics::Cardinality::Any);
}
#[test]
fn from_str() {
let actual = HeaderClause::from_str("format-version: 1.2").unwrap();
let expected =
HeaderClause::FormatVersion(Box::new(UnquotedString::new(String::from("1.2"))));
assert_eq!(actual, expected);
let actual = HeaderClause::from_str("subsetdef: GO_SLIM \"GO Slim\"").unwrap();
let expected = HeaderClause::Subsetdef(
Box::new(SubsetIdent::from(UnprefixedIdent::new("GO_SLIM"))),
Box::new(QuotedString::new("GO Slim")),
);
assert_eq!(actual, expected);
let actual = HeaderClause::from_str("date: 17:03:2019 20:16").unwrap();
let expected = HeaderClause::Date(Box::new(NaiveDateTime::new(17, 3, 2019, 20, 16)));
assert_eq!(actual, expected);
let actual =
HeaderClause::from_str("namespace-id-rule: * XAO:$sequence(7,5000,9999999)$").unwrap();
let expected = HeaderClause::NamespaceIdRule(Box::new(UnquotedString::new(
"* XAO:$sequence(7,5000,9999999)$",
)));
assert_eq!(actual, expected);
let actual = HeaderClause::from_str("treat-xrefs-as-relationship: TEST rel").unwrap();
let expected = HeaderClause::TreatXrefsAsRelationship(
Box::new(IdentPrefix::new("TEST")),
Box::new(RelationIdent::from(UnprefixedIdent::new("rel"))),
);
assert_eq!(actual, expected);
let actual = HeaderClause::from_str("tag: value").unwrap();
let expected = HeaderClause::Unreserved(
Box::new(UnquotedString::new("tag")),
Box::new(UnquotedString::new("value")),
);
assert_eq!(actual, expected);
}
#[test]
fn partial_cmp() {
macro_rules! assert_lt {
($l:ident, $r:ident) => {
assert!($l < $r, "'{}' < '{}' is not true!", $l, $r)
};
}
let fv1 = HeaderClause::FormatVersion(Box::new(UnquotedString::new("1.4")));
let fv2 = HeaderClause::FormatVersion(Box::new(UnquotedString::new("2")));
assert_lt!(fv1, fv2);
let dv1 = HeaderClause::DataVersion(Box::new(UnquotedString::new("1.4")));
let dv2 = HeaderClause::DataVersion(Box::new(UnquotedString::new("2")));
assert_lt!(dv1, dv2);
assert_lt!(fv1, dv1);
assert_lt!(fv1, dv2);
assert_lt!(fv2, dv1);
assert_lt!(fv2, dv2);
}
#[test]
fn display() {
let expected = "unreserved-thing: something";
let actual = HeaderClause::Unreserved(
Box::new(UnquotedString::new("unreserved-thing")),
Box::new(UnquotedString::new("something")),
);
assert_eq!(&actual.to_string(), expected);
let expected = r#"synonymtypedef: EXAMPLE "example""#;
let actual = HeaderClause::SynonymTypedef(
Box::new(SynonymTypeIdent::from(UnprefixedIdent::new("EXAMPLE"))),
Box::new(QuotedString::new("example")),
None,
);
assert_eq!(&actual.to_string(), expected);
}
}