link_relation 0.1.0

Registered link relation types for Web Linking (RFC8288)
Documentation
//! # Link Relations
//!
//! Registered relation types for
//! [Web Linking (RFC8288)](https://datatracker.ietf.org/doc/html/rfc8288).
//!
//! Definitions generated from IANA's
//! [link relations registry](https://www.iana.org/assignments/link-relations/link-relations.xml).
//!
//! Please check [LinkRelation] for all registered link relation types.
//!
//! ```rust
//! use link_relation::LinkRelation;
//! assert_eq!(LinkRelation::ACL.get_name(), "acl");
//! ```
//!
//! ## Crate Features
//!
//! - **serde** - Serialization and deserialization support with
//!   [serde](https://crates.io/crates/serde).

mod generated;
pub use generated::{LinkRelation, LINK_RELATIONS};

#[cfg(feature = "serde")]
mod serde;

use std::error::Error;
use std::fmt;
use std::str::FromStr;

/// Detailed link relation data.
#[derive(Clone, Debug)]
pub struct LinkRelationDetails {
    pub name: String,
    pub description: String,
    pub reference: String,
    pub notes: Option<String>,
}

/// Error definitions for parsing link relation with [FromStr].
#[derive(Copy, Clone, Debug)]
pub enum LinkRelationParsingError {
    /// Cannot find this link relation variant.
    NotFound,
}

impl fmt::Display for LinkRelationParsingError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(
            f,
            "Error while parsing LinkRelation: {}",
            match self {
                LinkRelationParsingError::NotFound => "Not found",
            }
        )
    }
}

impl Error for LinkRelationParsingError {}

impl LinkRelation {
    /// Get the associated LinkRelation definition.
    pub fn get_link_relation(&self) -> &LinkRelationDetails {
        // It should never panic
        LINK_RELATIONS.get(self).unwrap()
    }

    /// Get the original name of the specified link relation type.
    pub fn get_name(&self) -> &str {
        &self.get_link_relation().name
    }

    /// Get the description of the link relation.
    pub fn get_description(&self) -> &str {
        &self.get_link_relation().description
    }

    /// Get the reference of the link relation.
    pub fn get_reference(&self) -> &str {
        &self.get_link_relation().reference
    }

    /// Get the notes of the link relation.
    pub fn get_notes(&self) -> Option<&str> {
        let link_relation = self.get_link_relation();
        link_relation.notes.as_deref()
    }
}

impl FromStr for LinkRelation {
    type Err = LinkRelationParsingError;

    fn from_str(value: &str) -> Result<Self, Self::Err> {
        let value_str = value.trim().to_lowercase();
        LINK_RELATIONS
            .iter()
            .filter_map(|(k, v)| if value_str == v.name { Some(*k) } else { None })
            .next()
            .ok_or(LinkRelationParsingError::NotFound)
    }
}

impl fmt::Display for LinkRelation {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{}", self.get_name())
    }
}

#[cfg(test)]
mod tests {
    use super::LinkRelation;

    #[test]
    fn test_to_string() {
        assert_eq!(LinkRelation::ACL.to_string(), String::from("acl"));
    }
}