1use crate::{
3 vocabulary::{BlankIdVocabulary, BlankIdVocabularyMut, IriVocabulary},
4 BlankIdBuf, Id, Vocabulary,
5};
6
7pub trait Generator<V: IriVocabulary + BlankIdVocabulary = ()> {
9 fn next(&mut self, vocabulary: &mut V) -> Id<V::Iri, V::BlankId>;
11}
12
13impl<V: IriVocabulary + BlankIdVocabulary, G: Generator<V>> Generator<V> for &mut G {
14 fn next(&mut self, vocabulary: &mut V) -> Id<V::Iri, V::BlankId> {
15 (*self).next(vocabulary)
16 }
17}
18
19#[derive(Default)]
25pub struct Blank {
26 prefix: String,
28
29 count: usize,
31}
32
33impl Blank {
34 pub fn new() -> Self {
36 Self::new_full(String::new(), 0)
37 }
38
39 pub fn new_with_offset(offset: usize) -> Self {
45 Self::new_full(String::new(), offset)
46 }
47
48 pub fn new_with_prefix(prefix: String) -> Self {
50 Self::new_full(prefix, 0)
51 }
52
53 pub fn new_full(prefix: String, offset: usize) -> Self {
59 Self {
60 prefix,
61 count: offset,
62 }
63 }
64
65 pub fn prefix(&self) -> &str {
67 &self.prefix
68 }
69
70 pub fn count(&self) -> usize {
72 self.count
73 }
74
75 pub fn next_blank_id(&mut self) -> BlankIdBuf {
76 let id = unsafe { BlankIdBuf::new_unchecked(format!("_:{}{}", self.prefix, self.count)) };
77 self.count += 1;
78 id
79 }
80}
81
82impl<V: Vocabulary + BlankIdVocabularyMut> Generator<V> for Blank {
83 fn next(&mut self, vocabulary: &mut V) -> Id<V::Iri, V::BlankId> {
84 Id::Blank(vocabulary.insert_blank_id(&self.next_blank_id()))
85 }
86}
87
88pub enum Uuid {
100 #[cfg(feature = "uuid-generator-v3")]
105 V3(uuid::Uuid, String),
106
107 #[cfg(feature = "uuid-generator-v4")]
111 V4,
112
113 #[cfg(feature = "uuid-generator-v5")]
118 V5(uuid::Uuid, String),
119}
120
121#[cfg(any(
122 feature = "uuid-generator-v3",
123 feature = "uuid-generator-v4",
124 feature = "uuid-generator-v5"
125))]
126impl Uuid {
127 pub fn next_uuid(&self) -> uuid::Uuid {
128 match self {
129 #[cfg(feature = "uuid-generator-v3")]
130 Self::V3(vocabulary, name) => uuid::Uuid::new_v3(vocabulary, name.as_bytes()),
131 #[cfg(feature = "uuid-generator-v4")]
132 Self::V4 => uuid::Uuid::new_v4(),
133 #[cfg(feature = "uuid-generator-v5")]
134 Self::V5(vocabulary, name) => uuid::Uuid::new_v5(vocabulary, name.as_bytes()),
135 }
136 }
137
138 #[cfg(feature = "meta")]
139 pub fn with_metadata<M>(self, metadata: M) -> WithMetadata<Self, M>
141 where
142 Self: Sized,
143 {
144 WithMetadata {
145 metadata,
146 generator: self,
147 }
148 }
149
150 #[cfg(feature = "meta")]
151 pub fn with_default_metadata<M: Default>(self) -> WithMetadata<Self, M>
153 where
154 Self: Sized,
155 {
156 WithMetadata {
157 metadata: M::default(),
158 generator: self,
159 }
160 }
161}
162
163#[cfg(any(
164 feature = "uuid-generator-v3",
165 feature = "uuid-generator-v4",
166 feature = "uuid-generator-v5"
167))]
168impl<V: crate::Vocabulary + crate::vocabulary::IriVocabularyMut> Generator<V> for Uuid {
169 fn next(&mut self, vocabulary: &mut V) -> Id<V::Iri, V::BlankId> {
170 let mut buffer: Vec<u8> = vec![0; uuid::adapter::Urn::LENGTH];
171 let uuid = self.next_uuid();
172 let len = uuid.to_urn().encode_lower(buffer.as_mut()).len();
173 buffer.truncate(len);
174
175 Id::Iri(vocabulary.insert_owned(unsafe {
176 iref::IriBuf::new_unchecked(String::from_utf8_unchecked(buffer))
177 }))
178 }
179}
180
181#[cfg(any(
182 feature = "uuid-generator-v3",
183 feature = "uuid-generator-v4",
184 feature = "uuid-generator-v5"
185))]
186#[cfg(test)]
187mod tests {
188 use super::*;
189
190 #[cfg(feature = "uuid-generator-v3")]
191 #[test]
192 fn uuidv3_iri() {
193 let mut uuid_gen = Uuid::V3(
194 uuid::Uuid::parse_str("936DA01F9ABD4d9d80C702AF85C822A8").unwrap(),
195 "test".to_string(),
196 );
197 for _ in 0..100 {
198 let reference: Id = uuid_gen.next(&mut ());
199 assert!(iref::Iri::new(reference.as_str()).is_ok())
200 }
201 }
202
203 #[cfg(feature = "uuid-generator-v4")]
204 #[test]
205 fn uuidv4_iri() {
206 let mut uuid_gen = Uuid::V4;
207 for _ in 0..100 {
208 let reference: Id = uuid_gen.next(&mut ());
209 assert!(iref::Iri::new(reference.as_str()).is_ok())
210 }
211 }
212
213 #[cfg(feature = "uuid-generator-v5")]
214 #[test]
215 fn uuidv5_iri() {
216 let mut uuid_gen = Uuid::V5(
217 uuid::Uuid::parse_str("936DA01F9ABD4d9d80C702AF85C822A8").unwrap(),
218 "test".to_string(),
219 );
220 for _ in 0..100 {
221 let reference: Id = uuid_gen.next(&mut ());
222 assert!(iref::Iri::new(reference.as_str()).is_ok())
223 }
224 }
225}