use serde::{Deserialize, Serialize};
use std::fmt;
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize, PartialOrd, Ord)]
pub struct Predicate {
uri: String,
}
impl Predicate {
pub fn named(name: impl Into<String>) -> Self {
Self { uri: name.into() }
}
pub fn uri(uri: impl Into<String>) -> Self {
Self { uri: uri.into() }
}
pub fn as_str(&self) -> &str {
&self.uri
}
pub fn namespace(&self) -> Option<&str> {
self.uri.rsplit_once(':').map(|(ns, _)| ns)
}
pub fn local_name(&self) -> &str {
self.uri.rsplit(':').next().unwrap_or(&self.uri)
}
pub fn to_bytes(&self) -> Vec<u8> {
self.uri.as_bytes().to_vec()
}
pub fn from_bytes(bytes: &[u8]) -> Option<Self> {
String::from_utf8(bytes.to_vec())
.ok()
.map(|uri| Self { uri })
}
pub fn rdf_type() -> Self {
Self::named("rdf:type")
}
pub fn rdfs_label() -> Self {
Self::named("rdfs:label")
}
pub fn rdfs_comment() -> Self {
Self::named("rdfs:comment")
}
pub fn rdfs_subclass_of() -> Self {
Self::named("rdfs:subClassOf")
}
pub fn owl_same_as() -> Self {
Self::named("owl:sameAs")
}
pub fn aingle_author() -> Self {
Self::named("aingle:author")
}
pub fn aingle_timestamp() -> Self {
Self::named("aingle:timestamp")
}
pub fn aingle_signature() -> Self {
Self::named("aingle:signature")
}
pub fn aingle_prev_action() -> Self {
Self::named("aingle:prevAction")
}
pub fn aingle_entry_hash() -> Self {
Self::named("aingle:entryHash")
}
pub fn aingle_seq() -> Self {
Self::named("aingle:seq")
}
pub fn has_name() -> Self {
Self::named("has_name")
}
pub fn has_title() -> Self {
Self::named("has_title")
}
pub fn issued_by() -> Self {
Self::named("issued_by")
}
pub fn works_at() -> Self {
Self::named("works_at")
}
pub fn located_in() -> Self {
Self::named("located_in")
}
pub fn owns() -> Self {
Self::named("owns")
}
pub fn certifies() -> Self {
Self::named("certifies")
}
pub fn trusts() -> Self {
Self::named("trusts")
}
pub fn connected_to() -> Self {
Self::named("connected_to")
}
pub fn parent_of() -> Self {
Self::named("parent_of")
}
pub fn child_of() -> Self {
Self::named("child_of")
}
}
impl fmt::Display for Predicate {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "<{}>", self.uri)
}
}
impl From<String> for Predicate {
fn from(s: String) -> Self {
Self::named(s)
}
}
impl From<&str> for Predicate {
fn from(s: &str) -> Self {
Self::named(s)
}
}
impl AsRef<str> for Predicate {
fn as_ref(&self) -> &str {
&self.uri
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_named_predicate() {
let pred = Predicate::named("has_title");
assert_eq!(pred.as_str(), "has_title");
assert_eq!(pred.local_name(), "has_title");
}
#[test]
fn test_namespaced_predicate() {
let pred = Predicate::named("rdf:type");
assert_eq!(pred.namespace(), Some("rdf"));
assert_eq!(pred.local_name(), "type");
}
#[test]
fn test_well_known_predicates() {
assert_eq!(Predicate::rdf_type().as_str(), "rdf:type");
assert_eq!(Predicate::aingle_author().as_str(), "aingle:author");
assert_eq!(Predicate::has_title().as_str(), "has_title");
}
#[test]
fn test_display() {
let pred = Predicate::named("has_name");
assert_eq!(format!("{}", pred), "<has_name>");
}
#[test]
fn test_serialization() {
let pred = Predicate::named("test:predicate");
let bytes = pred.to_bytes();
let restored = Predicate::from_bytes(&bytes).unwrap();
assert_eq!(pred, restored);
}
#[test]
fn test_equality() {
let p1 = Predicate::named("test");
let p2 = Predicate::named("test");
let p3 = Predicate::named("other");
assert_eq!(p1, p2);
assert_ne!(p1, p3);
}
}