use crate::{
syntax::{Term, TermLike},
util::{self, AsAnyJson},
BlankId, Id,
};
use generic_json::JsonClone;
use iref::{AsIri, Iri, IriBuf};
use std::borrow::Borrow;
use std::convert::TryFrom;
use std::fmt;
#[derive(Clone, PartialEq, Eq, Hash)]
pub enum Reference<T: AsIri = IriBuf> {
Id(T),
Blank(BlankId),
Invalid(String),
}
impl<T: AsIri> Reference<T> {
#[inline(always)]
pub fn is_valid(&self) -> bool {
!matches!(self, Self::Invalid(_))
}
#[inline(always)]
pub fn as_str(&self) -> &str {
match self {
Reference::Id(id) => id.as_iri().into_str(),
Reference::Blank(id) => id.as_str(),
Reference::Invalid(id) => id.as_str(),
}
}
#[inline(always)]
pub fn as_iri(&self) -> Option<Iri> {
match self {
Reference::Id(k) => Some(k.as_iri()),
_ => None,
}
}
#[inline(always)]
pub fn into_term(self) -> Term<T> {
Term::Ref(self)
}
}
impl<T: AsIri> TermLike for Reference<T> {
#[inline(always)]
fn as_iri(&self) -> Option<Iri> {
self.as_iri()
}
#[inline(always)]
fn as_str(&self) -> &str {
self.as_str()
}
}
impl<T: AsIri + PartialEq> PartialEq<T> for Reference<T> {
fn eq(&self, other: &T) -> bool {
match self {
Reference::Id(id) => id == other,
_ => false,
}
}
}
impl<T: AsIri> PartialEq<str> for Reference<T> {
fn eq(&self, other: &str) -> bool {
match self {
Reference::Id(id) => match Iri::from_str(other) {
Ok(iri) => id.as_iri() == iri,
Err(_) => false,
},
Reference::Blank(id) => id.as_str() == other,
Reference::Invalid(id) => id == other,
}
}
}
impl<'a, T: AsIri> From<&'a Reference<T>> for Reference<&'a T> {
fn from(r: &'a Reference<T>) -> Reference<&'a T> {
match r {
Reference::Id(id) => Reference::Id(id),
Reference::Blank(id) => Reference::Blank(id.clone()),
Reference::Invalid(id) => Reference::Invalid(id.clone()),
}
}
}
impl<T: AsIri> From<T> for Reference<T> {
#[inline(always)]
fn from(id: T) -> Reference<T> {
Reference::Id(id)
}
}
impl<T: AsIri + PartialEq> PartialEq<Term<T>> for Reference<T> {
#[inline]
fn eq(&self, term: &Term<T>) -> bool {
match term {
Term::Ref(prop) => self == prop,
_ => false,
}
}
}
impl<T: AsIri + PartialEq> PartialEq<Reference<T>> for Term<T> {
#[inline]
fn eq(&self, r: &Reference<T>) -> bool {
match self {
Term::Ref(prop) => prop == r,
_ => false,
}
}
}
impl<T: AsIri> TryFrom<Term<T>> for Reference<T> {
type Error = Term<T>;
#[inline]
fn try_from(term: Term<T>) -> Result<Reference<T>, Term<T>> {
match term {
Term::Ref(prop) => Ok(prop),
term => Err(term),
}
}
}
impl<T: AsIri> From<BlankId> for Reference<T> {
#[inline(always)]
fn from(blank: BlankId) -> Reference<T> {
Reference::Blank(blank)
}
}
impl<J: JsonClone, K: util::JsonFrom<J>, T: Id> util::AsJson<J, K> for Reference<T> {
#[inline]
fn as_json_with(&self, meta: impl Clone + Fn(Option<&J::MetaData>) -> K::MetaData) -> K {
match self {
Reference::Id(id) => id.as_json(meta(None)),
Reference::Blank(b) => b.as_json_with(meta(None)),
Reference::Invalid(id) => id.as_json_with(meta(None)),
}
}
}
impl<T: AsIri> fmt::Display for Reference<T> {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Reference::Id(id) => id.as_iri().fmt(f),
Reference::Blank(b) => b.fmt(f),
Reference::Invalid(id) => id.fmt(f),
}
}
}
impl<T: AsIri> fmt::Debug for Reference<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Reference::Id(id) => write!(f, "Reference::Id({})", id.as_iri()),
Reference::Blank(b) => write!(f, "Reference::Blank({})", b),
Reference::Invalid(id) => write!(f, "Reference::Invalid({})", id),
}
}
}
pub trait ToReference<T: Id> {
type Reference: Borrow<Reference<T>>;
fn to_ref(&self) -> Self::Reference;
}
impl<'a, T: Id> ToReference<T> for &'a Reference<T> {
type Reference = &'a Reference<T>;
#[inline(always)]
fn to_ref(&self) -> Self::Reference {
self
}
}