this repo has no description
1//! Different kinds of [`Tag`]s that can be parsed.
2
3use crate::error::ResolveError;
4use crate::label::DefaultLabel;
5use crate::label::Label;
6#[cfg(doc)]
7use crate::storage::Storage;
8use crate::storage::StorageLock;
9#[cfg(doc)]
10use crate::TagManager;
11#[cfg(feature = "either")]
12use either::Either;
13use itertools::intersperse_with;
14use std::fmt::Display;
15use std::fmt::Formatter;
16use std::fmt::Result as FmtResult;
17use std::hash::BuildHasher;
18use std::marker::PhantomData;
19use string_interner::backend::Backend as InternerBackend;
20use string_interner::DefaultSymbol;
21#[cfg(doc)]
22use string_interner::StringInterner;
23use string_interner::Symbol;
24
25/// A trait defining a [`Tag`] which contains interned data.
26///
27/// The _only_ defining operation of a [`Tag`] is that it can be
28/// converted back into a [`String`] using the [`Storage`] that
29/// created it and the correct separator configured by the [`TagManager`]
30/// that built it.
31///
32/// [`Tag`]s have an underlying [`Symbol`] used to define their storage.
33/// Internally, [`Tag`]s are just a set of [`Symbol`]s used to make
34/// storage and identity comparison cheap while enabling reconstruction
35/// of the original [`String`].
36pub trait Tag {
37 /// The label of the [`TagManager`] used to produce the [`Tag`].
38 type Label: Label;
39
40 /// The [`Symbol`] used by the [`Storage`] as a handle to the stored string data.
41 type Symbol: Symbol;
42
43 /// Get the [`TagKind`] of the current tag.
44 fn kind(&self) -> TagKind;
45
46 /// Try to resolve a [`Tag`] back into a [`String`].
47 fn resolve<B, H>(
48 &self,
49 storage: &StorageLock<'_, Self::Label, B, H>,
50 key_value_separator: KeyValueSep,
51 path_separator: PathSep,
52 ) -> Result<String, ResolveError>
53 where
54 B: InternerBackend<Symbol = Self::Symbol>,
55 H: BuildHasher;
56}
57
58#[cfg(feature = "either")]
59// Auto-impl for `Either` wrapping two `Tag`s.
60impl<L, S, T1, T2> Tag for Either<T1, T2>
61where
62 L: Label,
63 S: Symbol,
64 T1: Tag<Label = L, Symbol = S>,
65 T2: Tag<Label = L, Symbol = S>,
66{
67 type Label = L;
68 type Symbol = S;
69
70 fn resolve<B, H>(
71 &self,
72 storage: &StorageLock<'_, Self::Label, B, H>,
73 key_value_separator: KeyValueSep,
74 path_separator: PathSep,
75 ) -> Result<String, ResolveError>
76 where
77 B: InternerBackend<Symbol = Self::Symbol>,
78 H: BuildHasher,
79 {
80 match self {
81 Either::Left(t) => t.resolve(storage, key_value_separator, path_separator),
82 Either::Right(t) => t.resolve(storage, key_value_separator, path_separator),
83 }
84 }
85
86 fn kind(&self) -> TagKind {
87 match self {
88 Either::Left(t) => t.kind(),
89 Either::Right(t) => t.kind(),
90 }
91 }
92}
93
94//---------------------------------------------------------------------------
95
96/// A [`Tag`] without internal structure.
97///
98/// [`PlainTag`] interns the full contents of a tag together.
99#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
100pub struct PlainTag<L = DefaultLabel, S = DefaultSymbol>(S, PhantomData<L>)
101where
102 L: Label,
103 S: Symbol;
104
105impl<L: Label, S: Symbol> PlainTag<L, S> {
106 /// Construct a new [`PlainTag`].
107 pub(crate) fn new<B, H>(storage: &mut StorageLock<'_, L, B, H>, raw: &str) -> Self
108 where
109 B: InternerBackend<Symbol = S>,
110 H: BuildHasher,
111 {
112 PlainTag(storage.get_or_intern(raw), PhantomData)
113 }
114
115 /// Resolve the whole tag into a [`String`].
116 pub fn resolve<B, H>(&self, storage: &StorageLock<'_, L, B, H>) -> Result<String, ResolveError>
117 where
118 B: InternerBackend<Symbol = S>,
119 H: BuildHasher,
120 {
121 self.resolve_str(storage).map(ToString::to_string)
122 }
123
124 /// Resolve the whole tag into a string slice.
125 ///
126 /// Note that the returned string slice is a view into the underlying interner
127 /// data, which means you're holding a borrow on the interner as long as the slice
128 /// is held. If you want to let go of the borrow, copy the slice into a new owned
129 /// string.
130 pub fn resolve_str<'intern, B, H>(
131 &self,
132 storage: &'intern StorageLock<'_, L, B, H>,
133 ) -> Result<&'intern str, ResolveError>
134 where
135 B: InternerBackend<Symbol = S>,
136 H: BuildHasher,
137 {
138 storage.resolve(self.0).ok_or(ResolveError::TagNotFound)
139 }
140}
141
142impl<L: Label, S: Symbol> Tag for PlainTag<L, S> {
143 type Label = L;
144 type Symbol = S;
145
146 fn resolve<B, H>(
147 &self,
148 storage: &StorageLock<'_, Self::Label, B, H>,
149 _key_value_separator: KeyValueSep,
150 _path_separator: PathSep,
151 ) -> Result<String, ResolveError>
152 where
153 B: InternerBackend<Symbol = Self::Symbol>,
154 H: BuildHasher,
155 {
156 self.resolve(storage)
157 }
158
159 fn kind(&self) -> TagKind {
160 TagKind::Plain
161 }
162}
163
164//---------------------------------------------------------------------------
165
166/// A [`Tag`] composed of a key and a value.
167///
168/// [`KeyValueTag`] interns the key and value separately, on the expectation
169/// that keys especially will be frequently repeated across tags.
170#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
171pub struct KeyValueTag<L = DefaultLabel, S = DefaultSymbol>(S, S, PhantomData<L>)
172where
173 L: Label,
174 S: Symbol;
175
176impl<L: Label, S: Symbol> KeyValueTag<L, S> {
177 /// Construct a new [`KeyValueTag`].
178 pub(crate) fn new<B, H>(storage: &mut StorageLock<'_, L, B, H>, key: &str, value: &str) -> Self
179 where
180 B: InternerBackend<Symbol = S>,
181 H: BuildHasher,
182 {
183 KeyValueTag(
184 storage.get_or_intern(key),
185 storage.get_or_intern(value),
186 PhantomData,
187 )
188 }
189
190 /// Resolve the whole tag into a [`String`].
191 pub fn resolve<B, H>(
192 &self,
193 storage: &StorageLock<'_, L, B, H>,
194 key_value_separator: KeyValueSep,
195 _path_separator: PathSep,
196 ) -> Result<String, ResolveError>
197 where
198 B: InternerBackend<Symbol = S>,
199 H: BuildHasher,
200 {
201 self.resolve_key_value(storage)
202 .map(|(key, value)| format!("{key}{key_value_separator}{value}"))
203 }
204
205 /// Resolve the key and value parts of the tag separately.
206 ///
207 /// Note that the returned string slices are views into the underlying interner
208 /// data, which means you're holding a borrow on the interner as long as the slices
209 /// are held. If you want to let go of the borrow, copy the slices into new owned
210 /// strings.
211 pub fn resolve_key_value<'intern, B, H>(
212 &self,
213 storage: &'intern StorageLock<'_, L, B, H>,
214 ) -> Result<(&'intern str, &'intern str), ResolveError>
215 where
216 B: InternerBackend<Symbol = S>,
217 H: BuildHasher,
218 {
219 let (key, value) = self.try_resolve_key_value(storage);
220 Ok((key?, value?))
221 }
222
223 /// Try to resolve the key and value parts of the tag separately.
224 ///
225 /// This lets you resolve partial tags, if for some reason part of the tag
226 /// resolves and the other doesn't.
227 ///
228 /// Note that the returned string slices are views into the underlying interner
229 /// data, which means you're holding a borrow on the interner as long as the slices
230 /// are held. If you want to let go of the borrow, copy the slices into new owned
231 /// strings.
232 pub fn try_resolve_key_value<'intern, B, H>(
233 &self,
234 storage: &'intern StorageLock<'_, L, B, H>,
235 ) -> (
236 Result<&'intern str, ResolveError>,
237 Result<&'intern str, ResolveError>,
238 )
239 where
240 B: InternerBackend<Symbol = S>,
241 H: BuildHasher,
242 {
243 (
244 storage.resolve(self.0).ok_or(ResolveError::KeyNotFound),
245 storage.resolve(self.1).ok_or(ResolveError::ValueNotFound),
246 )
247 }
248}
249
250impl<L: Label, S: Symbol> Tag for KeyValueTag<L, S> {
251 type Label = L;
252 type Symbol = S;
253
254 fn resolve<B, H>(
255 &self,
256 storage: &StorageLock<'_, Self::Label, B, H>,
257 key_value_separator: KeyValueSep,
258 path_separator: PathSep,
259 ) -> Result<String, ResolveError>
260 where
261 B: InternerBackend<Symbol = Self::Symbol>,
262 H: BuildHasher,
263 {
264 self.resolve(storage, key_value_separator, path_separator)
265 }
266
267 fn kind(&self) -> TagKind {
268 TagKind::KeyValue
269 }
270}
271
272//---------------------------------------------------------------------------
273
274/// A [`Tag`] composed of arbitrary parts.
275///
276/// [`MultipartTag`] interns each part of the tag separately, on the
277/// expectation that individual parts will be frequently repeated.
278#[derive(Debug, Clone, PartialEq, Eq, Hash)]
279pub struct MultipartTag<L = DefaultLabel, S = DefaultSymbol>(Vec<S>, PhantomData<L>)
280where
281 L: Label,
282 S: Symbol;
283
284impl<L: Label, S: Symbol> MultipartTag<L, S> {
285 /// Construct a new [`MultipartTag`].
286 pub(crate) fn new<'part, I, B, H>(storage: &mut StorageLock<'_, L, B, H>, parts: I) -> Self
287 where
288 I: Iterator<Item = &'part str>,
289 B: InternerBackend<Symbol = S>,
290 H: BuildHasher,
291 {
292 MultipartTag(
293 parts.map(|part| storage.get_or_intern(part)).collect(),
294 PhantomData,
295 )
296 }
297
298 /// Resolve the whole tag into a [`String`].
299 pub fn resolve<B, H>(
300 &self,
301 storage: &StorageLock<'_, L, B, H>,
302 _key_value_separator: KeyValueSep,
303 path_separator: PathSep,
304 ) -> Result<String, ResolveError>
305 where
306 B: InternerBackend<Symbol = S>,
307 H: BuildHasher,
308 {
309 intersperse_with(self.try_resolve_parts(storage), || Ok(path_separator.0)).try_fold(
310 String::new(),
311 |mut acc, res| {
312 res.map(|next| {
313 acc.push_str(next);
314 acc
315 })
316 },
317 )
318 }
319
320 /// Resolve each part of the tag.
321 ///
322 /// Note that the returned string slices are views into the underlying interner
323 /// data, which means you're holding a borrow on the interner as long as the slices
324 /// are held. If you want to let go of the borrow, copy the slices into new owned
325 /// strings.
326 pub fn resolve_parts<'intern, B, H, C>(
327 &self,
328 storage: &'intern StorageLock<'_, L, B, H>,
329 ) -> Result<C, ResolveError>
330 where
331 B: InternerBackend<Symbol = S>,
332 H: BuildHasher,
333 C: FromIterator<&'intern str>,
334 {
335 self.try_resolve_parts(storage).collect()
336 }
337
338 /// Try to resolve each part of the tag.
339 ///
340 /// This lets you partially resolve the tag, if for some reason individual
341 /// parts don't resolve.
342 ///
343 /// Note that the returned string slices are views into the underlying interner
344 /// data, which means you're holding a borrow on the interner as long as the slices
345 /// are held. If you want to let go of the borrow, copy the slices into new owned
346 /// strings.
347 pub fn try_resolve_parts<'s, 'intern: 's, B, H>(
348 &'s self,
349 storage: &'intern StorageLock<'_, L, B, H>,
350 ) -> impl Iterator<Item = Result<&'intern str, ResolveError>> + 's
351 where
352 B: InternerBackend<Symbol = S>,
353 H: BuildHasher,
354 {
355 self.0
356 .iter()
357 .copied()
358 .map(|part| storage.resolve(part).ok_or(ResolveError::PartNotFound))
359 }
360}
361
362impl<L: Label, S: Symbol> Tag for MultipartTag<L, S> {
363 type Label = L;
364 type Symbol = S;
365
366 fn resolve<B, H>(
367 &self,
368 storage: &StorageLock<'_, Self::Label, B, H>,
369 key_value_separator: KeyValueSep,
370 path_separator: PathSep,
371 ) -> Result<String, ResolveError>
372 where
373 B: InternerBackend<Symbol = Self::Symbol>,
374 H: BuildHasher,
375 {
376 self.resolve(storage, key_value_separator, path_separator)
377 }
378
379 fn kind(&self) -> TagKind {
380 TagKind::Multipart
381 }
382}
383
384/// The separator between keys and values in a key-value tag.
385///
386/// The default separator is `":"`.
387#[derive(Debug, Copy, Clone)]
388pub struct KeyValueSep(pub &'static str);
389
390impl Display for KeyValueSep {
391 fn fmt(&self, f: &mut Formatter) -> FmtResult {
392 write!(f, "{}", self.0)
393 }
394}
395
396impl Default for KeyValueSep {
397 fn default() -> Self {
398 KeyValueSep(":")
399 }
400}
401
402/// The separator between path segments in a multipart tag.
403///
404/// The default separator is `"/"`.
405#[derive(Debug, Copy, Clone)]
406pub struct PathSep(pub &'static str);
407
408impl Display for PathSep {
409 fn fmt(&self, f: &mut Formatter) -> FmtResult {
410 write!(f, "{}", self.0)
411 }
412}
413
414impl Default for PathSep {
415 fn default() -> Self {
416 PathSep("/")
417 }
418}
419
420/// The kind of tag being worked with.
421#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
422pub enum TagKind {
423 /// A [`PlainTag`].
424 Plain,
425
426 /// A [`KeyValueTag`].
427 KeyValue,
428
429 /// A [`MultipartTag`].
430 Multipart,
431
432 /// A type of [`Tag`] not otherwise known.
433 Other,
434}
435
436/// A trait to implement on types that _carry_ [`Tag`]s.
437///
438/// This trait is generic over the tag type, to permit implementing
439/// it for multiple types of tags.
440pub trait Tagged<T: Tag> {
441 /// The type of iterator used to provide the [`Tag`]s.
442 ///
443 /// The lifetime bounds indicate that the tagged type and the
444 /// tags it produces need to outlive the references to those tags
445 /// returned by the tag iterator.
446 type TagIter<'item>: Iterator<Item = &'item T>
447 where
448 Self: 'item,
449 T: 'item;
450
451 /// Get if the tagged type has tags.
452 ///
453 /// This is included in the API because there's not a good way to get
454 /// the number of elements out of an iterator without using `count()`,
455 /// which consumes the iterator.
456 ///
457 /// `size_hint` unfortunately is `None` for the upper bound by default,
458 /// so it is frequently not useful.
459 fn has_tags(&self) -> bool;
460
461 /// Get the tags of the tagged type.
462 fn get_tags(&self) -> Self::TagIter<'_>;
463}