iri_string/types/generic/macros.rs
1//! Macros to define resource identifier types.
2
3/// Implements type conversion from slice into smart pointer.
4macro_rules! impl_from_slice_into_smartptr {
5 (
6 // Generic slice type.
7 ty: $ty:ident,
8 // Smart pointer item path (without type parameter).
9 smartptr: $($smartptr:ident)::*,
10 // Pointer mutability for `into_raw` and `from_raw`.
11 // Use `mut` for `Box`, and `const` for `Arc` and `Rc`.
12 mutability: $mut:ident,
13 ) => {
14 #[cfg(feature = "alloc")]
15 impl<S: crate::spec::Spec> From<&$ty<S>> for $($smartptr)::* <$ty<S>> {
16 fn from(s: &$ty<S>) -> Self {
17 let inner: &str = s.as_str();
18 let buf = $($smartptr)::* ::<str>::from(inner);
19 // SAFETY: `$ty<S>` has `repr(transparent)` attribute, so the
20 // memory layouts of `$smartptr<str>` and `$smartptr<$ty<S>>`
21 // are compatible.
22 unsafe {
23 let raw: *$mut str = $($smartptr)::* ::into_raw(buf);
24 $($smartptr)::* ::<$ty<S>>::from_raw(raw as *$mut $ty<S>)
25 }
26 }
27 }
28 };
29}
30
31/// Implements `PartialEq` and `PartialOrd`.
32macro_rules! impl_cmp {
33 ($ty_common:ty, $ty_lhs:ty, $ty_rhs:ty) => {
34 impl<S: crate::spec::Spec> PartialEq<$ty_rhs> for $ty_lhs {
35 #[inline]
36 fn eq(&self, o: &$ty_rhs) -> bool {
37 <$ty_common as PartialEq<$ty_common>>::eq(self.as_ref(), o.as_ref())
38 }
39 }
40 impl<S: crate::spec::Spec> PartialEq<$ty_lhs> for $ty_rhs {
41 #[inline]
42 fn eq(&self, o: &$ty_lhs) -> bool {
43 <$ty_common as PartialEq<$ty_common>>::eq(self.as_ref(), o.as_ref())
44 }
45 }
46 impl<S: crate::spec::Spec> PartialOrd<$ty_rhs> for $ty_lhs {
47 #[inline]
48 fn partial_cmp(&self, o: &$ty_rhs) -> Option<core::cmp::Ordering> {
49 <$ty_common as PartialOrd<$ty_common>>::partial_cmp(self.as_ref(), o.as_ref())
50 }
51 }
52 impl<S: crate::spec::Spec> PartialOrd<$ty_lhs> for $ty_rhs {
53 #[inline]
54 fn partial_cmp(&self, o: &$ty_lhs) -> Option<core::cmp::Ordering> {
55 <$ty_common as PartialOrd<$ty_common>>::partial_cmp(self.as_ref(), o.as_ref())
56 }
57 }
58 };
59}
60
61/// Implements `PartialEq` and `PartialOrd` with two independent spec type parameter.
62macro_rules! impl_cmp2 {
63 ($ty_common:ty, $ty_lhs:ty, $ty_rhs:ty) => {
64 impl<S: crate::spec::Spec, T: crate::spec::Spec> PartialEq<$ty_rhs> for $ty_lhs {
65 #[inline]
66 fn eq(&self, o: &$ty_rhs) -> bool {
67 <$ty_common as PartialEq<$ty_common>>::eq(self.as_ref(), o.as_ref())
68 }
69 }
70 impl<S: crate::spec::Spec, T: crate::spec::Spec> PartialEq<$ty_lhs> for $ty_rhs {
71 #[inline]
72 fn eq(&self, o: &$ty_lhs) -> bool {
73 <$ty_common as PartialEq<$ty_common>>::eq(self.as_ref(), o.as_ref())
74 }
75 }
76 impl<S: crate::spec::Spec, T: crate::spec::Spec> PartialOrd<$ty_rhs> for $ty_lhs {
77 #[inline]
78 fn partial_cmp(&self, o: &$ty_rhs) -> Option<core::cmp::Ordering> {
79 <$ty_common as PartialOrd<$ty_common>>::partial_cmp(self.as_ref(), o.as_ref())
80 }
81 }
82 impl<S: crate::spec::Spec, T: crate::spec::Spec> PartialOrd<$ty_lhs> for $ty_rhs {
83 #[inline]
84 fn partial_cmp(&self, o: &$ty_lhs) -> Option<core::cmp::Ordering> {
85 <$ty_common as PartialOrd<$ty_common>>::partial_cmp(self.as_ref(), o.as_ref())
86 }
87 }
88 };
89}
90
91/// Implements `PartialEq` and `PartialOrd` with two independent spec type parameter.
92macro_rules! impl_cmp2_as_str {
93 ($ty_lhs:ty, $ty_rhs:ty) => {
94 impl<S: crate::spec::Spec, T: crate::spec::Spec> PartialEq<$ty_rhs> for $ty_lhs {
95 #[inline]
96 fn eq(&self, o: &$ty_rhs) -> bool {
97 PartialEq::eq(self.as_str(), o.as_str())
98 }
99 }
100 impl<S: crate::spec::Spec, T: crate::spec::Spec> PartialEq<$ty_lhs> for $ty_rhs {
101 #[inline]
102 fn eq(&self, o: &$ty_lhs) -> bool {
103 PartialEq::eq(self.as_str(), o.as_str())
104 }
105 }
106 impl<S: crate::spec::Spec, T: crate::spec::Spec> PartialOrd<$ty_rhs> for $ty_lhs {
107 #[inline]
108 fn partial_cmp(&self, o: &$ty_rhs) -> Option<core::cmp::Ordering> {
109 PartialOrd::partial_cmp(self.as_str(), o.as_str())
110 }
111 }
112 impl<S: crate::spec::Spec, T: crate::spec::Spec> PartialOrd<$ty_lhs> for $ty_rhs {
113 #[inline]
114 fn partial_cmp(&self, o: &$ty_lhs) -> Option<core::cmp::Ordering> {
115 PartialOrd::partial_cmp(self.as_str(), o.as_str())
116 }
117 }
118 };
119}
120
121/// Define the custom string slice type, and implements methods and traits.
122///
123/// Methods to be implemented:
124///
125/// * `pub fn new()`
126/// * `pub fn new_unchecked()`
127/// * `pub(crate) fn new_always_unchecked()`
128/// * `pub(crate) fn new_unchecked_justified()`
129/// * `pub(in crate::types) fn validate()`
130/// * `pub fn as_str()`
131/// * `pub fn len()`
132/// * `pub fn is_empty()`
133///
134/// Traits to be implemented:
135///
136/// * fundamental
137/// + `Debug for $ty`
138/// + `Eq for $ty`
139/// + `Ord for $ty`
140/// + `Hash for $ty`
141/// * type conversion
142/// + `AsRef<&str> for $ty`
143/// + `AsRef<&$ty> for $ty`
144/// + `From<&$ty>` for Cow<$ty>`
145/// + `From<&$ty>` for Arc<$ty>`
146/// + `From<&$ty>` for Box<$ty>`
147/// + `From<&$ty>` for Rc<$ty>`
148/// + `From<&$ty> for &str`
149/// + `TryFrom<&str> for &$ty`
150/// + `TryFrom<&[u8]> for &$ty`
151/// * comparison (only `PartialEq` impls are listed, but `PartialOrd` is also implemented).
152/// + `PartialEq<$ty> for $ty`
153/// + `str` and `$ty`
154/// - `PartialEq<str> for $ty`
155/// - `PartialEq<$ty> for str`
156/// - `PartialEq<&str> for $ty`
157/// - `PartialEq<$ty> for &str`
158/// - `PartialEq<str> for &$ty`
159/// - `PartialEq<&$ty> for str`
160/// + `$ty` and `$ty`
161/// - `PartialEq<&$ty> for $ty`
162/// - `PartialEq<$ty> for &$ty`
163/// * other
164/// + `Display for $ty`
165/// * serde
166/// + `serde::Serialize`
167/// + `serde::Deserialize`
168macro_rules! define_custom_string_slice {
169 (
170 $(#[$meta:meta])*
171 struct $ty:ident {
172 validator = $validate:ident,
173 expecting_msg = $expecting:expr,
174 }
175 ) => {
176 $(#[$meta])*
177 // `#[derive(..)]` cannot be used here, because it adds `S: DerivedTrait` bounds automatically.
178 #[repr(transparent)]
179 #[cfg_attr(feature = "serde", derive(serde::Serialize))]
180 #[cfg_attr(feature = "serde", serde(bound = "S: crate::spec::Spec"))]
181 #[cfg_attr(feature = "serde", serde(transparent))]
182 pub struct $ty<S> {
183 /// Spec.
184 #[cfg_attr(feature = "serde", serde(skip))]
185 _spec: core::marker::PhantomData<fn() -> S>,
186 /// Inner data.
187 inner: str,
188 }
189
190 impl<S: crate::spec::Spec> $ty<S> {
191 /// Creates a new string.
192 #[inline]
193 pub fn new(s: &str) -> Result<&Self, crate::validate::Error> {
194 core::convert::TryFrom::try_from(s)
195 }
196
197 /// Creates a new string without validation.
198 ///
199 /// This does not validate the given string, so it is caller's
200 /// responsibility to ensure the given string is valid.
201 ///
202 /// # Safety
203 ///
204 /// The given string must be syntactically valid as `Self` type.
205 /// If not, any use of the returned value or the call of this
206 /// function itself may result in undefined behavior.
207 #[inline]
208 #[must_use]
209 pub unsafe fn new_unchecked(s: &str) -> &Self {
210 // SAFETY: `new_unchecked` requires the same precondition
211 // as `new_always_unchecked`.
212 unsafe { Self::new_always_unchecked(s) }
213 }
214
215 /// Creates a new string without any validation.
216 ///
217 /// This does not validate the given string at any time.
218 ///
219 /// Intended for internal use. This should be used when the
220 /// conversion is done right after the direct validation is done.
221 /// For example, in a code path `T::validate(s)` returned `Ok(_)`,
222 /// this function can be used to convert `s` into the type `T`.
223 ///
224 /// # Safety
225 ///
226 /// The given string must be syntactically valid as `Self` type.
227 #[inline]
228 #[must_use]
229 pub(crate) unsafe fn new_always_unchecked(s: &str) -> &Self {
230 // SAFETY: the cast is safe since `Self` type has `repr(transparent)`
231 // attribute and the content is guaranteed as valid by the
232 // precondition of the function.
233 unsafe { &*(s as *const str as *const Self) }
234 }
235
236 /// Creates a new string possibly without validation.
237 ///
238 /// This does validation on debug build.
239 ///
240 /// Intended for internal use. This should be used when the
241 /// conversion is considered valid based on knowledge of the
242 /// specifications and/or internal algorithms, but the entire input
243 /// is not yet validated.
244 ///
245 /// # Safety
246 ///
247 /// The given string must be syntactically valid as `Self` type.
248 #[inline]
249 #[must_use]
250 pub(crate) unsafe fn new_unchecked_justified<'a>(
251 s: &'a str,
252 reason: &'_ str
253 ) -> &'a Self {
254 debug_assert_eq!(Self::validate(s), Ok(()), "{reason}");
255 // SAFETY: `new_unchecked_justified` requires the same precondition
256 // as `new_always_unchecked`. Additionally in debug build, just
257 // checked the content is actually valid by `Self::validate(s)`.
258 unsafe { Self::new_always_unchecked(s) }
259 }
260
261 /// Checks if the given string content is valid as `Self`.
262 pub(in crate::types) fn validate(s: &str) -> Result<(), crate::validate::Error> {
263 $validate::<S>(s)
264 }
265
266 /// Returns `&str`.
267 #[inline]
268 #[must_use]
269 pub fn as_str(&self) -> &str {
270 self.as_ref()
271 }
272
273 /// Returns the string length.
274 #[inline]
275 #[must_use]
276 pub fn len(&self) -> usize {
277 self.as_str().len()
278 }
279
280 /// Returns whether the string is empty.
281 #[inline]
282 #[must_use]
283 pub fn is_empty(&self) -> bool {
284 self.as_str().is_empty()
285 }
286 }
287
288 impl<S: crate::spec::Spec> core::fmt::Debug for $ty<S> {
289 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
290 f.debug_tuple(stringify!($ty)).field(&&self.inner).finish()
291 }
292 }
293
294 impl<S: crate::spec::Spec> PartialEq for $ty<S> {
295 #[inline]
296 fn eq(&self, other: &Self) -> bool {
297 self.inner == other.inner
298 }
299 }
300
301 impl<S: crate::spec::Spec> Eq for $ty<S> {}
302
303 impl<S: crate::spec::Spec> PartialOrd for $ty<S> {
304 #[inline]
305 fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
306 Some(self.cmp(&other))
307 }
308 }
309
310 impl<S: crate::spec::Spec> Ord for $ty<S> {
311 #[inline]
312 fn cmp(&self, other: &Self) -> core::cmp::Ordering {
313 self.inner.cmp(&other.inner)
314 }
315 }
316
317 impl<S: crate::spec::Spec> core::hash::Hash for $ty<S> {
318 #[inline]
319 fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
320 self.inner.hash(state);
321 }
322 }
323
324 impl<S: crate::spec::Spec> AsRef<str> for $ty<S> {
325 #[inline]
326 fn as_ref(&self) -> &str {
327 &self.inner
328 }
329 }
330
331 impl<S: crate::spec::Spec> AsRef<$ty<S>> for $ty<S> {
332 #[inline]
333 fn as_ref(&self) -> &$ty<S> {
334 self
335 }
336 }
337
338 #[cfg(feature = "alloc")]
339 impl<'a, S: crate::spec::Spec> From<&'a $ty<S>> for alloc::borrow::Cow<'a, $ty<S>> {
340 #[inline]
341 fn from(s: &'a $ty<S>) -> Self {
342 alloc::borrow::Cow::Borrowed(s)
343 }
344 }
345
346 impl_from_slice_into_smartptr! {
347 ty: $ty,
348 smartptr: alloc::sync::Arc,
349 mutability: const,
350 }
351
352 impl_from_slice_into_smartptr! {
353 ty: $ty,
354 smartptr: alloc::boxed::Box,
355 mutability: mut,
356 }
357
358 impl_from_slice_into_smartptr! {
359 ty: $ty,
360 smartptr: alloc::rc::Rc,
361 mutability: const,
362 }
363
364 impl<'a, S: crate::spec::Spec> From<&'a $ty<S>> for &'a str {
365 #[inline]
366 fn from(s: &'a $ty<S>) -> &'a str {
367 s.as_ref()
368 }
369 }
370
371 impl<'a, S: crate::spec::Spec> core::convert::TryFrom<&'a str> for &'a $ty<S> {
372 type Error = crate::validate::Error;
373
374 #[inline]
375 fn try_from(s: &'a str) -> Result<Self, Self::Error> {
376 match <$ty<S>>::validate(s) {
377 // SAFETY: just confirmed `s` is valid as `$ty`.
378 Ok(()) => Ok(unsafe { $ty::new_always_unchecked(s) }),
379 Err(e) => Err(e),
380 }
381 }
382 }
383
384 impl<'a, S: crate::spec::Spec> core::convert::TryFrom<&'a [u8]> for &'a $ty<S> {
385 type Error = crate::validate::Error;
386
387 #[inline]
388 fn try_from(bytes: &'a [u8]) -> Result<Self, Self::Error> {
389 let s = core::str::from_utf8(bytes).map_err(|_| {
390 crate::validate::Error::with_kind(crate::validate::ErrorKind::InvalidUtf8)
391 })?;
392 match <$ty<S>>::validate(s) {
393 // SAFETY: just confirmed `s` is valid as `$ty`.
394 Ok(()) => Ok(unsafe { $ty::new_always_unchecked(s) }),
395 Err(e) => Err(e),
396 }
397 }
398 }
399
400 impl_cmp!(str, str, $ty<S>);
401 impl_cmp!(str, &str, $ty<S>);
402 impl_cmp!(str, str, &$ty<S>);
403 impl_cmp2!(str, &$ty<S>, $ty<T>);
404
405 impl<S: crate::spec::Spec> core::fmt::Display for $ty<S> {
406 #[inline]
407 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
408 f.write_str(self.as_str())
409 }
410 }
411
412 /// Serde deserializer implementation.
413 #[cfg(feature = "serde")]
414 mod __serde_slice {
415 use super::$ty;
416
417 use core::{convert::TryFrom, fmt, marker::PhantomData};
418
419 use serde::{
420 de::{self, Visitor},
421 Deserialize, Deserializer,
422 };
423
424 /// Custom borrowed string visitor.
425 #[derive(Debug, Clone, Copy)]
426 struct CustomStrVisitor<S>(PhantomData<fn() -> S>);
427
428 impl<'de, S: 'de + crate::spec::Spec> Visitor<'de> for CustomStrVisitor<S> {
429 type Value = &'de $ty<S>;
430
431 #[inline]
432 fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
433 f.write_str($expecting)
434 }
435
436 #[inline]
437 fn visit_borrowed_str<E>(self, v: &'de str) -> Result<Self::Value, E>
438 where
439 E: de::Error,
440 {
441 <&'de $ty<S> as TryFrom<&'de str>>::try_from(v).map_err(E::custom)
442 }
443 }
444
445 // About `'de` and `'a`, see
446 // <https://serde.rs/lifetimes.html#the-deserializede-lifetime>.
447 impl<'de: 'a, 'a, S: 'de + crate::spec::Spec> Deserialize<'de> for &'a $ty<S> {
448 #[inline]
449 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
450 where
451 D: Deserializer<'de>,
452 {
453 deserializer.deserialize_string(CustomStrVisitor::<S>(PhantomData))
454 }
455 }
456 }
457 };
458}
459
460/// Define the custom owned string type, and implements methods and traits.
461///
462/// Methods to be implemented:
463///
464/// * `pub fn new_unchecked()`
465/// * `pub(crate) fn new_always_unchecked()`
466/// * `pub(crate) fn new_unchecked_justified()`
467/// * `pub(in crate::types) fn validate()`
468/// * `pub fn shrink_to_fit()`
469///
470/// Traits to be implemented:
471///
472/// * fundamental
473/// + `Debug for $ty`
474/// + `Clone for $ty`
475/// + `Eq for $ty`
476/// + `Ord for $ty`
477/// + `Hash for $ty`
478/// * type conversion
479/// + `AsRef<str> for $ty`
480/// + `AsRef<$slice> for $ty`
481/// + `Borrow<str> for $ty`
482/// + `Borrow<$slice> for $ty`
483/// + `ToOwned<Owned = $ty> for $slice`
484/// + `From<&$slice> for $ty`
485/// + `From<$ty> for String`
486/// + `From<$ty> for Cow<'_, $slice>`
487/// + `From<$ty> for Box<$slice>`
488/// + `TryFrom<&str> for $ty`
489/// + `TryFrom<&[u8]> for $ty`
490/// + `TryFrom<String> for $ty`
491/// + `FromStr for $ty`
492/// + `Deref<Target = $slice> for $ty`
493/// * comparison (only `PartialEq` impls are listed, but `PartialOrd` is also implemented.
494/// + `PartialEq<$ty> for $ty`
495/// + `$slice` and `str`
496/// - `PartialEq<$slice> for Cow<'_, str>`
497/// - `PartialEq<Cow<'_, str>> for $slice`
498/// - `PartialEq<&$slice> for Cow<'_, str>`
499/// - `PartialEq<Cow<'_, str>> for &$slice`
500/// + `$slice` and `Cow<$slice>`
501/// - `PartialEq<$slice> for Cow<'_, $slice>`
502/// - `PartialEq<Cow<'_, $slice>> for $slice`
503/// - `PartialEq<&$slice> for Cow<'_, $slice>`
504/// - `PartialEq<Cow<'_, $slice>> for &$slice`
505/// + `str` and `$ty`
506/// - `PartialEq<str> for $ty`
507/// - `PartialEq<$ty> for str`
508/// - `PartialEq<&str> for $ty`
509/// - `PartialEq<$ty> for &str`
510/// - `PartialEq<Cow<'_, str>> for $ty`
511/// - `PartialEq<$ty> for Cow<'_, str>`
512/// + `String` and `$ty`
513/// - `PartialEq<String> for $ty`
514/// - `PartialEq<$ty> for String`
515/// + `$slice` and `$ty`
516/// - `PartialEq<$slice> for $ty`
517/// - `PartialEq<$ty> for $slice`
518/// - `PartialEq<&$slice> for $ty`
519/// - `PartialEq<$ty> for &$slice`
520/// - `PartialEq<Cow<'_, $slice>> for $ty`
521/// - `PartialEq<$ty> for Cow<'_, $slice>`
522/// * other
523/// + `Display for $ty`
524/// * serde
525/// + `serde::Serialize`
526/// + `serde::Deserialize`
527// Note that `From<$ty> for {Arc,Rc}<$slice>` is currently not implemented since
528// this won't reuse allocated memory and hides internal memory reallocation. See
529// <https://github.com/lo48576/iri-string/issues/20#issuecomment-1105207849>.
530// However, this is not decided with firm belief or opinion, so there would be
531// a chance that they are implemented in future.
532#[cfg(feature = "alloc")]
533macro_rules! define_custom_string_owned {
534 (
535 $(#[$meta:meta])*
536 struct $ty:ident {
537 validator = $validate:ident,
538 slice = $slice:ident,
539 expecting_msg = $expecting:expr,
540 }
541 ) => {
542 $(#[$meta])*
543 // `#[derive(..)]` cannot be used here, because it adds `S: DerivedTrait` bounds automatically.
544 #[cfg(feature = "alloc")]
545 #[cfg_attr(all(feature = "serde", feature = "alloc"), derive(serde::Serialize))]
546 #[cfg_attr(all(feature = "serde", feature = "alloc"), serde(bound = "S: crate::spec::Spec"))]
547 #[cfg_attr(all(feature = "serde", feature = "alloc"), serde(transparent))]
548 pub struct $ty<S> {
549 /// Spec.
550 #[cfg_attr(all(feature = "serde", feature = "alloc"), serde(skip))]
551 _spec: core::marker::PhantomData<fn() -> S>,
552 /// Inner data.
553 inner: alloc::string::String,
554 }
555
556 impl<S: crate::spec::Spec> $ty<S> {
557 /// Creates a new string without validation.
558 ///
559 /// This does not validate the given string, so it is caller's
560 /// responsibility to ensure the given string is valid.
561 ///
562 /// # Safety
563 ///
564 /// The given string must be syntactically valid as `Self` type.
565 /// If not, any use of the returned value or the call of this
566 /// function itself may result in undefined behavior.
567 #[inline]
568 #[must_use]
569 pub unsafe fn new_unchecked(s: alloc::string::String) -> Self {
570 // SAFETY: `new_unchecked` requires the same precondition
571 // as `new_always_unchecked`.
572 unsafe { Self::new_always_unchecked(s) }
573 }
574
575 /// Creates a new string maybe without validation.
576 ///
577 /// This does not validate the given string at any time.
578 ///
579 /// Intended for internal use. This should be used when the
580 /// conversion is done right after the direct validation is done.
581 /// For example, in a code path `T::validate(s)` returned `Ok(_)`,
582 /// this function can be used to convert `s` into the type `T`.
583 ///
584 /// # Safety
585 ///
586 /// The given string must be syntactically valid as `Self` type.
587 #[inline]
588 #[must_use]
589 pub(crate) unsafe fn new_always_unchecked(s: alloc::string::String) -> Self {
590 // The construction itself can be written in safe Rust, but
591 // every other place including unsafe functions expects
592 // `self.inner` to be syntactically valid as `Self`. In order to
593 // make them safe, the construction should validate the value
594 // or at least should require users to validate the value by
595 // making the function `unsafe`.
596 Self {
597 _spec: core::marker::PhantomData,
598 inner: s,
599 }
600 }
601
602 /// Creates a new string possibly without validation.
603 ///
604 /// This does validation on debug build.
605 ///
606 /// Intended for internal use. This should be used when the
607 /// conversion is considered valid based on knowledge of the
608 /// specifications and/or internal algorithms, but the entire input
609 /// is not yet validated.
610 ///
611 /// # Safety
612 ///
613 /// The given string must be syntactically valid as `Self` type.
614 #[must_use]
615 pub(crate) unsafe fn new_unchecked_justified(
616 s: alloc::string::String,
617 reason: &str,
618 ) -> Self {
619 debug_assert_eq!(Self::validate(&s), Ok(()), "{reason}");
620 // SAFETY: `new_unchecked_justified` requires the same precondition
621 // as `new_always_unchecked`. Additionally in debug build, just
622 // checked the content is actually valid by `Self::validate(s)`.
623 unsafe { Self::new_always_unchecked(s) }
624 }
625
626 /// Checks if the given string content is valid as `Self`.
627 pub(in crate::types) fn validate(s: &str) -> Result<(), crate::validate::Error> {
628 $validate::<S>(s)
629 }
630
631 /// Returns a mutable reference to the inner string buffer.
632 ///
633 /// This may be useful to implement inline modification algorithm,
634 /// but be careful as this method itself cannot validate the new
635 /// content.
636 ///
637 /// # Safety
638 ///
639 /// The content after modification must be syntactically valid as
640 /// `Self` type.
641 /// If not, any use of the returned value or the call of this
642 /// function itself may result in undefined behavior.
643 #[inline]
644 #[must_use]
645 // TODO: Use wrapper type to enforce validation on finish?
646 pub(crate) unsafe fn as_inner_mut(&mut self) -> &mut alloc::string::String {
647 &mut self.inner
648 }
649
650 /// Shrinks the capacity of the inner buffer to match its length.
651 #[inline]
652 pub fn shrink_to_fit(&mut self) {
653 self.inner.shrink_to_fit()
654 }
655
656 /// Returns the internal buffer capacity in bytes.
657 #[inline]
658 #[must_use]
659 pub fn capacity(&self) -> usize {
660 self.inner.capacity()
661 }
662
663 /// Returns the borrowed IRI string slice.
664 ///
665 /// This is equivalent to `&*self`.
666 #[inline]
667 #[must_use]
668 pub fn as_slice(&self) -> &$slice<S> {
669 self.as_ref()
670 }
671 }
672
673 impl<S: crate::spec::Spec> core::fmt::Debug for $ty<S> {
674 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
675 f.debug_tuple(stringify!($ty)).field(&&self.inner).finish()
676 }
677 }
678
679 impl<S: crate::spec::Spec> Clone for $ty<S> {
680 #[inline]
681 fn clone(&self) -> Self {
682 // This is safe because `self` must be valid.
683 Self {
684 _spec: core::marker::PhantomData,
685 inner: self.inner.clone(),
686 }
687 }
688 }
689
690 impl<S: crate::spec::Spec, T: crate::spec::Spec> PartialEq<$ty<T>> for $ty<S> {
691 #[inline]
692 fn eq(&self, other: &$ty<T>) -> bool {
693 self.inner == other.inner
694 }
695 }
696
697 impl<S: crate::spec::Spec> Eq for $ty<S> {}
698
699 impl<S: crate::spec::Spec, T: crate::spec::Spec> PartialOrd<$ty<T>> for $ty<S> {
700 #[inline]
701 fn partial_cmp(&self, other: &$ty<T>) -> Option<core::cmp::Ordering> {
702 self.inner.partial_cmp(&other.inner)
703 }
704 }
705
706 impl<S: crate::spec::Spec> Ord for $ty<S> {
707 #[inline]
708 fn cmp(&self, other: &Self) -> core::cmp::Ordering {
709 self.inner.cmp(&other.inner)
710 }
711 }
712
713 impl<S: crate::spec::Spec> core::hash::Hash for $ty<S> {
714 #[inline]
715 fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
716 self.inner.hash(state);
717 }
718 }
719
720 impl<S: crate::spec::Spec> AsRef<str> for $ty<S> {
721 #[inline]
722 fn as_ref(&self) -> &str {
723 &self.inner
724 }
725 }
726
727 impl<S: crate::spec::Spec> AsRef<$slice<S>> for $ty<S> {
728 #[inline]
729 fn as_ref(&self) -> &$slice<S> {
730 // SAFETY: `$ty<S>` and `$slice<S>` requires same validation, so
731 // the content of `self: &$ty<S>` must be valid as `$slice<S>`.
732 unsafe {
733 $slice::new_unchecked_justified(
734 AsRef::<str>::as_ref(self),
735 "conversion between the types of same syntax is always valid",
736 )
737 }
738 }
739 }
740
741 impl<S: crate::spec::Spec> core::borrow::Borrow<str> for $ty<S> {
742 #[inline]
743 fn borrow(&self) -> &str {
744 self.as_ref()
745 }
746 }
747
748 impl<S: crate::spec::Spec> core::borrow::Borrow<$slice<S>> for $ty<S> {
749 #[inline]
750 fn borrow(&self) -> &$slice<S> {
751 self.as_ref()
752 }
753 }
754
755 impl<S: crate::spec::Spec> alloc::borrow::ToOwned for $slice<S> {
756 type Owned = $ty<S>;
757
758 #[inline]
759 fn to_owned(&self) -> Self::Owned {
760 self.into()
761 }
762 }
763
764 impl<S: crate::spec::Spec> From<&'_ $slice<S>> for $ty<S> {
765 #[inline]
766 fn from(s: &$slice<S>) -> Self {
767 // This is safe because `s` must be valid.
768 $ty {
769 _spec: core::marker::PhantomData,
770 inner: alloc::string::String::from(s.as_str()),
771 }
772 }
773 }
774
775 impl<S: crate::spec::Spec> From<$ty<S>> for alloc::string::String {
776 #[inline]
777 fn from(s: $ty<S>) -> Self {
778 s.inner
779 }
780 }
781
782 impl<'a, S: crate::spec::Spec> From<$ty<S>> for alloc::borrow::Cow<'a, $slice<S>> {
783 #[inline]
784 fn from(s: $ty<S>) -> alloc::borrow::Cow<'a, $slice<S>> {
785 alloc::borrow::Cow::Owned(s)
786 }
787 }
788
789 impl<S: crate::spec::Spec> From<$ty<S>> for alloc::boxed::Box<$slice<S>> {
790 #[inline]
791 fn from(s: $ty<S>) -> alloc::boxed::Box<$slice<S>> {
792 let inner: alloc::string::String = s.into();
793 let buf = alloc::boxed::Box::<str>::from(inner);
794 // SAFETY: `$slice<S>` has `repr(transparent)` attribute, so
795 // the memory layouts of `Box<str>` and `Box<$slice<S>>` are
796 // compatible. Additionally, `$ty<S>` and `$slice<S>` require
797 // the same syntax (it is the macro user's responsibility to
798 // guarantee).
799 unsafe {
800 let raw: *mut str = alloc::boxed::Box::into_raw(buf);
801 alloc::boxed::Box::<$slice<S>>::from_raw(raw as *mut $slice<S>)
802 }
803 }
804 }
805
806 impl<S: crate::spec::Spec> core::convert::TryFrom<&'_ str> for $ty<S> {
807 type Error = crate::validate::Error;
808
809 #[inline]
810 fn try_from(s: &str) -> Result<Self, Self::Error> {
811 <&$slice<S>>::try_from(s).map(Into::into)
812 }
813 }
814
815 impl<S: crate::spec::Spec> core::convert::TryFrom<&'_ [u8]> for $ty<S> {
816 type Error = crate::validate::Error;
817
818 #[inline]
819 fn try_from(bytes: &[u8]) -> Result<Self, Self::Error> {
820 let s = core::str::from_utf8(bytes).map_err(|_| {
821 crate::validate::Error::with_kind(crate::validate::ErrorKind::InvalidUtf8)
822 })?;
823 <&$slice<S>>::try_from(s).map(Into::into)
824 }
825 }
826
827 impl<S: crate::spec::Spec> core::convert::TryFrom<alloc::string::String> for $ty<S> {
828 type Error = crate::types::CreationError<alloc::string::String>;
829
830 #[inline]
831 fn try_from(s: alloc::string::String) -> Result<Self, Self::Error> {
832 match <$ty<S>>::validate(s.as_str()) {
833 Ok(_) => {
834 // SAFETY: just confirmed that `s` is valid as `$ty<S>`.
835 Ok(unsafe { Self::new_always_unchecked(s) })
836 }
837 Err(e) => Err(crate::types::CreationError::new(e, s)),
838 }
839 }
840 }
841
842 impl<S: crate::spec::Spec> alloc::str::FromStr for $ty<S> {
843 type Err = crate::validate::Error;
844
845 #[inline]
846 fn from_str(s: &str) -> Result<Self, Self::Err> {
847 core::convert::TryFrom::try_from(s)
848 }
849 }
850
851 impl<S: crate::spec::Spec> core::ops::Deref for $ty<S> {
852 type Target = $slice<S>;
853
854 #[inline]
855 fn deref(&self) -> &$slice<S> {
856 self.as_ref()
857 }
858 }
859
860 impl_cmp!(str, $slice<S>, alloc::borrow::Cow<'_, str>);
861 impl_cmp!(str, &$slice<S>, alloc::borrow::Cow<'_, str>);
862 impl_cmp2_as_str!(&$slice<S>, alloc::borrow::Cow<'_, $slice<T>>);
863
864 impl_cmp!(str, str, $ty<S>);
865 impl_cmp!(str, &str, $ty<S>);
866 impl_cmp!(str, alloc::borrow::Cow<'_, str>, $ty<S>);
867 impl_cmp!(str, alloc::string::String, $ty<S>);
868 impl_cmp2!(str, $slice<S>, $ty<T>);
869 impl_cmp2!(str, &$slice<S>, $ty<T>);
870 impl_cmp2_as_str!(alloc::borrow::Cow<'_, $slice<S>>, $ty<T>);
871
872 impl<S: crate::spec::Spec> core::fmt::Display for $ty<S> {
873 #[inline]
874 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
875 f.write_str(self.as_str())
876 }
877 }
878
879 /// Serde deserializer implementation.
880 #[cfg(all(feature = "alloc", feature = "serde"))]
881 mod __serde_owned {
882 use super::$ty;
883
884 use core::{convert::TryFrom, fmt, marker::PhantomData};
885
886 #[cfg(all(feature = "serde", feature = "alloc"))]
887 use alloc::string::String;
888
889 use serde::{
890 de::{self, Visitor},
891 Deserialize, Deserializer,
892 };
893
894 /// Custom owned string visitor.
895 #[derive(Debug, Clone, Copy)]
896 struct CustomStringVisitor<S>(PhantomData<fn() -> S>);
897
898 impl<'de, S: crate::spec::Spec> Visitor<'de> for CustomStringVisitor<S> {
899 type Value = $ty<S>;
900
901 #[inline]
902 fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
903 f.write_str($expecting)
904 }
905
906 #[inline]
907 fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
908 where
909 E: de::Error,
910 {
911 <$ty<S> as TryFrom<&str>>::try_from(v).map_err(E::custom)
912 }
913
914 #[cfg(all(feature = "serde", feature = "alloc"))]
915 #[inline]
916 fn visit_string<E>(self, v: String) -> Result<Self::Value, E>
917 where
918 E: de::Error,
919 {
920 <$ty<S> as TryFrom<String>>::try_from(v).map_err(E::custom)
921 }
922 }
923
924 impl<'de, S: crate::spec::Spec> Deserialize<'de> for $ty<S> {
925 #[inline]
926 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
927 where
928 D: Deserializer<'de>,
929 {
930 deserializer.deserialize_str(CustomStringVisitor::<S>(PhantomData))
931 }
932 }
933 }
934 };
935}
936
937/// Implements trivial conversions and other useful traits between two IRI types.
938///
939/// Implemented traits:
940///
941/// * type conversion
942/// + `AsRef<$to_slice> for $from_slice`
943/// + `AsRef<$to_slice> for $from_owned`
944/// + `From<$from_slice> for $to_slice`
945/// + `From<$from_owned> for $to_owned`
946/// + `TryFrom<&$to_slice> for &$from_slice`
947/// + `TryFrom<$to_owned> for $from_owned`
948/// * comparison (only `PartialEq` impls are listed, but `PartialOrd` is also implemented).
949/// + `$from_slice` and `$to_slice`
950/// - `PartialEq<$from_slice> for $to_slice`
951/// - `PartialEq<$to_slice> for $from_slice`
952/// - `PartialEq<&$from_slice> for $to_slice`
953/// - `PartialEq<$to_slice> for &$from_slice`
954/// - `PartialEq<$from_slice> for &$to_slice`
955/// - `PartialEq<&$to_slice> for $from_slice`
956/// - `PartialEq<$from_slice> for Cow<'_, $to_slice>`
957/// - `PartialEq<Cow<'_, $to_slice>> for $from_slice`
958/// - `PartialEq<&$from_slice> for Cow<'_, $to_slice>`
959/// - `PartialEq<Cow<'_, $to_slice>> for &$from_slice`
960/// - `PartialEq<Cow<'_, $from_slice>> for $to_slice`
961/// - `PartialEq<$to_slice> for Cow<'_, $from_slice>`
962/// - `PartialEq<Cow<'_, $from_slice>> for &$to_slice`
963/// - `PartialEq<&$to_slice> for Cow<'_, $from_slice>`
964/// + `$from_slice` and `$to_owned`
965/// - `PartialEq<$from_slice> for $to_owned`
966/// - `PartialEq<$to_owned> for $from_slice`
967/// - `PartialEq<&$from_slice> for $to_owned`
968/// - `PartialEq<$to_owned> for &$from_slice`
969/// - `PartialEq<Cow<'_, $from_slice>> for $to_owned`
970/// - `PartialEq<$to_owned> for Cow<'_, $from_slice>`
971/// + `$from_owned` and `$to_slice`
972/// - `PartialEq<$from_owned> for $to_slice`
973/// - `PartialEq<$to_slice> for $from_owned`
974/// - `PartialEq<$from_owned> for &$to_slice`
975/// - `PartialEq<&$to_slice> for $from_owned`
976/// - `PartialEq<$from_owned> for Cow<'_, $to_slice>`
977/// - `PartialEq<Cow<'_, $to_slice>> for $from_owned`
978/// + `$from_owned` and `$to_owned`
979/// - `PartialEq<$from_owned> for $to_owned`
980/// - `PartialEq<$to_owned> for $from_owned`
981macro_rules! impl_trivial_conv_between_iri {
982 (
983 from_slice: $from_slice:ident,
984 from_owned: $from_owned:ident,
985 to_slice: $to_slice:ident,
986 to_owned: $to_owned:ident,
987 ) => {
988 impl<S: crate::spec::Spec> AsRef<$to_slice<S>> for $from_slice<S> {
989 #[inline]
990 fn as_ref(&self) -> &$to_slice<S> {
991 // SAFETY: `$from_slice<S>` should be subset of `$to_slice<S>`.
992 // The caller of `impl_trivial_conv_between_iri!` macro is
993 // responsible for guaranteeing that.
994 unsafe {
995 <$to_slice<S>>::new_unchecked_justified(
996 self.as_str(),
997 "a cast to the superset syntax is always valid",
998 )
999 }
1000 }
1001 }
1002
1003 #[cfg(feature = "alloc")]
1004 impl<S: crate::spec::Spec> AsRef<$to_slice<S>> for $from_owned<S> {
1005 #[inline]
1006 fn as_ref(&self) -> &$to_slice<S> {
1007 AsRef::<$from_slice<S>>::as_ref(self).as_ref()
1008 }
1009 }
1010
1011 impl<'a, S: crate::spec::Spec> From<&'a $from_slice<S>> for &'a $to_slice<S> {
1012 #[inline]
1013 fn from(s: &'a $from_slice<S>) -> &'a $to_slice<S> {
1014 s.as_ref()
1015 }
1016 }
1017
1018 #[cfg(feature = "alloc")]
1019 impl<S: crate::spec::Spec> From<$from_owned<S>> for $to_owned<S> {
1020 #[inline]
1021 fn from(s: $from_owned<S>) -> $to_owned<S> {
1022 // SAFETY: `$from_slice<S>` should be subset of `$to_slice<S>`.
1023 // The caller of `impl_trivial_conv_between_iri!` macro is
1024 // responsible for guaranteeing that.
1025 unsafe {
1026 <$to_owned<S>>::new_unchecked_justified(
1027 s.into(),
1028 "a cast to the superset syntax is always valid",
1029 )
1030 }
1031 }
1032 }
1033
1034 impl<'a, S: crate::spec::Spec> core::convert::TryFrom<&'a $to_slice<S>>
1035 for &'a $from_slice<S>
1036 {
1037 type Error = crate::validate::Error;
1038
1039 #[inline]
1040 fn try_from(s: &'a $to_slice<S>) -> Result<Self, Self::Error> {
1041 Self::try_from(s.as_str())
1042 }
1043 }
1044
1045 #[cfg(feature = "alloc")]
1046 impl<S: crate::spec::Spec> core::convert::TryFrom<$to_owned<S>> for $from_owned<S> {
1047 type Error = crate::types::CreationError<$to_owned<S>>;
1048
1049 fn try_from(s: $to_owned<S>) -> Result<Self, Self::Error> {
1050 match <$from_owned<S>>::validate(s.as_str()) {
1051 // SAFETY: just confirmed `s.as_str()` is valid as `$from_owned<S>`.
1052 Ok(_) => Ok(unsafe { <$from_owned<S>>::new_always_unchecked(s.into()) }),
1053 Err(e) => Err(crate::types::CreationError::new(e, s)),
1054 }
1055 }
1056 }
1057
1058 impl_cmp2_as_str!($from_slice<S>, $to_slice<T>);
1059 impl_cmp2_as_str!(&$from_slice<S>, $to_slice<T>);
1060 impl_cmp2_as_str!($from_slice<S>, &$to_slice<T>);
1061 #[cfg(feature = "alloc")]
1062 impl_cmp2_as_str!($from_slice<S>, alloc::borrow::Cow<'_, $to_slice<T>>);
1063 #[cfg(feature = "alloc")]
1064 impl_cmp2_as_str!(&$from_slice<S>, alloc::borrow::Cow<'_, $to_slice<T>>);
1065 #[cfg(feature = "alloc")]
1066 impl_cmp2_as_str!(alloc::borrow::Cow<'_, $from_slice<S>>, $to_slice<T>);
1067 #[cfg(feature = "alloc")]
1068 impl_cmp2_as_str!(alloc::borrow::Cow<'_, $from_slice<S>>, &$to_slice<T>);
1069
1070 #[cfg(feature = "alloc")]
1071 impl_cmp2_as_str!($from_slice<S>, $to_owned<T>);
1072 #[cfg(feature = "alloc")]
1073 impl_cmp2_as_str!(&$from_slice<S>, $to_owned<T>);
1074 #[cfg(feature = "alloc")]
1075 impl_cmp2_as_str!(alloc::borrow::Cow<'_, $from_slice<S>>, $to_owned<T>);
1076
1077 #[cfg(feature = "alloc")]
1078 impl_cmp2_as_str!($from_owned<S>, $to_slice<T>);
1079 #[cfg(feature = "alloc")]
1080 impl_cmp2_as_str!($from_owned<S>, &$to_slice<T>);
1081 #[cfg(feature = "alloc")]
1082 impl_cmp2_as_str!($from_owned<S>, alloc::borrow::Cow<'_, $to_slice<T>>);
1083 #[cfg(feature = "alloc")]
1084 impl_cmp2_as_str!($from_owned<S>, $to_owned<T>);
1085 };
1086}