uuid/fmt.rs
1// Copyright 2013-2014 The Rust Project Developers.
2// Copyright 2018 The Uuid Project Developers.
3//
4// See the COPYRIGHT file at the top-level directory of this distribution.
5//
6// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
7// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
8// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
9// option. This file may not be copied, modified, or distributed
10// except according to those terms.
11
12//! Adapters for alternative string formats.
13
14use core::str::FromStr;
15
16use crate::{
17 std::{borrow::Borrow, fmt, str},
18 Error, Uuid, Variant,
19};
20
21#[cfg(feature = "std")]
22use crate::std::string::{String, ToString};
23
24impl std::fmt::Debug for Uuid {
25 #[inline]
26 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
27 fmt::LowerHex::fmt(self, f)
28 }
29}
30
31impl fmt::Display for Uuid {
32 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
33 fmt::LowerHex::fmt(self, f)
34 }
35}
36
37#[cfg(feature = "std")]
38impl From<Uuid> for String {
39 fn from(uuid: Uuid) -> Self {
40 uuid.to_string()
41 }
42}
43
44impl fmt::Display for Variant {
45 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
46 match *self {
47 Variant::NCS => write!(f, "NCS"),
48 Variant::RFC4122 => write!(f, "RFC4122"),
49 Variant::Microsoft => write!(f, "Microsoft"),
50 Variant::Future => write!(f, "Future"),
51 }
52 }
53}
54
55impl fmt::LowerHex for Uuid {
56 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
57 fmt::LowerHex::fmt(self.as_hyphenated(), f)
58 }
59}
60
61impl fmt::UpperHex for Uuid {
62 #[inline]
63 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
64 fmt::UpperHex::fmt(self.as_hyphenated(), f)
65 }
66}
67
68/// Format a [`Uuid`] as a hyphenated string, like
69/// `67e55044-10b1-426f-9247-bb680e5fe0c8`.
70#[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
71#[cfg_attr(
72 all(uuid_unstable, feature = "zerocopy"),
73 derive(
74 zerocopy::IntoBytes,
75 zerocopy::FromBytes,
76 zerocopy::KnownLayout,
77 zerocopy::Immutable,
78 zerocopy::Unaligned
79 )
80)]
81#[repr(transparent)]
82pub struct Hyphenated(Uuid);
83
84/// Format a [`Uuid`] as a simple string, like
85/// `67e5504410b1426f9247bb680e5fe0c8`.
86#[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
87#[cfg_attr(
88 all(uuid_unstable, feature = "zerocopy"),
89 derive(
90 zerocopy::IntoBytes,
91 zerocopy::FromBytes,
92 zerocopy::KnownLayout,
93 zerocopy::Immutable,
94 zerocopy::Unaligned
95 )
96)]
97#[repr(transparent)]
98pub struct Simple(Uuid);
99
100/// Format a [`Uuid`] as a URN string, like
101/// `urn:uuid:67e55044-10b1-426f-9247-bb680e5fe0c8`.
102#[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
103#[cfg_attr(
104 all(uuid_unstable, feature = "zerocopy"),
105 derive(
106 zerocopy::IntoBytes,
107 zerocopy::FromBytes,
108 zerocopy::KnownLayout,
109 zerocopy::Immutable,
110 zerocopy::Unaligned
111 )
112)]
113#[repr(transparent)]
114pub struct Urn(Uuid);
115
116/// Format a [`Uuid`] as a braced hyphenated string, like
117/// `{67e55044-10b1-426f-9247-bb680e5fe0c8}`.
118#[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
119#[cfg_attr(
120 all(uuid_unstable, feature = "zerocopy"),
121 derive(
122 zerocopy::IntoBytes,
123 zerocopy::FromBytes,
124 zerocopy::KnownLayout,
125 zerocopy::Immutable,
126 zerocopy::Unaligned
127 )
128)]
129#[repr(transparent)]
130pub struct Braced(Uuid);
131
132impl Uuid {
133 /// Get a [`Hyphenated`] formatter.
134 #[inline]
135 pub const fn hyphenated(self) -> Hyphenated {
136 Hyphenated(self)
137 }
138
139 /// Get a borrowed [`Hyphenated`] formatter.
140 #[inline]
141 pub fn as_hyphenated(&self) -> &Hyphenated {
142 unsafe_transmute_ref!(self)
143 }
144
145 /// Get a [`Simple`] formatter.
146 #[inline]
147 pub const fn simple(self) -> Simple {
148 Simple(self)
149 }
150
151 /// Get a borrowed [`Simple`] formatter.
152 #[inline]
153 pub fn as_simple(&self) -> &Simple {
154 unsafe_transmute_ref!(self)
155 }
156
157 /// Get a [`Urn`] formatter.
158 #[inline]
159 pub const fn urn(self) -> Urn {
160 Urn(self)
161 }
162
163 /// Get a borrowed [`Urn`] formatter.
164 #[inline]
165 pub fn as_urn(&self) -> &Urn {
166 unsafe_transmute_ref!(self)
167 }
168
169 /// Get a [`Braced`] formatter.
170 #[inline]
171 pub const fn braced(self) -> Braced {
172 Braced(self)
173 }
174
175 /// Get a borrowed [`Braced`] formatter.
176 #[inline]
177 pub fn as_braced(&self) -> &Braced {
178 unsafe_transmute_ref!(self)
179 }
180}
181
182const UPPER: [u8; 16] = [
183 b'0', b'1', b'2', b'3', b'4', b'5', b'6', b'7', b'8', b'9', b'A', b'B', b'C', b'D', b'E', b'F',
184];
185const LOWER: [u8; 16] = [
186 b'0', b'1', b'2', b'3', b'4', b'5', b'6', b'7', b'8', b'9', b'a', b'b', b'c', b'd', b'e', b'f',
187];
188
189#[inline]
190const fn format_simple(src: &[u8; 16], upper: bool) -> [u8; 32] {
191 let lut = if upper { &UPPER } else { &LOWER };
192 let mut dst = [0; 32];
193 let mut i = 0;
194 while i < 16 {
195 let x = src[i];
196 dst[i * 2] = lut[(x >> 4) as usize];
197 dst[i * 2 + 1] = lut[(x & 0x0f) as usize];
198 i += 1;
199 }
200 dst
201}
202
203#[inline]
204const fn format_hyphenated(src: &[u8; 16], upper: bool) -> [u8; 36] {
205 let lut = if upper { &UPPER } else { &LOWER };
206 let groups = [(0, 8), (9, 13), (14, 18), (19, 23), (24, 36)];
207 let mut dst = [0; 36];
208
209 let mut group_idx = 0;
210 let mut i = 0;
211 while group_idx < 5 {
212 let (start, end) = groups[group_idx];
213 let mut j = start;
214 while j < end {
215 let x = src[i];
216 i += 1;
217
218 dst[j] = lut[(x >> 4) as usize];
219 dst[j + 1] = lut[(x & 0x0f) as usize];
220 j += 2;
221 }
222 if group_idx < 4 {
223 dst[end] = b'-';
224 }
225 group_idx += 1;
226 }
227 dst
228}
229
230#[inline]
231fn encode_simple<'b>(src: &[u8; 16], buffer: &'b mut [u8], upper: bool) -> &'b mut str {
232 let buf = &mut buffer[..Simple::LENGTH];
233 let buf: &mut [u8; Simple::LENGTH] = buf.try_into().unwrap();
234 *buf = format_simple(src, upper);
235
236 // SAFETY: The encoded buffer is ASCII encoded
237 unsafe { str::from_utf8_unchecked_mut(buf) }
238}
239
240#[inline]
241fn encode_hyphenated<'b>(src: &[u8; 16], buffer: &'b mut [u8], upper: bool) -> &'b mut str {
242 let buf = &mut buffer[..Hyphenated::LENGTH];
243 let buf: &mut [u8; Hyphenated::LENGTH] = buf.try_into().unwrap();
244 *buf = format_hyphenated(src, upper);
245
246 // SAFETY: The encoded buffer is ASCII encoded
247 unsafe { str::from_utf8_unchecked_mut(buf) }
248}
249
250#[inline]
251fn encode_braced<'b>(src: &[u8; 16], buffer: &'b mut [u8], upper: bool) -> &'b mut str {
252 let buf = &mut buffer[..Hyphenated::LENGTH + 2];
253 let buf: &mut [u8; Hyphenated::LENGTH + 2] = buf.try_into().unwrap();
254
255 #[cfg_attr(all(uuid_unstable, feature = "zerocopy"), derive(zerocopy::IntoBytes))]
256 #[repr(C)]
257 struct Braced {
258 open_curly: u8,
259 hyphenated: [u8; Hyphenated::LENGTH],
260 close_curly: u8,
261 }
262
263 let braced = Braced {
264 open_curly: b'{',
265 hyphenated: format_hyphenated(src, upper),
266 close_curly: b'}',
267 };
268
269 *buf = unsafe_transmute!(braced);
270
271 // SAFETY: The encoded buffer is ASCII encoded
272 unsafe { str::from_utf8_unchecked_mut(buf) }
273}
274
275#[inline]
276fn encode_urn<'b>(src: &[u8; 16], buffer: &'b mut [u8], upper: bool) -> &'b mut str {
277 let buf = &mut buffer[..Urn::LENGTH];
278 buf[..9].copy_from_slice(b"urn:uuid:");
279
280 let dst = &mut buf[9..(9 + Hyphenated::LENGTH)];
281 let dst: &mut [u8; Hyphenated::LENGTH] = dst.try_into().unwrap();
282 *dst = format_hyphenated(src, upper);
283
284 // SAFETY: The encoded buffer is ASCII encoded
285 unsafe { str::from_utf8_unchecked_mut(buf) }
286}
287
288impl Hyphenated {
289 /// The length of a hyphenated [`Uuid`] string.
290 ///
291 /// [`Uuid`]: ../struct.Uuid.html
292 pub const LENGTH: usize = 36;
293
294 /// Creates a [`Hyphenated`] from a [`Uuid`].
295 ///
296 /// [`Uuid`]: ../struct.Uuid.html
297 /// [`Hyphenated`]: struct.Hyphenated.html
298 pub const fn from_uuid(uuid: Uuid) -> Self {
299 Hyphenated(uuid)
300 }
301
302 /// Writes the [`Uuid`] as a lower-case hyphenated string to
303 /// `buffer`, and returns the subslice of the buffer that contains the
304 /// encoded UUID.
305 ///
306 /// This is slightly more efficient than using the formatting
307 /// infrastructure as it avoids virtual calls, and may avoid
308 /// double buffering.
309 ///
310 /// [`Uuid`]: ../struct.Uuid.html
311 ///
312 /// # Panics
313 ///
314 /// Panics if the buffer is not large enough: it must have length at least
315 /// [`LENGTH`]. [`Uuid::encode_buffer`] can be used to get a
316 /// sufficiently-large temporary buffer.
317 ///
318 /// [`LENGTH`]: #associatedconstant.LENGTH
319 /// [`Uuid::encode_buffer`]: ../struct.Uuid.html#method.encode_buffer
320 ///
321 /// # Examples
322 ///
323 /// ```rust
324 /// use uuid::Uuid;
325 ///
326 /// fn main() -> Result<(), uuid::Error> {
327 /// let uuid = Uuid::parse_str("936DA01f9abd4d9d80c702af85c822a8")?;
328 ///
329 /// // the encoded portion is returned
330 /// assert_eq!(
331 /// uuid.hyphenated()
332 /// .encode_lower(&mut Uuid::encode_buffer()),
333 /// "936da01f-9abd-4d9d-80c7-02af85c822a8"
334 /// );
335 ///
336 /// // the buffer is mutated directly, and trailing contents remains
337 /// let mut buf = [b'!'; 40];
338 /// uuid.hyphenated().encode_lower(&mut buf);
339 /// assert_eq!(
340 /// &buf as &[_],
341 /// b"936da01f-9abd-4d9d-80c7-02af85c822a8!!!!" as &[_]
342 /// );
343 ///
344 /// Ok(())
345 /// }
346 /// ```
347 /// */
348 #[inline]
349 pub fn encode_lower<'buf>(&self, buffer: &'buf mut [u8]) -> &'buf mut str {
350 encode_hyphenated(self.0.as_bytes(), buffer, false)
351 }
352
353 /// Writes the [`Uuid`] as an upper-case hyphenated string to
354 /// `buffer`, and returns the subslice of the buffer that contains the
355 /// encoded UUID.
356 ///
357 /// This is slightly more efficient than using the formatting
358 /// infrastructure as it avoids virtual calls, and may avoid
359 /// double buffering.
360 ///
361 /// [`Uuid`]: ../struct.Uuid.html
362 ///
363 /// # Panics
364 ///
365 /// Panics if the buffer is not large enough: it must have length at least
366 /// [`LENGTH`]. [`Uuid::encode_buffer`] can be used to get a
367 /// sufficiently-large temporary buffer.
368 ///
369 /// [`LENGTH`]: #associatedconstant.LENGTH
370 /// [`Uuid::encode_buffer`]: ../struct.Uuid.html#method.encode_buffer
371 ///
372 /// # Examples
373 ///
374 /// ```rust
375 /// use uuid::Uuid;
376 ///
377 /// fn main() -> Result<(), uuid::Error> {
378 /// let uuid = Uuid::parse_str("936da01f9abd4d9d80c702af85c822a8")?;
379 ///
380 /// // the encoded portion is returned
381 /// assert_eq!(
382 /// uuid.hyphenated()
383 /// .encode_upper(&mut Uuid::encode_buffer()),
384 /// "936DA01F-9ABD-4D9D-80C7-02AF85C822A8"
385 /// );
386 ///
387 /// // the buffer is mutated directly, and trailing contents remains
388 /// let mut buf = [b'!'; 40];
389 /// uuid.hyphenated().encode_upper(&mut buf);
390 /// assert_eq!(
391 /// &buf as &[_],
392 /// b"936DA01F-9ABD-4D9D-80C7-02AF85C822A8!!!!" as &[_]
393 /// );
394 ///
395 /// Ok(())
396 /// }
397 /// ```
398 /// */
399 #[inline]
400 pub fn encode_upper<'buf>(&self, buffer: &'buf mut [u8]) -> &'buf mut str {
401 encode_hyphenated(self.0.as_bytes(), buffer, true)
402 }
403
404 /// Get a reference to the underlying [`Uuid`].
405 ///
406 /// # Examples
407 ///
408 /// ```rust
409 /// use uuid::Uuid;
410 ///
411 /// let hyphenated = Uuid::nil().hyphenated();
412 /// assert_eq!(*hyphenated.as_uuid(), Uuid::nil());
413 /// ```
414 pub const fn as_uuid(&self) -> &Uuid {
415 &self.0
416 }
417
418 /// Consumes the [`Hyphenated`], returning the underlying [`Uuid`].
419 ///
420 /// # Examples
421 ///
422 /// ```rust
423 /// use uuid::Uuid;
424 ///
425 /// let hyphenated = Uuid::nil().hyphenated();
426 /// assert_eq!(hyphenated.into_uuid(), Uuid::nil());
427 /// ```
428 pub const fn into_uuid(self) -> Uuid {
429 self.0
430 }
431}
432
433impl Braced {
434 /// The length of a braced [`Uuid`] string.
435 ///
436 /// [`Uuid`]: ../struct.Uuid.html
437 pub const LENGTH: usize = 38;
438
439 /// Creates a [`Braced`] from a [`Uuid`].
440 ///
441 /// [`Uuid`]: ../struct.Uuid.html
442 /// [`Braced`]: struct.Braced.html
443 pub const fn from_uuid(uuid: Uuid) -> Self {
444 Braced(uuid)
445 }
446
447 /// Writes the [`Uuid`] as a lower-case hyphenated string surrounded by
448 /// braces to `buffer`, and returns the subslice of the buffer that contains
449 /// the encoded UUID.
450 ///
451 /// This is slightly more efficient than using the formatting
452 /// infrastructure as it avoids virtual calls, and may avoid
453 /// double buffering.
454 ///
455 /// [`Uuid`]: ../struct.Uuid.html
456 ///
457 /// # Panics
458 ///
459 /// Panics if the buffer is not large enough: it must have length at least
460 /// [`LENGTH`]. [`Uuid::encode_buffer`] can be used to get a
461 /// sufficiently-large temporary buffer.
462 ///
463 /// [`LENGTH`]: #associatedconstant.LENGTH
464 /// [`Uuid::encode_buffer`]: ../struct.Uuid.html#method.encode_buffer
465 ///
466 /// # Examples
467 ///
468 /// ```rust
469 /// use uuid::Uuid;
470 ///
471 /// fn main() -> Result<(), uuid::Error> {
472 /// let uuid = Uuid::parse_str("936DA01f9abd4d9d80c702af85c822a8")?;
473 ///
474 /// // the encoded portion is returned
475 /// assert_eq!(
476 /// uuid.braced()
477 /// .encode_lower(&mut Uuid::encode_buffer()),
478 /// "{936da01f-9abd-4d9d-80c7-02af85c822a8}"
479 /// );
480 ///
481 /// // the buffer is mutated directly, and trailing contents remains
482 /// let mut buf = [b'!'; 40];
483 /// uuid.braced().encode_lower(&mut buf);
484 /// assert_eq!(
485 /// &buf as &[_],
486 /// b"{936da01f-9abd-4d9d-80c7-02af85c822a8}!!" as &[_]
487 /// );
488 ///
489 /// Ok(())
490 /// }
491 /// ```
492 /// */
493 #[inline]
494 pub fn encode_lower<'buf>(&self, buffer: &'buf mut [u8]) -> &'buf mut str {
495 encode_braced(self.0.as_bytes(), buffer, false)
496 }
497
498 /// Writes the [`Uuid`] as an upper-case hyphenated string surrounded by
499 /// braces to `buffer`, and returns the subslice of the buffer that contains
500 /// the encoded UUID.
501 ///
502 /// This is slightly more efficient than using the formatting
503 /// infrastructure as it avoids virtual calls, and may avoid
504 /// double buffering.
505 ///
506 /// [`Uuid`]: ../struct.Uuid.html
507 ///
508 /// # Panics
509 ///
510 /// Panics if the buffer is not large enough: it must have length at least
511 /// [`LENGTH`]. [`Uuid::encode_buffer`] can be used to get a
512 /// sufficiently-large temporary buffer.
513 ///
514 /// [`LENGTH`]: #associatedconstant.LENGTH
515 /// [`Uuid::encode_buffer`]: ../struct.Uuid.html#method.encode_buffer
516 ///
517 /// # Examples
518 ///
519 /// ```rust
520 /// use uuid::Uuid;
521 ///
522 /// fn main() -> Result<(), uuid::Error> {
523 /// let uuid = Uuid::parse_str("936da01f9abd4d9d80c702af85c822a8")?;
524 ///
525 /// // the encoded portion is returned
526 /// assert_eq!(
527 /// uuid.braced()
528 /// .encode_upper(&mut Uuid::encode_buffer()),
529 /// "{936DA01F-9ABD-4D9D-80C7-02AF85C822A8}"
530 /// );
531 ///
532 /// // the buffer is mutated directly, and trailing contents remains
533 /// let mut buf = [b'!'; 40];
534 /// uuid.braced().encode_upper(&mut buf);
535 /// assert_eq!(
536 /// &buf as &[_],
537 /// b"{936DA01F-9ABD-4D9D-80C7-02AF85C822A8}!!" as &[_]
538 /// );
539 ///
540 /// Ok(())
541 /// }
542 /// ```
543 /// */
544 #[inline]
545 pub fn encode_upper<'buf>(&self, buffer: &'buf mut [u8]) -> &'buf mut str {
546 encode_braced(self.0.as_bytes(), buffer, true)
547 }
548
549 /// Get a reference to the underlying [`Uuid`].
550 ///
551 /// # Examples
552 ///
553 /// ```rust
554 /// use uuid::Uuid;
555 ///
556 /// let braced = Uuid::nil().braced();
557 /// assert_eq!(*braced.as_uuid(), Uuid::nil());
558 /// ```
559 pub const fn as_uuid(&self) -> &Uuid {
560 &self.0
561 }
562
563 /// Consumes the [`Braced`], returning the underlying [`Uuid`].
564 ///
565 /// # Examples
566 ///
567 /// ```rust
568 /// use uuid::Uuid;
569 ///
570 /// let braced = Uuid::nil().braced();
571 /// assert_eq!(braced.into_uuid(), Uuid::nil());
572 /// ```
573 pub const fn into_uuid(self) -> Uuid {
574 self.0
575 }
576}
577
578impl Simple {
579 /// The length of a simple [`Uuid`] string.
580 ///
581 /// [`Uuid`]: ../struct.Uuid.html
582 pub const LENGTH: usize = 32;
583
584 /// Creates a [`Simple`] from a [`Uuid`].
585 ///
586 /// [`Uuid`]: ../struct.Uuid.html
587 /// [`Simple`]: struct.Simple.html
588 pub const fn from_uuid(uuid: Uuid) -> Self {
589 Simple(uuid)
590 }
591
592 /// Writes the [`Uuid`] as a lower-case simple string to `buffer`,
593 /// and returns the subslice of the buffer that contains the encoded UUID.
594 ///
595 /// This is slightly more efficient than using the formatting
596 /// infrastructure as it avoids virtual calls, and may avoid
597 /// double buffering.
598 ///
599 /// [`Uuid`]: ../struct.Uuid.html
600 ///
601 /// # Panics
602 ///
603 /// Panics if the buffer is not large enough: it must have length at least
604 /// [`LENGTH`]. [`Uuid::encode_buffer`] can be used to get a
605 /// sufficiently-large temporary buffer.
606 ///
607 /// [`LENGTH`]: #associatedconstant.LENGTH
608 /// [`Uuid::encode_buffer`]: ../struct.Uuid.html#method.encode_buffer
609 ///
610 /// # Examples
611 ///
612 /// ```rust
613 /// use uuid::Uuid;
614 ///
615 /// fn main() -> Result<(), uuid::Error> {
616 /// let uuid = Uuid::parse_str("936DA01f9abd4d9d80c702af85c822a8")?;
617 ///
618 /// // the encoded portion is returned
619 /// assert_eq!(
620 /// uuid.simple().encode_lower(&mut Uuid::encode_buffer()),
621 /// "936da01f9abd4d9d80c702af85c822a8"
622 /// );
623 ///
624 /// // the buffer is mutated directly, and trailing contents remains
625 /// let mut buf = [b'!'; 36];
626 /// assert_eq!(
627 /// uuid.simple().encode_lower(&mut buf),
628 /// "936da01f9abd4d9d80c702af85c822a8"
629 /// );
630 /// assert_eq!(
631 /// &buf as &[_],
632 /// b"936da01f9abd4d9d80c702af85c822a8!!!!" as &[_]
633 /// );
634 ///
635 /// Ok(())
636 /// }
637 /// ```
638 /// */
639 #[inline]
640 pub fn encode_lower<'buf>(&self, buffer: &'buf mut [u8]) -> &'buf mut str {
641 encode_simple(self.0.as_bytes(), buffer, false)
642 }
643
644 /// Writes the [`Uuid`] as an upper-case simple string to `buffer`,
645 /// and returns the subslice of the buffer that contains the encoded UUID.
646 ///
647 /// [`Uuid`]: ../struct.Uuid.html
648 ///
649 /// # Panics
650 ///
651 /// Panics if the buffer is not large enough: it must have length at least
652 /// [`LENGTH`]. [`Uuid::encode_buffer`] can be used to get a
653 /// sufficiently-large temporary buffer.
654 ///
655 /// [`LENGTH`]: #associatedconstant.LENGTH
656 /// [`Uuid::encode_buffer`]: ../struct.Uuid.html#method.encode_buffer
657 ///
658 /// # Examples
659 ///
660 /// ```rust
661 /// use uuid::Uuid;
662 ///
663 /// fn main() -> Result<(), uuid::Error> {
664 /// let uuid = Uuid::parse_str("936da01f9abd4d9d80c702af85c822a8")?;
665 ///
666 /// // the encoded portion is returned
667 /// assert_eq!(
668 /// uuid.simple().encode_upper(&mut Uuid::encode_buffer()),
669 /// "936DA01F9ABD4D9D80C702AF85C822A8"
670 /// );
671 ///
672 /// // the buffer is mutated directly, and trailing contents remains
673 /// let mut buf = [b'!'; 36];
674 /// assert_eq!(
675 /// uuid.simple().encode_upper(&mut buf),
676 /// "936DA01F9ABD4D9D80C702AF85C822A8"
677 /// );
678 /// assert_eq!(
679 /// &buf as &[_],
680 /// b"936DA01F9ABD4D9D80C702AF85C822A8!!!!" as &[_]
681 /// );
682 ///
683 /// Ok(())
684 /// }
685 /// ```
686 /// */
687 #[inline]
688 pub fn encode_upper<'buf>(&self, buffer: &'buf mut [u8]) -> &'buf mut str {
689 encode_simple(self.0.as_bytes(), buffer, true)
690 }
691
692 /// Get a reference to the underlying [`Uuid`].
693 ///
694 /// # Examples
695 ///
696 /// ```rust
697 /// use uuid::Uuid;
698 ///
699 /// let simple = Uuid::nil().simple();
700 /// assert_eq!(*simple.as_uuid(), Uuid::nil());
701 /// ```
702 pub const fn as_uuid(&self) -> &Uuid {
703 &self.0
704 }
705
706 /// Consumes the [`Simple`], returning the underlying [`Uuid`].
707 ///
708 /// # Examples
709 ///
710 /// ```rust
711 /// use uuid::Uuid;
712 ///
713 /// let simple = Uuid::nil().simple();
714 /// assert_eq!(simple.into_uuid(), Uuid::nil());
715 /// ```
716 pub const fn into_uuid(self) -> Uuid {
717 self.0
718 }
719}
720
721impl Urn {
722 /// The length of a URN [`Uuid`] string.
723 ///
724 /// [`Uuid`]: ../struct.Uuid.html
725 pub const LENGTH: usize = 45;
726
727 /// Creates a [`Urn`] from a [`Uuid`].
728 ///
729 /// [`Uuid`]: ../struct.Uuid.html
730 /// [`Urn`]: struct.Urn.html
731 pub const fn from_uuid(uuid: Uuid) -> Self {
732 Urn(uuid)
733 }
734
735 /// Writes the [`Uuid`] as a lower-case URN string to
736 /// `buffer`, and returns the subslice of the buffer that contains the
737 /// encoded UUID.
738 ///
739 /// This is slightly more efficient than using the formatting
740 /// infrastructure as it avoids virtual calls, and may avoid
741 /// double buffering.
742 ///
743 /// [`Uuid`]: ../struct.Uuid.html
744 ///
745 /// # Panics
746 ///
747 /// Panics if the buffer is not large enough: it must have length at least
748 /// [`LENGTH`]. [`Uuid::encode_buffer`] can be used to get a
749 /// sufficiently-large temporary buffer.
750 ///
751 /// [`LENGTH`]: #associatedconstant.LENGTH
752 /// [`Uuid::encode_buffer`]: ../struct.Uuid.html#method.encode_buffer
753 ///
754 /// # Examples
755 ///
756 /// ```rust
757 /// use uuid::Uuid;
758 ///
759 /// fn main() -> Result<(), uuid::Error> {
760 /// let uuid = Uuid::parse_str("936DA01f9abd4d9d80c702af85c822a8")?;
761 ///
762 /// // the encoded portion is returned
763 /// assert_eq!(
764 /// uuid.urn().encode_lower(&mut Uuid::encode_buffer()),
765 /// "urn:uuid:936da01f-9abd-4d9d-80c7-02af85c822a8"
766 /// );
767 ///
768 /// // the buffer is mutated directly, and trailing contents remains
769 /// let mut buf = [b'!'; 49];
770 /// uuid.urn().encode_lower(&mut buf);
771 /// assert_eq!(
772 /// uuid.urn().encode_lower(&mut buf),
773 /// "urn:uuid:936da01f-9abd-4d9d-80c7-02af85c822a8"
774 /// );
775 /// assert_eq!(
776 /// &buf as &[_],
777 /// b"urn:uuid:936da01f-9abd-4d9d-80c7-02af85c822a8!!!!" as &[_]
778 /// );
779 ///
780 /// Ok(())
781 /// }
782 /// ```
783 /// */
784 #[inline]
785 pub fn encode_lower<'buf>(&self, buffer: &'buf mut [u8]) -> &'buf mut str {
786 encode_urn(self.0.as_bytes(), buffer, false)
787 }
788
789 /// Writes the [`Uuid`] as an upper-case URN string to
790 /// `buffer`, and returns the subslice of the buffer that contains the
791 /// encoded UUID.
792 ///
793 /// This is slightly more efficient than using the formatting
794 /// infrastructure as it avoids virtual calls, and may avoid
795 /// double buffering.
796 ///
797 /// [`Uuid`]: ../struct.Uuid.html
798 ///
799 /// # Panics
800 ///
801 /// Panics if the buffer is not large enough: it must have length at least
802 /// [`LENGTH`]. [`Uuid::encode_buffer`] can be used to get a
803 /// sufficiently-large temporary buffer.
804 ///
805 /// [`LENGTH`]: #associatedconstant.LENGTH
806 /// [`Uuid::encode_buffer`]: ../struct.Uuid.html#method.encode_buffer
807 ///
808 /// # Examples
809 ///
810 /// ```rust
811 /// use uuid::Uuid;
812 ///
813 /// fn main() -> Result<(), uuid::Error> {
814 /// let uuid = Uuid::parse_str("936da01f9abd4d9d80c702af85c822a8")?;
815 ///
816 /// // the encoded portion is returned
817 /// assert_eq!(
818 /// uuid.urn().encode_upper(&mut Uuid::encode_buffer()),
819 /// "urn:uuid:936DA01F-9ABD-4D9D-80C7-02AF85C822A8"
820 /// );
821 ///
822 /// // the buffer is mutated directly, and trailing contents remains
823 /// let mut buf = [b'!'; 49];
824 /// assert_eq!(
825 /// uuid.urn().encode_upper(&mut buf),
826 /// "urn:uuid:936DA01F-9ABD-4D9D-80C7-02AF85C822A8"
827 /// );
828 /// assert_eq!(
829 /// &buf as &[_],
830 /// b"urn:uuid:936DA01F-9ABD-4D9D-80C7-02AF85C822A8!!!!" as &[_]
831 /// );
832 ///
833 /// Ok(())
834 /// }
835 /// ```
836 /// */
837 #[inline]
838 pub fn encode_upper<'buf>(&self, buffer: &'buf mut [u8]) -> &'buf mut str {
839 encode_urn(self.0.as_bytes(), buffer, true)
840 }
841
842 /// Get a reference to the underlying [`Uuid`].
843 ///
844 /// # Examples
845 ///
846 /// ```rust
847 /// use uuid::Uuid;
848 ///
849 /// let urn = Uuid::nil().urn();
850 /// assert_eq!(*urn.as_uuid(), Uuid::nil());
851 /// ```
852 pub const fn as_uuid(&self) -> &Uuid {
853 &self.0
854 }
855
856 /// Consumes the [`Urn`], returning the underlying [`Uuid`].
857 ///
858 /// # Examples
859 ///
860 /// ```rust
861 /// use uuid::Uuid;
862 ///
863 /// let urn = Uuid::nil().urn();
864 /// assert_eq!(urn.into_uuid(), Uuid::nil());
865 /// ```
866 pub const fn into_uuid(self) -> Uuid {
867 self.0
868 }
869}
870
871impl FromStr for Hyphenated {
872 type Err = Error;
873
874 fn from_str(s: &str) -> Result<Self, Self::Err> {
875 crate::parser::parse_hyphenated(s.as_bytes())
876 .map(|b| Hyphenated(Uuid(b)))
877 .map_err(|invalid| invalid.into_err())
878 }
879}
880
881impl FromStr for Simple {
882 type Err = Error;
883
884 fn from_str(s: &str) -> Result<Self, Self::Err> {
885 crate::parser::parse_simple(s.as_bytes())
886 .map(|b| Simple(Uuid(b)))
887 .map_err(|invalid| invalid.into_err())
888 }
889}
890
891impl FromStr for Urn {
892 type Err = Error;
893
894 fn from_str(s: &str) -> Result<Self, Self::Err> {
895 crate::parser::parse_urn(s.as_bytes())
896 .map(|b| Urn(Uuid(b)))
897 .map_err(|invalid| invalid.into_err())
898 }
899}
900
901impl FromStr for Braced {
902 type Err = Error;
903
904 fn from_str(s: &str) -> Result<Self, Self::Err> {
905 crate::parser::parse_braced(s.as_bytes())
906 .map(|b| Braced(Uuid(b)))
907 .map_err(|invalid| invalid.into_err())
908 }
909}
910
911macro_rules! impl_fmt_traits {
912 ($($T:ident<$($a:lifetime),*>),+) => {$(
913 impl<$($a),*> fmt::Display for $T<$($a),*> {
914 #[inline]
915 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
916 fmt::LowerHex::fmt(self, f)
917 }
918 }
919
920 impl<$($a),*> fmt::LowerHex for $T<$($a),*> {
921 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
922 f.write_str(self.encode_lower(&mut [0; Self::LENGTH]))
923 }
924 }
925
926 impl<$($a),*> fmt::UpperHex for $T<$($a),*> {
927 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
928 f.write_str(self.encode_upper(&mut [0; Self::LENGTH]))
929 }
930 }
931
932 impl_fmt_from!($T<$($a),*>);
933 )+}
934}
935
936macro_rules! impl_fmt_from {
937 ($T:ident<>) => {
938 impl From<Uuid> for $T {
939 #[inline]
940 fn from(f: Uuid) -> Self {
941 $T(f)
942 }
943 }
944
945 impl From<$T> for Uuid {
946 #[inline]
947 fn from(f: $T) -> Self {
948 f.into_uuid()
949 }
950 }
951
952 impl AsRef<Uuid> for $T {
953 #[inline]
954 fn as_ref(&self) -> &Uuid {
955 &self.0
956 }
957 }
958
959 impl Borrow<Uuid> for $T {
960 #[inline]
961 fn borrow(&self) -> &Uuid {
962 &self.0
963 }
964 }
965 };
966 ($T:ident<$a:lifetime>) => {
967 impl<$a> From<&$a Uuid> for $T<$a> {
968 #[inline]
969 fn from(f: &$a Uuid) -> Self {
970 $T::from_uuid_ref(f)
971 }
972 }
973
974 impl<$a> From<$T<$a>> for &$a Uuid {
975 #[inline]
976 fn from(f: $T<$a>) -> &$a Uuid {
977 f.0
978 }
979 }
980
981 impl<$a> AsRef<Uuid> for $T<$a> {
982 #[inline]
983 fn as_ref(&self) -> &Uuid {
984 self.0
985 }
986 }
987
988 impl<$a> Borrow<Uuid> for $T<$a> {
989 #[inline]
990 fn borrow(&self) -> &Uuid {
991 self.0
992 }
993 }
994 };
995}
996
997impl_fmt_traits! {
998 Hyphenated<>,
999 Simple<>,
1000 Urn<>,
1001 Braced<>
1002}
1003
1004#[cfg(test)]
1005mod tests {
1006 use super::*;
1007
1008 #[test]
1009 fn hyphenated_trailing() {
1010 let mut buf = [b'x'; 100];
1011 let len = Uuid::nil().hyphenated().encode_lower(&mut buf).len();
1012 assert_eq!(len, super::Hyphenated::LENGTH);
1013 assert!(buf[len..].iter().all(|x| *x == b'x'));
1014 }
1015
1016 #[test]
1017 fn hyphenated_ref_trailing() {
1018 let mut buf = [b'x'; 100];
1019 let len = Uuid::nil().as_hyphenated().encode_lower(&mut buf).len();
1020 assert_eq!(len, super::Hyphenated::LENGTH);
1021 assert!(buf[len..].iter().all(|x| *x == b'x'));
1022 }
1023
1024 #[test]
1025 fn simple_trailing() {
1026 let mut buf = [b'x'; 100];
1027 let len = Uuid::nil().simple().encode_lower(&mut buf).len();
1028 assert_eq!(len, super::Simple::LENGTH);
1029 assert!(buf[len..].iter().all(|x| *x == b'x'));
1030 }
1031
1032 #[test]
1033 fn simple_ref_trailing() {
1034 let mut buf = [b'x'; 100];
1035 let len = Uuid::nil().as_simple().encode_lower(&mut buf).len();
1036 assert_eq!(len, super::Simple::LENGTH);
1037 assert!(buf[len..].iter().all(|x| *x == b'x'));
1038 }
1039
1040 #[test]
1041 fn urn_trailing() {
1042 let mut buf = [b'x'; 100];
1043 let len = Uuid::nil().urn().encode_lower(&mut buf).len();
1044 assert_eq!(len, super::Urn::LENGTH);
1045 assert!(buf[len..].iter().all(|x| *x == b'x'));
1046 }
1047
1048 #[test]
1049 fn urn_ref_trailing() {
1050 let mut buf = [b'x'; 100];
1051 let len = Uuid::nil().as_urn().encode_lower(&mut buf).len();
1052 assert_eq!(len, super::Urn::LENGTH);
1053 assert!(buf[len..].iter().all(|x| *x == b'x'));
1054 }
1055
1056 #[test]
1057 fn braced_trailing() {
1058 let mut buf = [b'x'; 100];
1059 let len = Uuid::nil().braced().encode_lower(&mut buf).len();
1060 assert_eq!(len, super::Braced::LENGTH);
1061 assert!(buf[len..].iter().all(|x| *x == b'x'));
1062 }
1063
1064 #[test]
1065 fn braced_ref_trailing() {
1066 let mut buf = [b'x'; 100];
1067 let len = Uuid::nil().as_braced().encode_lower(&mut buf).len();
1068 assert_eq!(len, super::Braced::LENGTH);
1069 assert!(buf[len..].iter().all(|x| *x == b'x'));
1070 }
1071
1072 #[test]
1073 #[should_panic]
1074 fn hyphenated_too_small() {
1075 Uuid::nil().hyphenated().encode_lower(&mut [0; 35]);
1076 }
1077
1078 #[test]
1079 #[should_panic]
1080 fn simple_too_small() {
1081 Uuid::nil().simple().encode_lower(&mut [0; 31]);
1082 }
1083
1084 #[test]
1085 #[should_panic]
1086 fn urn_too_small() {
1087 Uuid::nil().urn().encode_lower(&mut [0; 44]);
1088 }
1089
1090 #[test]
1091 #[should_panic]
1092 fn braced_too_small() {
1093 Uuid::nil().braced().encode_lower(&mut [0; 37]);
1094 }
1095
1096 #[test]
1097 fn hyphenated_to_inner() {
1098 let hyphenated = Uuid::nil().hyphenated();
1099 assert_eq!(Uuid::from(hyphenated), Uuid::nil());
1100 }
1101
1102 #[test]
1103 fn simple_to_inner() {
1104 let simple = Uuid::nil().simple();
1105 assert_eq!(Uuid::from(simple), Uuid::nil());
1106 }
1107
1108 #[test]
1109 fn urn_to_inner() {
1110 let urn = Uuid::nil().urn();
1111 assert_eq!(Uuid::from(urn), Uuid::nil());
1112 }
1113
1114 #[test]
1115 fn braced_to_inner() {
1116 let braced = Uuid::nil().braced();
1117 assert_eq!(Uuid::from(braced), Uuid::nil());
1118 }
1119}