use crate::ValidId;
use locspan::Meta;
use rdf_types::{BlankIdBuf, BlankIdVocabularyMut, IriVocabularyMut};
pub trait Generator<T, B, M, N> {
fn next(&mut self, vocabulary: &mut N) -> Meta<ValidId<T, B>, M>;
}
impl<'a, T, B, M, N, G: Generator<T, B, M, N>> Generator<T, B, M, N> for &'a mut G {
fn next(&mut self, vocabulary: &mut N) -> Meta<ValidId<T, B>, M> {
(*self).next(vocabulary)
}
}
#[derive(Default)]
pub struct Blank<M> {
metadata: M,
prefix: String,
count: usize,
}
impl<M> Blank<M> {
pub fn new(metadata: M) -> Self {
Self::new_full(metadata, String::new(), 0)
}
pub fn new_with_offset(metadata: M, offset: usize) -> Self {
Self::new_full(metadata, String::new(), offset)
}
pub fn new_with_prefix(metadata: M, prefix: String) -> Self {
Self::new_full(metadata, prefix, 0)
}
pub fn new_full(metadata: M, prefix: String, offset: usize) -> Self {
Self {
metadata,
prefix,
count: offset,
}
}
pub fn metadata(&self) -> &M {
&self.metadata
}
pub fn prefix(&self) -> &str {
&self.prefix
}
pub fn count(&self) -> usize {
self.count
}
pub fn next_blank_id(&mut self) -> BlankIdBuf {
let id = unsafe { BlankIdBuf::new_unchecked(format!("_:{}{}", self.prefix, self.count)) };
self.count += 1;
id
}
}
impl<T, B, M: Clone, N: BlankIdVocabularyMut<BlankId = B>> Generator<T, B, M, N> for Blank<M> {
fn next(&mut self, vocabulary: &mut N) -> Meta<ValidId<T, B>, M> {
Meta(
ValidId::Blank(vocabulary.insert_blank_id(&self.next_blank_id())),
self.metadata.clone(),
)
}
}
pub enum Uuid<M> {
#[cfg(feature = "uuid-generator-v3")]
V3(M, uuid::Uuid, String),
#[cfg(feature = "uuid-generator-v4")]
V4(M),
#[cfg(feature = "uuid-generator-v5")]
V5(M, uuid::Uuid, String),
}
#[cfg(any(
feature = "uuid-generator-v3",
feature = "uuid-generator-v4",
feature = "uuid-generator-v5"
))]
impl<M: Clone> Uuid<M> {
pub fn next_uuid(&self) -> Meta<uuid::Uuid, M> {
match self {
#[cfg(feature = "uuid-generator-v3")]
Self::V3(meta, vocabulary, name) => Meta(
uuid::Uuid::new_v3(vocabulary, name.as_bytes()),
meta.clone(),
),
#[cfg(feature = "uuid-generator-v4")]
Self::V4(meta) => Meta(uuid::Uuid::new_v4(), meta.clone()),
#[cfg(feature = "uuid-generator-v5")]
Self::V5(meta, vocabulary, name) => Meta(
uuid::Uuid::new_v5(vocabulary, name.as_bytes()),
meta.clone(),
),
}
}
}
#[cfg(any(
feature = "uuid-generator-v3",
feature = "uuid-generator-v4",
feature = "uuid-generator-v5"
))]
impl<T, B, M: Clone, N: IriVocabularyMut<Iri = T>> Generator<T, B, M, N> for Uuid<M> {
fn next(&mut self, vocabulary: &mut N) -> Meta<ValidId<T, B>, M> {
unsafe {
let mut buffer = Vec::with_capacity(uuid::adapter::Urn::LENGTH);
let ptr = buffer.as_mut_ptr();
let capacity = buffer.capacity();
std::mem::forget(buffer);
let Meta(uuid, meta) = self.next_uuid();
let len = uuid
.to_urn()
.encode_lower(std::slice::from_raw_parts_mut(
ptr,
uuid::adapter::Urn::LENGTH,
))
.len();
let buffer = Vec::from_raw_parts(ptr, len, capacity);
let p = iref::parsing::ParsedIriRef::new(&buffer).unwrap();
let iri = iref::IriBuf::from_raw_parts(buffer, p);
Meta(ValidId::Iri(vocabulary.insert(iri.as_iri())), meta)
}
}
}
#[cfg(any(
feature = "uuid-generator-v3",
feature = "uuid-generator-v4",
feature = "uuid-generator-v5"
))]
#[cfg(test)]
mod tests {
use super::*;
#[cfg(feature = "uuid-generator-v3")]
#[test]
fn uuidv3_iri() {
let mut uuid_gen = Uuid::V3(
(),
uuid::Uuid::parse_str("936DA01F9ABD4d9d80C702AF85C822A8").unwrap(),
"test".to_string(),
);
for _ in 0..100 {
let reference: ValidId = uuid_gen.next(&mut ()).into_value();
assert!(iref::IriBuf::new(reference.as_str()).is_ok())
}
}
#[cfg(feature = "uuid-generator-v4")]
#[test]
fn uuidv4_iri() {
let mut uuid_gen = Uuid::V4(());
for _ in 0..100 {
let reference: ValidId = uuid_gen.next(&mut ()).into_value();
assert!(iref::IriBuf::new(reference.as_str()).is_ok())
}
}
#[cfg(feature = "uuid-generator-v5")]
#[test]
fn uuidv5_iri() {
let mut uuid_gen = Uuid::V5(
(),
uuid::Uuid::parse_str("936DA01F9ABD4d9d80C702AF85C822A8").unwrap(),
"test".to_string(),
);
for _ in 0..100 {
let reference: ValidId = uuid_gen.next(&mut ()).into_value();
assert!(iref::IriBuf::new(reference.as_str()).is_ok())
}
}
}