Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,9 @@ jobs:
- name: Test
run: cargo nextest run --workspace --lib --all-targets --all-features

- name: Test Docstrings
run: cargo test --doc --workspace --all-features

format:
name: Code Format
runs-on: ubuntu-latest
Expand Down
24 changes: 24 additions & 0 deletions src/curie.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,36 @@
use std::fmt::{Display, Formatter};

/// A parsed CURIE (Compact URI) representation.
///
/// A CURIE consists of a prefix and a reference separated by a colon (`:`),
/// providing a compact way to represent URIs. For example, `HP:0000054` where
/// `HP` is the prefix and `0000054` is the reference.
///
/// This struct stores the CURIE as a single string internally for efficiency,
/// tracking the prefix length to enable zero-copy access to both components.
///
/// # Examples
///
/// ```
/// # use securiety::{Curie, CurieParser, CurieParsing};
/// let parser = CurieParser::general();
/// let curie = parser.parse("prefix:reference").unwrap();
///
/// assert_eq!(curie.prefix(), "prefix");
/// assert_eq!(curie.reference(), "reference");
/// assert_eq!(curie.to_string(), "prefix:reference");
/// ```
#[derive(Debug, Clone, PartialEq, Hash, Eq, PartialOrd, Ord)]
pub struct Curie {
inner: String,
prefix_len: usize,
}

impl Curie {
/// Creates a new `Curie` from a prefix and reference.
///
/// This is an internal constructor used by the parser. Users should typically
/// obtain `Curie` instances through a [`CurieParser`].
pub(crate) fn new(prefix: &str, reference: &str) -> Curie {
let inner = format!("{prefix}:{reference}");
let prefix_len = prefix.len();
Expand Down
52 changes: 52 additions & 0 deletions src/curie_parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,64 @@ use crate::curie::Curie;
use crate::error::CurieParsingError;
use crate::traits::{CurieParsing, CurieValidation};

/// A parser for CURIE (Compact URI) strings that validates input using a configurable validator.
///
/// CURIEs are compact representations of URIs in the form `prefix:reference`, commonly used
/// in semantic web applications and knowledge graphs.
///
/// # Type Parameters
///
/// * `Validator` - A type implementing [`CurieValidation`] used to validate CURIE strings
/// before parsing.
///
/// # Examples
///
/// ```
/// use securiety::{CurieParser, CurieParsing};
///
/// let parser = CurieParser::general();
/// let curie = parser.parse("prefix:reference").unwrap();
/// assert_eq!(curie.prefix(), "prefix");
/// assert_eq!(curie.reference(), "reference");
/// ```
#[derive(Debug, Clone)]
pub struct CurieParser<Validator: CurieValidation> {
pub(crate) validator: Validator,
}

impl<Validator: CurieValidation> CurieParsing for CurieParser<Validator> {
/// Parses a CURIE string into a [`Curie`] instance.
///
/// The parsing process:
/// 1. Validates the input string using the configured validator
/// 2. Splits the string on the colon (`:`) separator
/// 3. Returns a [`Curie`] with the prefix and reference components
///
/// # Arguments
///
/// * `curie` - A string slice containing the CURIE to parse (e.g., "prefix:reference")
///
/// # Returns
///
/// * `Ok(Curie)` - Successfully parsed CURIE
/// * `Err(CurieParsingError::InvalidCurie)` - The input failed validation
/// * `Err(CurieParsingError::UnparsableCurie)` - The input passed validation but
/// couldn't be split into prefix and reference (no colon found)
///
/// # Examples
///
/// ```
/// use securiety::{CurieParser, CurieParsing};
/// let parser = CurieParser::hp();
///
/// // Valid CURIE
/// let result = parser.parse("HP:0000054");
/// assert!(result.is_ok());
///
/// // Invalid CURIE (no colon)
/// let result = parser.parse("invalid");
/// assert!(result.is_err());
/// ```
fn parse(&self, curie: &str) -> Result<Curie, CurieParsingError> {
match self.validator.validate(curie) {
true => {
Expand Down
23 changes: 23 additions & 0 deletions src/validators/regex_validator.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,29 @@
use crate::error::InvalidRegexError;
use crate::traits::CurieValidation;
use regex::Regex;

/// A CURIE validator that uses regular expressions to validate CURIE strings.
///
/// This validator allows flexible validation rules by accepting any regular expression
/// pattern. It's useful when you need custom validation logic beyond simple format checks.
///
/// # Examples
///
/// ```
/// use securiety::{CurieRegexValidator, CurieValidation};
/// use regex::Regex;
/// // Create a validator that requires lowercase prefixes
/// let validator = CurieRegexValidator::general();
///
/// assert!(validator.validate("rdf:type"));
/// ```
///
/// ```
/// use securiety::{CurieRegexValidator, CurieValidation};
/// // Create validator for specific resource
/// let validator = CurieRegexValidator::hp();
/// assert!(validator.validate("HP:0000054"));
/// ```
#[derive(Debug, Clone)]
pub struct CurieRegexValidator {
regex: Regex,
Expand Down