Skip to main content

uuid/
parser.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//! [`Uuid`] parsing constructs and utilities.
13//!
14//! [`Uuid`]: ../struct.Uuid.html
15
16use crate::{
17    error::*,
18    std::{convert::TryFrom, str},
19    Uuid,
20};
21
22#[cfg(feature = "std")]
23use crate::std::string::String;
24
25impl str::FromStr for Uuid {
26    type Err = Error;
27
28    fn from_str(uuid_str: &str) -> Result<Self, Self::Err> {
29        Uuid::parse_str(uuid_str)
30    }
31}
32
33impl TryFrom<&'_ str> for Uuid {
34    type Error = Error;
35
36    fn try_from(uuid_str: &'_ str) -> Result<Self, Self::Error> {
37        Uuid::parse_str(uuid_str)
38    }
39}
40
41#[cfg(feature = "std")]
42impl TryFrom<String> for Uuid {
43    type Error = Error;
44
45    fn try_from(uuid_str: String) -> Result<Self, Self::Error> {
46        Uuid::try_from(uuid_str.as_ref())
47    }
48}
49
50impl Uuid {
51    /// Parses a `Uuid` from a string of hexadecimal digits with optional
52    /// hyphens.
53    ///
54    /// Any of the formats generated by this module (simple, hyphenated, urn,
55    /// Microsoft GUID) are supported by this parsing function.
56    ///
57    /// Prefer [`try_parse`] unless you need detailed user-facing diagnostics.
58    /// This method will be eventually deprecated in favor of `try_parse`.
59    ///
60    /// # Examples
61    ///
62    /// Parse a hyphenated UUID:
63    ///
64    /// ```
65    /// # use uuid::{Uuid, Version, Variant};
66    /// # fn main() -> Result<(), uuid::Error> {
67    /// let uuid = Uuid::parse_str("550e8400-e29b-41d4-a716-446655440000")?;
68    ///
69    /// assert_eq!(Some(Version::Random), uuid.get_version());
70    /// assert_eq!(Variant::RFC4122, uuid.get_variant());
71    /// # Ok(())
72    /// # }
73    /// ```
74    ///
75    /// [`try_parse`]: #method.try_parse
76    pub fn parse_str(input: &str) -> Result<Uuid, Error> {
77        try_parse(input.as_bytes())
78            .map(Uuid::from_bytes)
79            .map_err(InvalidUuid::into_err)
80    }
81
82    /// Parses a `Uuid` from a string of hexadecimal digits with optional
83    /// hyphens.
84    ///
85    /// This function is similar to [`parse_str`], in fact `parse_str` shares
86    /// the same underlying parser. The difference is that if `try_parse`
87    /// fails, it won't generate very useful error messages. The `parse_str`
88    /// function will eventually be deprecated in favor of `try_parse`.
89    ///
90    /// To parse a UUID from a byte stream instead of a UTF8 string, see
91    /// [`try_parse_ascii`].
92    ///
93    /// # Examples
94    ///
95    /// Parse a hyphenated UUID:
96    ///
97    /// ```
98    /// # use uuid::{Uuid, Version, Variant};
99    /// # fn main() -> Result<(), uuid::Error> {
100    /// let uuid = Uuid::try_parse("550e8400-e29b-41d4-a716-446655440000")?;
101    ///
102    /// assert_eq!(Some(Version::Random), uuid.get_version());
103    /// assert_eq!(Variant::RFC4122, uuid.get_variant());
104    /// # Ok(())
105    /// # }
106    /// ```
107    ///
108    /// [`parse_str`]: #method.parse_str
109    /// [`try_parse_ascii`]: #method.try_parse_ascii
110    pub const fn try_parse(input: &str) -> Result<Uuid, Error> {
111        Self::try_parse_ascii(input.as_bytes())
112    }
113
114    /// Parses a `Uuid` from a string of hexadecimal digits with optional
115    /// hyphens.
116    ///
117    /// The input is expected to be a string of ASCII characters. This method
118    /// can be more convenient than [`try_parse`] if the UUID is being
119    /// parsed from a byte stream instead of from a UTF8 string.
120    ///
121    /// # Examples
122    ///
123    /// Parse a hyphenated UUID:
124    ///
125    /// ```
126    /// # use uuid::{Uuid, Version, Variant};
127    /// # fn main() -> Result<(), uuid::Error> {
128    /// let uuid = Uuid::try_parse_ascii(b"550e8400-e29b-41d4-a716-446655440000")?;
129    ///
130    /// assert_eq!(Some(Version::Random), uuid.get_version());
131    /// assert_eq!(Variant::RFC4122, uuid.get_variant());
132    /// # Ok(())
133    /// # }
134    /// ```
135    ///
136    /// [`try_parse`]: #method.try_parse
137    pub const fn try_parse_ascii(input: &[u8]) -> Result<Uuid, Error> {
138        match try_parse(input) {
139            Ok(bytes) => Ok(Uuid::from_bytes(bytes)),
140            // If parsing fails then we don't know exactly what went wrong
141            // In this case, we just return a generic error
142            Err(_) => Err(Error(ErrorKind::ParseOther)),
143        }
144    }
145}
146
147const fn try_parse(input: &'_ [u8]) -> Result<[u8; 16], InvalidUuid<'_>> {
148    match (input.len(), input) {
149        // Inputs of 32 bytes must be a non-hyphenated UUID
150        (32, s) => parse_simple(s, true),
151        // Hyphenated UUIDs may be wrapped in various ways:
152        // - `{UUID}` for braced UUIDs
153        // - `urn:uuid:UUID` for URNs
154        // - `UUID` for a regular hyphenated UUID
155        (36, s) | (38, [b'{', s @ .., b'}']) => parse_hyphenated(s),
156        (45, s) => {
157            let (prefix, s) = s.split_at(9);
158
159            if prefix.eq_ignore_ascii_case(b"urn:uuid:") {
160                parse_hyphenated(s)
161            } else {
162                Err(InvalidUuid(input, RequestedUuid::Any))
163            }
164        }
165        // Any other shaped input is immediately invalid
166        _ => Err(InvalidUuid(input, RequestedUuid::Any)),
167    }
168}
169
170#[inline]
171#[allow(dead_code)]
172pub(crate) const fn parse_braced(input: &'_ [u8]) -> Result<[u8; 16], InvalidUuid<'_>> {
173    if let (38, [b'{', s @ .., b'}']) = (input.len(), input) {
174        parse_hyphenated(s)
175    } else {
176        Err(InvalidUuid(input, RequestedUuid::Braced))
177    }
178}
179
180#[inline]
181#[allow(dead_code)]
182pub(crate) const fn parse_urn(input: &'_ [u8]) -> Result<[u8; 16], InvalidUuid<'_>> {
183    if input.len() == 45 && input.split_at(9).0.eq_ignore_ascii_case(b"urn:uuid:") {
184        parse_hyphenated(input.split_at(9).1)
185    } else {
186        Err(InvalidUuid(input, RequestedUuid::Urn))
187    }
188}
189
190#[inline]
191pub(crate) const fn parse_simple(
192    s: &'_ [u8],
193    speculative: bool,
194) -> Result<[u8; 16], InvalidUuid<'_>> {
195    // This length check here removes all other bounds
196    // checks in this function
197    if s.len() != 32 {
198        return Err(InvalidUuid(
199            s,
200            if speculative {
201                RequestedUuid::Any
202            } else {
203                RequestedUuid::Simple
204            },
205        ));
206    }
207
208    // Copy the hex characters into a fixed-size array so the decoder's
209    // bounds are statically known.
210    let mut hex = [0u8; 32];
211    let mut i = 0;
212    while i < 32 {
213        hex[i] = s[i];
214        i += 1;
215    }
216
217    match decode_hex32(&hex) {
218        Some(buf) => Ok(buf),
219        None => Err(InvalidUuid(
220            s,
221            if speculative {
222                RequestedUuid::Any
223            } else {
224                RequestedUuid::Simple
225            },
226        )),
227    }
228}
229
230#[inline]
231pub(crate) const fn parse_hyphenated(s: &'_ [u8]) -> Result<[u8; 16], InvalidUuid<'_>> {
232    // This length check here removes all other bounds
233    // checks in this function
234    if s.len() != 36 {
235        return Err(InvalidUuid(s, RequestedUuid::Hyphenated));
236    }
237
238    // The hex characters are split into five groups separated by hyphens.
239    // The indexes we're interested in are:
240    //
241    // uuid     : 936da01f-9abd-4d9d-80c7-02af85c822a8
242    //            |   |   ||   ||   ||   ||   |   |
243    // hyphens  : |   |   8|  13|  18|  23|   |   |
244    // positions: 0   4    9   14   19   24  28  32
245
246    // First, ensure the hyphens appear in the right places
247    match [s[8], s[13], s[18], s[23]] {
248        [b'-', b'-', b'-', b'-'] => {}
249        _ => return Err(InvalidUuid(s, RequestedUuid::Hyphenated)),
250    }
251
252    // Gather the hex characters, skipping the four hyphens, so they're
253    // contiguous for the decoder.
254    let mut hex = [0u8; 32];
255    let mut i = 0;
256    while i < 8 {
257        hex[i] = s[i];
258        i += 1;
259    }
260    while i < 12 {
261        hex[i] = s[i + 1];
262        i += 1;
263    }
264    while i < 16 {
265        hex[i] = s[i + 2];
266        i += 1;
267    }
268    while i < 20 {
269        hex[i] = s[i + 3];
270        i += 1;
271    }
272    while i < 32 {
273        hex[i] = s[i + 4];
274        i += 1;
275    }
276
277    match decode_hex32(&hex) {
278        Some(buf) => Ok(buf),
279        None => Err(InvalidUuid(s, RequestedUuid::Hyphenated)),
280    }
281}
282
283/// Decodes 32 hexadecimal ASCII characters into 16 bytes, returning `None` if
284/// any character is not a valid hexadecimal digit.
285#[inline]
286const fn decode_hex32(hex: &[u8; 32]) -> Option<[u8; 16]> {
287    let mut nibbles = [0u8; 32];
288    let mut bad = 0u8;
289
290    let mut i = 0;
291    while i < 32 {
292        let c = hex[i];
293
294        // '0'..='9' map to 0..=9; 'a'..='f' and 'A'..='F' (via `| 0x20`) map to
295        // 0..=5, offset by 10 to land in 10..=15.
296        let digit = c.wrapping_sub(b'0');
297        let alpha = (c | 0x20).wrapping_sub(b'a');
298
299        let is_digit = digit < 10;
300        let is_alpha = alpha < 6;
301
302        nibbles[i] = if is_digit {
303            digit
304        } else {
305            alpha.wrapping_add(10)
306        };
307
308        bad |= if is_digit | is_alpha { 0 } else { 1 };
309
310        i += 1;
311    }
312
313    if bad != 0 {
314        return None;
315    }
316
317    let mut buf = [0u8; 16];
318    let mut j = 0;
319    while j < 16 {
320        buf[j] = (nibbles[j * 2] << 4) | nibbles[j * 2 + 1];
321        j += 1;
322    }
323
324    Some(buf)
325}
326
327#[cfg(test)]
328mod tests {
329    use super::*;
330    use crate::{
331        fmt::*,
332        std::{str::FromStr, string::ToString},
333        tests::some_uuid_iter,
334    };
335
336    #[test]
337    fn test_parse_valid() {
338        let from_hyphenated = Uuid::parse_str("67e55044-10b1-426f-9247-bb680e5fe0c8").unwrap();
339        let from_simple = Uuid::parse_str("67e5504410b1426f9247bb680e5fe0c8").unwrap();
340        let from_urn = Uuid::parse_str("urn:uuid:67e55044-10b1-426f-9247-bb680e5fe0c8").unwrap();
341        let from_guid = Uuid::parse_str("{67e55044-10b1-426f-9247-bb680e5fe0c8}").unwrap();
342
343        assert_eq!(from_hyphenated, from_simple);
344        assert_eq!(from_hyphenated, from_urn);
345        assert_eq!(from_hyphenated, from_guid);
346
347        assert!(Uuid::parse_str("00000000000000000000000000000000").is_ok());
348        assert!(Uuid::parse_str("67e55044-10b1-426f-9247-bb680e5fe0c8").is_ok());
349        assert!(Uuid::parse_str("F9168C5E-CEB2-4faa-B6BF-329BF39FA1E4").is_ok());
350        assert!(Uuid::parse_str("67e5504410b1426f9247bb680e5fe0c8").is_ok());
351        assert!(Uuid::parse_str("01020304-1112-2122-3132-414243444546").is_ok());
352        assert!(Uuid::parse_str("urn:uuid:67e55044-10b1-426f-9247-bb680e5fe0c8").is_ok());
353        assert!(Uuid::parse_str("URN:UUID:67e55044-10b1-426f-9247-bb680e5fe0c8").is_ok());
354        assert!(Uuid::parse_str("Urn:Uuid:67e55044-10b1-426f-9247-bb680e5fe0c8").is_ok());
355        assert!(Uuid::parse_str("{6d93bade-bd9f-4e13-8914-9474e1e3567b}").is_ok());
356
357        assert_eq!(
358            from_urn,
359            Uuid::parse_str("URN:UUID:67e55044-10b1-426f-9247-bb680e5fe0c8").unwrap()
360        );
361        assert_eq!(
362            from_urn,
363            Uuid::parse_str("urn:UUID:67e55044-10b1-426f-9247-bb680e5fe0c8").unwrap()
364        );
365
366        // Nil
367        let nil = Uuid::nil();
368        assert_eq!(
369            Uuid::parse_str("00000000000000000000000000000000").unwrap(),
370            nil
371        );
372        assert_eq!(
373            Uuid::parse_str("00000000-0000-0000-0000-000000000000").unwrap(),
374            nil
375        );
376    }
377
378    #[test]
379    fn test_parse_invalid() {
380        // Invalid
381        assert_eq!(
382            Uuid::parse_str(""),
383            Err(Error(ErrorKind::ParseLength { len: 0 }))
384        );
385
386        assert_eq!(
387            Uuid::parse_str("{}"),
388            Err(Error(ErrorKind::ParseGroupCount { count: 1 }))
389        );
390
391        assert_eq!(
392            Uuid::parse_str("!"),
393            Err(Error(ErrorKind::ParseChar {
394                character: '!',
395                index: 0,
396            }))
397        );
398
399        assert_eq!(
400            Uuid::parse_str("F9168C5E-CEB2-4faa-B6BF-329BF39FA1E45"),
401            Err(Error(ErrorKind::ParseGroupLength {
402                group: 4,
403                len: 13,
404                index: 25,
405            }))
406        );
407
408        assert_eq!(
409            Uuid::parse_str("F9168C5E-CEB2-4faa-BBF-329BF39FA1E4"),
410            Err(Error(ErrorKind::ParseGroupLength {
411                group: 3,
412                len: 3,
413                index: 20,
414            }))
415        );
416
417        assert_eq!(
418            Uuid::parse_str("F9168C5E-CEB2-4faa-BGBF-329BF39FA1E4"),
419            Err(Error(ErrorKind::ParseChar {
420                character: 'G',
421                index: 20,
422            }))
423        );
424
425        assert_eq!(
426            Uuid::parse_str("F9168C5E-CEB2F4faaFB6BFF329BF39FA1E4"),
427            Err(Error(ErrorKind::ParseGroupCount { count: 2 }))
428        );
429
430        assert_eq!(
431            Uuid::parse_str("F9168C5E-CEB2-4faaFB6BFF329BF39FA1E4"),
432            Err(Error(ErrorKind::ParseGroupCount { count: 3 }))
433        );
434
435        assert_eq!(
436            Uuid::parse_str("F9168C5E-CEB2-4faa-B6BFF329BF39FA1E4"),
437            Err(Error(ErrorKind::ParseGroupCount { count: 4 }))
438        );
439
440        assert_eq!(
441            Uuid::parse_str("F9168C5E-CEB2-4faa"),
442            Err(Error(ErrorKind::ParseGroupCount { count: 3 }))
443        );
444
445        assert_eq!(
446            Uuid::parse_str("F9168C5E-CEB2-4faaXB6BFF329BF39FA1E4"),
447            Err(Error(ErrorKind::ParseChar {
448                character: 'X',
449                index: 18,
450            }))
451        );
452
453        assert_eq!(
454            Uuid::parse_str("{F9168C5E-CEB2-4faa9B6BFF329BF39FA1E41"),
455            Err(Error(ErrorKind::ParseChar {
456                character: '{',
457                index: 0,
458            }))
459        );
460
461        assert_eq!(
462            Uuid::parse_str("{F9168C5E-CEB2-4faa9B6BFF329BF39FA1E41}"),
463            Err(Error(ErrorKind::ParseGroupCount { count: 3 }))
464        );
465
466        assert_eq!(
467            Uuid::parse_str("F9168C5E-CEB-24fa-eB6BFF32-BF39FA1E4"),
468            Err(Error(ErrorKind::ParseGroupLength {
469                group: 1,
470                len: 3,
471                index: 10,
472            }))
473        );
474
475        // // (group, found, expecting)
476        assert_eq!(
477            Uuid::parse_str("01020304-1112-2122-3132-41424344"),
478            Err(Error(ErrorKind::ParseGroupLength {
479                group: 4,
480                len: 8,
481                index: 25,
482            }))
483        );
484
485        assert_eq!(
486            Uuid::parse_str("67e5504410b1426f9247bb680e5fe0c"),
487            Err(Error(ErrorKind::ParseLength { len: 31 }))
488        );
489
490        assert_eq!(
491            Uuid::parse_str("67e5504410b1426f9247bb680e5fe0c88"),
492            Err(Error(ErrorKind::ParseLength { len: 33 }))
493        );
494
495        assert_eq!(
496            Uuid::parse_str("67e5504410b1426f9247bb680e5fe0cg8"),
497            Err(Error(ErrorKind::ParseChar {
498                character: 'g',
499                index: 31,
500            }))
501        );
502
503        assert_eq!(
504            Uuid::parse_str("67e5504410b1426%9247bb680e5fe0c8"),
505            Err(Error(ErrorKind::ParseChar {
506                character: '%',
507                index: 15,
508            }))
509        );
510
511        assert_eq!(
512            Uuid::parse_str("231231212212423424324323477343246663"),
513            Err(Error(ErrorKind::ParseGroupCount { count: 1 }))
514        );
515
516        assert_eq!(
517            Uuid::parse_str("{00000000000000000000000000000000}"),
518            Err(Error(ErrorKind::ParseGroupCount { count: 1 }))
519        );
520
521        assert_eq!(
522            Uuid::parse_str("67e5504410b1426f9247bb680e5fe0c"),
523            Err(Error(ErrorKind::ParseLength { len: 31 }))
524        );
525
526        assert_eq!(
527            Uuid::parse_str("67e550X410b1426f9247bb680e5fe0cd"),
528            Err(Error(ErrorKind::ParseChar {
529                character: 'X',
530                index: 6,
531            }))
532        );
533
534        assert_eq!(
535            Uuid::parse_str("67e550-4105b1426f9247bb680e5fe0c"),
536            Err(Error(ErrorKind::ParseGroupCount { count: 2 }))
537        );
538
539        assert_eq!(
540            Uuid::parse_str("F9168C5E-CEB2-4faa-B6BF1-02BF39FA1E4"),
541            Err(Error(ErrorKind::ParseGroupLength {
542                group: 3,
543                len: 5,
544                index: 20,
545            }))
546        );
547
548        assert_eq!(
549            Uuid::parse_str("\u{bcf3c}"),
550            Err(Error(ErrorKind::ParseChar {
551                character: '\u{bcf3c}',
552                index: 0,
553            }))
554        );
555
556        assert_eq!(
557            Uuid::parse_str("\u{130}"),
558            Err(Error(ErrorKind::ParseChar {
559                character: '\u{130}',
560                index: 0,
561            }))
562        );
563
564        assert_eq!(
565            Err(Error(ErrorKind::ParseLength { len: 0 })),
566            Hyphenated::from_str("")
567        );
568
569        assert_eq!(
570            Err(Error(ErrorKind::ParseGroupCount { count: 1 })),
571            Hyphenated::from_str("550e8400e29b41d4a716446655440000")
572        );
573
574        assert_eq!(
575            Err(Error(ErrorKind::ParseChar {
576                character: '-',
577                index: 8
578            })),
579            Simple::from_str("550e8400-e29b-41d4-a716-446655440000")
580        );
581
582        assert_eq!(
583            Err(Error(ErrorKind::ParseChar {
584                character: '5',
585                index: 0
586            })),
587            Urn::from_str("550e8400-e29b-41d4-a716-446655440000")
588        );
589        assert_eq!(
590            Err(Error(ErrorKind::ParseChar {
591                character: ':',
592                index: 0
593            })),
594            Urn::from_str(":550e8400-e29b-41d4-a716-446655440000")
595        );
596        assert_eq!(
597            Uuid::parse_str("urn:uuid:67e55044-10b1-426f-9247-bb680e5fe0c8").unwrap(),
598            Urn::from_str("URN:UUID:67e55044-10b1-426f-9247-bb680e5fe0c8")
599                .unwrap()
600                .into_uuid()
601        );
602
603        assert_eq!(
604            Err(Error(ErrorKind::ParseChar {
605                character: '5',
606                index: 0
607            })),
608            Braced::from_str("550e8400-e29b-41d4-a716-446655440000")
609        );
610        assert_eq!(
611            Err(Error(ErrorKind::ParseChar {
612                character: '{',
613                index: 1
614            })),
615            Braced::from_str("{{550e8400-e29b-41d4-a716-446655440000}}")
616        );
617
618        // Unicode
619        assert_eq!(
620            Uuid::from_str("{6e0----------9=4O-0e5\u{14}e0c4\u{ec2f}8}"),
621            Err(Error(ErrorKind::ParseChar {
622                character: '=',
623                index: 15,
624            }))
625        );
626
627        assert_eq!(
628            Uuid::from_str("urn:uuid:urae0c8"),
629            Err(Error(ErrorKind::ParseChar {
630                character: 'u',
631                index: 9,
632            }))
633        );
634    }
635
636    #[test]
637    fn test_roundtrip_default() {
638        for uuid_orig in some_uuid_iter() {
639            let orig_str = uuid_orig.to_string();
640            let uuid_out = Uuid::parse_str(&orig_str).unwrap();
641            assert_eq!(uuid_orig, uuid_out);
642        }
643    }
644
645    #[test]
646    fn test_roundtrip_hyphenated() {
647        for uuid_orig in some_uuid_iter() {
648            let orig_str = uuid_orig.hyphenated().to_string();
649            let uuid_out = Uuid::parse_str(&orig_str).unwrap();
650            assert_eq!(uuid_orig, uuid_out);
651        }
652    }
653
654    #[test]
655    fn test_roundtrip_simple() {
656        for uuid_orig in some_uuid_iter() {
657            let orig_str = uuid_orig.simple().to_string();
658            let uuid_out = Uuid::parse_str(&orig_str).unwrap();
659            assert_eq!(uuid_orig, uuid_out);
660        }
661    }
662
663    #[test]
664    fn test_roundtrip_urn() {
665        for uuid_orig in some_uuid_iter() {
666            let orig_str = uuid_orig.urn().to_string();
667            let uuid_out = Uuid::parse_str(&orig_str).unwrap();
668            assert_eq!(uuid_orig, uuid_out);
669        }
670    }
671
672    #[test]
673    fn test_roundtrip_braced() {
674        for uuid_orig in some_uuid_iter() {
675            let orig_str = uuid_orig.braced().to_string();
676            let uuid_out = Uuid::parse_str(&orig_str).unwrap();
677            assert_eq!(uuid_orig, uuid_out);
678        }
679    }
680
681    #[test]
682    fn test_roundtrip_parse_urn() {
683        for uuid_orig in some_uuid_iter() {
684            let orig_str = uuid_orig.urn().to_string();
685            let uuid_out = Uuid::from_bytes(parse_urn(orig_str.as_bytes()).unwrap());
686            assert_eq!(uuid_orig, uuid_out);
687        }
688    }
689
690    #[test]
691    fn test_roundtrip_parse_braced() {
692        for uuid_orig in some_uuid_iter() {
693            let orig_str = uuid_orig.braced().to_string();
694            let uuid_out = Uuid::from_bytes(parse_braced(orig_str.as_bytes()).unwrap());
695            assert_eq!(uuid_orig, uuid_out);
696        }
697    }
698
699    #[test]
700    fn test_try_parse_ascii_non_utf8() {
701        assert!(Uuid::try_parse_ascii(b"67e55044-10b1-426f-9247-bb680e5\0e0c8").is_err());
702    }
703}