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