(index<- ) ./libuuid/lib.rs
git branch: * master 5200215 auto merge of #14035 : alexcrichton/rust/experimental, r=huonw
modified: Fri May 9 13:02:28 2014
1 // Copyright 2013 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10
11 /*!
12 Generate and parse UUIDs
13
14 Provides support for Universally Unique Identifiers (UUIDs). A UUID is a
15 unique 128-bit number, stored as 16 octets. UUIDs are used to assign unique
16 identifiers to entities without requiring a central allocating authority.
17
18 They are particularly useful in distributed systems, though can be used in
19 disparate areas, such as databases and network protocols. Typically a UUID is
20 displayed in a readable string form as a sequence of hexadecimal digits,
21 separated into groups by hyphens.
22
23 The uniqueness property is not strictly guaranteed, however for all practical
24 purposes, it can be assumed that an unintentional collision would be extremely
25 unlikely.
26
27 # Examples
28
29 To create a new random (V4) UUID and print it out in hexadecimal form:
30
31 ```rust
32 use uuid::Uuid;
33
34 fn main() {
35 let uuid1 = Uuid::new_v4();
36 println!("{}", uuid1.to_str());
37 }
38 ```
39
40 # Strings
41
42 Examples of string representations:
43
44 * simple: `936DA01F9ABD4d9d80C702AF85C822A8`
45 * hyphenated: `550e8400-e29b-41d4-a716-446655440000`
46 * urn: `urn:uuid:F9168C5E-CEB2-4faa-B6BF-329BF39FA1E4`
47
48 # References
49
50 * [Wikipedia: Universally Unique Identifier](
51 http://en.wikipedia.org/wiki/Universally_unique_identifier)
52 * [RFC4122: A Universally Unique IDentifier (UUID) URN Namespace](
53 http://tools.ietf.org/html/rfc4122)
54
55 */
56
57 #![crate_id = "uuid#0.11-pre"]
58 #![crate_type = "rlib"]
59 #![crate_type = "dylib"]
60 #![license = "MIT/ASL2"]
61 #![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
62 html_favicon_url = "http://www.rust-lang.org/favicon.ico",
63 html_root_url = "http://static.rust-lang.org/doc/master")]
64
65 #![feature(default_type_params)]
66
67 // test harness access
68 #[cfg(test)]
69 extern crate test;
70
71 extern crate rand;
72 extern crate serialize;
73
74 use std::cast::{transmute,transmute_copy};
75 use std::char::Char;
76 use std::default::Default;
77 use std::fmt;
78 use std::from_str::FromStr;
79 use std::hash::Hash;
80 use std::num::FromStrRadix;
81 use std::str;
82 use std::slice;
83
84 use rand::Rng;
85
86 use serialize::{Encoder, Encodable, Decoder, Decodable};
87
88 /// A 128-bit (16 byte) buffer containing the ID
89 pub type UuidBytes = [u8, ..16];
90
91 /// The version of the UUID, denoting the generating algorithm
92 #[deriving(Eq)]
93 pub enum UuidVersion {
94 /// Version 1: MAC address
95 Version1Mac = 1,
96 /// Version 2: DCE Security
97 Version2Dce = 2,
98 /// Version 3: MD5 hash
99 Version3Md5 = 3,
100 /// Version 4: Random
101 Version4Random = 4,
102 /// Version 5: SHA-1 hash
103 Version5Sha1 = 5,
104 }
105
106 /// The reserved variants of UUIDs
107 #[deriving(Eq)]
108 pub enum UuidVariant {
109 /// Reserved by the NCS for backward compatibility
110 VariantNCS,
111 /// As described in the RFC4122 Specification (default)
112 VariantRFC4122,
113 /// Reserved by Microsoft for backward compatibility
114 VariantMicrosoft,
115 /// Reserved for future expansion
116 VariantFuture,
117 }
118
119 /// A Universally Unique Identifier (UUID)
120 pub struct Uuid {
121 /// The 128-bit number stored in 16 bytes
122 bytes: UuidBytes
123 }
124
125 impl<S: Writer> Hash<S> for Uuid {
126 fn hash(&self, state: &mut S) {
127 self.bytes.hash(state)
128 }
129 }
130
131 /// A UUID stored as fields (identical to UUID, used only for conversions)
132 struct UuidFields {
133 /// First field, 32-bit word
134 data1: u32,
135 /// Second field, 16-bit short
136 data2: u16,
137 /// Third field, 16-bit short
138 data3: u16,
139 /// Fourth field, 8 bytes
140 data4: [u8, ..8]
141 }
142
143 /// Error details for string parsing failures
144 #[allow(missing_doc)]
145 pub enum ParseError {
146 ErrorInvalidLength(uint),
147 ErrorInvalidCharacter(char, uint),
148 ErrorInvalidGroups(uint),
149 ErrorInvalidGroupLength(uint, uint, uint),
150 }
151
152 /// Converts a ParseError to a string
153 impl fmt::Show for ParseError {
154 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
155 match *self {
156 ErrorInvalidLength(found) =>
157 write!(f.buf, "Invalid length; expecting 32, 36 or 45 chars, \
158 found {}", found),
159 ErrorInvalidCharacter(found, pos) =>
160 write!(f.buf, "Invalid character; found `{}` (0x{:02x}) at \
161 offset {}", found, found as uint, pos),
162 ErrorInvalidGroups(found) =>
163 write!(f.buf, "Malformed; wrong number of groups: expected 1 \
164 or 5, found {}", found),
165 ErrorInvalidGroupLength(group, found, expecting) =>
166 write!(f.buf, "Malformed; length of group {} was {}, \
167 expecting {}", group, found, expecting),
168 }
169 }
170 }
171
172 // Length of each hyphenated group in hex digits
173 static UuidGroupLens: [uint, ..5] = [8u, 4u, 4u, 4u, 12u];
174
175 /// UUID support
176 impl Uuid {
177 /// Returns a nil or empty UUID (containing all zeroes)
178 pub fn nil() -> Uuid {
179 let uuid = Uuid{ bytes: [0, .. 16] };
180 uuid
181 }
182
183 /// Create a new UUID of the specified version
184 pub fn new(v: UuidVersion) -> Option<Uuid> {
185 match v {
186 Version4Random => Some(Uuid::new_v4()),
187 _ => None
188 }
189 }
190
191 /// Creates a new random UUID
192 ///
193 /// Uses the `rand` module's default RNG task as the source
194 /// of random numbers. Use the rand::Rand trait to supply
195 /// a custom generator if required.
196 pub fn new_v4() -> Uuid {
197 let ub = rand::task_rng().gen_vec(16);
198 let mut uuid = Uuid{ bytes: [0, .. 16] };
199 slice::bytes::copy_memory(uuid.bytes, ub.as_slice());
200 uuid.set_variant(VariantRFC4122);
201 uuid.set_version(Version4Random);
202 uuid
203 }
204
205 /// Creates a UUID using the supplied field values
206 ///
207 /// # Arguments
208 /// * `d1` A 32-bit word
209 /// * `d2` A 16-bit word
210 /// * `d3` A 16-bit word
211 /// * `d4` Array of 8 octets
212 pub fn from_fields(d1: u32, d2: u16, d3: u16, d4: &[u8]) -> Uuid {
213 use std::mem::{to_be16, to_be32};
214
215 // First construct a temporary field-based struct
216 let mut fields = UuidFields {
217 data1: 0,
218 data2: 0,
219 data3: 0,
220 data4: [0, ..8]
221 };
222
223 fields.data1 = to_be32(d1);
224 fields.data2 = to_be16(d2);
225 fields.data3 = to_be16(d3);
226 slice::bytes::copy_memory(fields.data4, d4);
227
228 unsafe {
229 transmute(fields)
230 }
231 }
232
233 /// Creates a UUID using the supplied bytes
234 ///
235 /// # Arguments
236 /// * `b` An array or slice of 16 bytes
237 pub fn from_bytes(b: &[u8]) -> Option<Uuid> {
238 if b.len() != 16 {
239 return None
240 }
241
242 let mut uuid = Uuid{ bytes: [0, .. 16] };
243 slice::bytes::copy_memory(uuid.bytes, b);
244 Some(uuid)
245 }
246
247 /// Specifies the variant of the UUID structure
248 fn set_variant(&mut self, v: UuidVariant) {
249 // Octet 8 contains the variant in the most significant 3 bits
250 match v {
251 VariantNCS => // b0xx...
252 self.bytes[8] = self.bytes[8] & 0x7f,
253 VariantRFC4122 => // b10x...
254 self.bytes[8] = (self.bytes[8] & 0x3f) | 0x80,
255 VariantMicrosoft => // b110...
256 self.bytes[8] = (self.bytes[8] & 0x1f) | 0xc0,
257 VariantFuture => // b111...
258 self.bytes[8] = (self.bytes[8] & 0x1f) | 0xe0,
259 }
260 }
261
262 /// Returns the variant of the UUID structure
263 ///
264 /// This determines the interpretation of the structure of the UUID.
265 /// Currently only the RFC4122 variant is generated by this module.
266 ///
267 /// * [Variant Reference](http://tools.ietf.org/html/rfc4122#section-4.1.1)
268 pub fn get_variant(&self) -> Option<UuidVariant> {
269 if self.bytes[8] & 0x80 == 0x00 {
270 Some(VariantNCS)
271 } else if self.bytes[8] & 0xc0 == 0x80 {
272 Some(VariantRFC4122)
273 } else if self.bytes[8] & 0xe0 == 0xc0 {
274 Some(VariantMicrosoft)
275 } else if self.bytes[8] & 0xe0 == 0xe0 {
276 Some(VariantFuture)
277 } else {
278 None
279 }
280 }
281
282 /// Specifies the version number of the UUID
283 fn set_version(&mut self, v: UuidVersion) {
284 self.bytes[6] = (self.bytes[6] & 0xF) | ((v as u8) << 4);
285 }
286
287 /// Returns the version number of the UUID
288 ///
289 /// This represents the algorithm used to generate the contents.
290 ///
291 /// Currently only the Random (V4) algorithm is supported by this
292 /// module. There are security and privacy implications for using
293 /// older versions - see [Wikipedia: Universally Unique Identifier](
294 /// http://en.wikipedia.org/wiki/Universally_unique_identifier) for
295 /// details.
296 ///
297 /// * [Version Reference](http://tools.ietf.org/html/rfc4122#section-4.1.3)
298 pub fn get_version_num(&self) -> uint {
299 (self.bytes[6] >> 4) as uint
300 }
301
302 /// Returns the version of the UUID
303 ///
304 /// This represents the algorithm used to generate the contents
305 pub fn get_version(&self) -> Option<UuidVersion> {
306 let v = self.bytes[6] >> 4;
307 match v {
308 1 => Some(Version1Mac),
309 2 => Some(Version2Dce),
310 3 => Some(Version3Md5),
311 4 => Some(Version4Random),
312 5 => Some(Version5Sha1),
313 _ => None
314 }
315 }
316
317 /// Return an array of 16 octets containing the UUID data
318 pub fn as_bytes<'a>(&'a self) -> &'a [u8] {
319 self.bytes.as_slice()
320 }
321
322 /// Returns the UUID as a string of 16 hexadecimal digits
323 ///
324 /// Example: `936DA01F9ABD4d9d80C702AF85C822A8`
325 pub fn to_simple_str(&self) -> ~str {
326 let mut s: Vec<u8> = Vec::from_elem(32, 0u8);
327 for i in range(0u, 16u) {
328 let digit = format!("{:02x}", self.bytes[i] as uint);
329 *s.get_mut(i*2+0) = digit[0];
330 *s.get_mut(i*2+1) = digit[1];
331 }
332 str::from_utf8(s.as_slice()).unwrap().to_str()
333 }
334
335 /// Returns a string of hexadecimal digits, separated into groups with a hyphen.
336 ///
337 /// Example: `550e8400-e29b-41d4-a716-446655440000`
338 pub fn to_hyphenated_str(&self) -> ~str {
339 use std::mem::{to_be16, to_be32};
340 // Convert to field-based struct as it matches groups in output.
341 // Ensure fields are in network byte order, as per RFC.
342 let mut uf: UuidFields;
343 unsafe {
344 uf = transmute_copy(&self.bytes);
345 }
346 uf.data1 = to_be32(uf.data1);
347 uf.data2 = to_be16(uf.data2);
348 uf.data3 = to_be16(uf.data3);
349 let s = format!("{:08x}-{:04x}-{:04x}-{:02x}{:02x}-\
350 {:02x}{:02x}{:02x}{:02x}{:02x}{:02x}",
351 uf.data1,
352 uf.data2, uf.data3,
353 uf.data4[0], uf.data4[1],
354 uf.data4[2], uf.data4[3], uf.data4[4],
355 uf.data4[5], uf.data4[6], uf.data4[7]);
356 s
357 }
358
359 /// Returns the UUID formatted as a full URN string
360 ///
361 /// This is the same as the hyphenated format, but with the "urn:uuid:" prefix.
362 ///
363 /// Example: `urn:uuid:F9168C5E-CEB2-4faa-B6BF-329BF39FA1E4`
364 pub fn to_urn_str(&self) -> ~str {
365 "urn:uuid:" + self.to_hyphenated_str()
366 }
367
368 /// Parses a UUID from a string of hexadecimal digits with optional hyphens
369 ///
370 /// Any of the formats generated by this module (simple, hyphenated, urn) are
371 /// supported by this parsing function.
372 pub fn parse_string(us: &str) -> Result<Uuid, ParseError> {
373
374 let mut us = us.clone();
375 let orig_len = us.len();
376
377 // Ensure length is valid for any of the supported formats
378 if orig_len != 32 && orig_len != 36 && orig_len != 45 {
379 return Err(ErrorInvalidLength(orig_len));
380 }
381
382 // Strip off URN prefix if present
383 if us.starts_with("urn:uuid:") {
384 us = us.slice(9, orig_len);
385 }
386
387 // Make sure all chars are either hex digits or hyphen
388 for (i, c) in us.chars().enumerate() {
389 match c {
390 '0'..'9' | 'A'..'F' | 'a'..'f' | '-' => {},
391 _ => return Err(ErrorInvalidCharacter(c, i)),
392 }
393 }
394
395 // Split string up by hyphens into groups
396 let hex_groups: Vec<&str> = us.split_str("-").collect();
397
398 // Get the length of each group
399 let group_lens: Vec<uint> = hex_groups.iter().map(|&v| v.len()).collect();
400
401 // Ensure the group lengths are valid
402 match group_lens.len() {
403 // Single group, no hyphens
404 1 => {
405 if *group_lens.get(0) != 32 {
406 return Err(ErrorInvalidLength(*group_lens.get(0)));
407 }
408 },
409 // Five groups, hyphens in between each
410 5 => {
411 // Ensure each group length matches the expected
412 for (i, (&gl, &expected)) in
413 group_lens.iter().zip(UuidGroupLens.iter()).enumerate() {
414 if gl != expected {
415 return Err(ErrorInvalidGroupLength(i, gl, expected))
416 }
417 }
418 },
419 _ => {
420 return Err(ErrorInvalidGroups(group_lens.len()));
421 }
422 }
423
424 // Normalise into one long hex string
425 let vs = hex_groups.concat();
426
427 // At this point, we know we have a valid hex string, without hyphens
428 assert!(vs.len() == 32);
429 assert!(vs.chars().all(|c| c.is_digit_radix(16)));
430
431 // Allocate output UUID buffer
432 let mut ub = [0u8, ..16];
433
434 // Extract each hex digit from the string
435 for i in range(0u, 16u) {
436 ub[i] = FromStrRadix::from_str_radix(vs.slice(i*2, (i+1)*2), 16).unwrap();
437 }
438
439 Ok(Uuid::from_bytes(ub).unwrap())
440 }
441
442 /// Tests if the UUID is nil
443 pub fn is_nil(&self) -> bool {
444 return self.bytes.iter().all(|&b| b == 0);
445 }
446 }
447
448 impl Default for Uuid {
449 /// Returns the nil UUID, which is all zeroes
450 fn default() -> Uuid {
451 Uuid::nil()
452 }
453 }
454
455 impl Clone for Uuid {
456 /// Returns a copy of the UUID
457 fn clone(&self) -> Uuid { *self }
458 }
459
460 impl FromStr for Uuid {
461 /// Parse a hex string and interpret as a UUID
462 ///
463 /// Accepted formats are a sequence of 32 hexadecimal characters,
464 /// with or without hypens (grouped as 8, 4, 4, 4, 12).
465 fn from_str(us: &str) -> Option<Uuid> {
466 let result = Uuid::parse_string(us);
467 match result {
468 Ok(u) => Some(u),
469 Err(_) => None
470 }
471 }
472 }
473
474 /// Convert the UUID to a hexadecimal-based string representation
475 impl fmt::Show for Uuid {
476 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
477 write!(f.buf, "{}", self.to_simple_str())
478 }
479 }
480
481 /// Test two UUIDs for equality
482 ///
483 /// UUIDs are equal only when they are byte-for-byte identical
484 impl Eq for Uuid {
485 fn eq(&self, other: &Uuid) -> bool {
486 self.bytes == other.bytes
487 }
488 }
489
490 impl TotalEq for Uuid {}
491
492 // FIXME #9845: Test these more thoroughly
493 impl<T: Encoder<E>, E> Encodable<T, E> for Uuid {
494 /// Encode a UUID as a hypenated string
495 fn encode(&self, e: &mut T) -> Result<(), E> {
496 e.emit_str(self.to_hyphenated_str())
497 }
498 }
499
500 impl<T: Decoder<E>, E> Decodable<T, E> for Uuid {
501 /// Decode a UUID from a string
502 fn decode(d: &mut T) -> Result<Uuid, E> {
503 Ok(from_str(try!(d.read_str())).unwrap())
504 }
505 }
506
507 /// Generates a random instance of UUID (V4 conformant)
508 impl rand::Rand for Uuid {
509 #[inline]
510 fn rand<R: rand::Rng>(rng: &mut R) -> Uuid {
511 let ub = rng.gen_vec(16);
512 let mut uuid = Uuid{ bytes: [0, .. 16] };
513 slice::bytes::copy_memory(uuid.bytes, ub.as_slice());
514 uuid.set_variant(VariantRFC4122);
515 uuid.set_version(Version4Random);
516 uuid
517 }
518 }
519
520 #[cfg(test)]
521 mod test {
522 extern crate collections;
523 extern crate rand;
524
525 use super::{Uuid, VariantMicrosoft, VariantNCS, VariantRFC4122,
526 Version1Mac, Version2Dce, Version3Md5, Version4Random,
527 Version5Sha1};
528 use std::str;
529 use std::io::MemWriter;
530
531 #[test]
532 fn test_nil() {
533 let nil = Uuid::nil();
534 let not_nil = Uuid::new_v4();
535
536 assert!(nil.is_nil());
537 assert!(!not_nil.is_nil());
538 }
539
540 #[test]
541 fn test_new() {
542 // Supported
543 let uuid1 = Uuid::new(Version4Random).unwrap();
544 let s = uuid1.to_simple_str();
545
546 assert!(s.len() == 32);
547 assert!(uuid1.get_version().unwrap() == Version4Random);
548
549 // Test unsupported versions
550 assert!(Uuid::new(Version1Mac) == None);
551 assert!(Uuid::new(Version2Dce) == None);
552 assert!(Uuid::new(Version3Md5) == None);
553 assert!(Uuid::new(Version5Sha1) == None);
554 }
555
556 #[test]
557 fn test_new_v4() {
558 let uuid1 = Uuid::new_v4();
559
560 assert!(uuid1.get_version().unwrap() == Version4Random);
561 assert!(uuid1.get_variant().unwrap() == VariantRFC4122);
562 }
563
564 #[test]
565 fn test_get_version() {
566 let uuid1 = Uuid::new_v4();
567
568 assert!(uuid1.get_version().unwrap() == Version4Random);
569 assert!(uuid1.get_version_num() == 4);
570 }
571
572 #[test]
573 fn test_get_variant() {
574 let uuid1 = Uuid::new_v4();
575 let uuid2 = Uuid::parse_string("550e8400-e29b-41d4-a716-446655440000").unwrap();
576 let uuid3 = Uuid::parse_string("67e55044-10b1-426f-9247-bb680e5fe0c8").unwrap();
577 let uuid4 = Uuid::parse_string("936DA01F9ABD4d9dC0C702AF85C822A8").unwrap();
578 let uuid5 = Uuid::parse_string("F9168C5E-CEB2-4faa-D6BF-329BF39FA1E4").unwrap();
579 let uuid6 = Uuid::parse_string("f81d4fae-7dec-11d0-7765-00a0c91e6bf6").unwrap();
580
581 assert!(uuid1.get_variant().unwrap() == VariantRFC4122);
582 assert!(uuid2.get_variant().unwrap() == VariantRFC4122);
583 assert!(uuid3.get_variant().unwrap() == VariantRFC4122);
584 assert!(uuid4.get_variant().unwrap() == VariantMicrosoft);
585 assert!(uuid5.get_variant().unwrap() == VariantMicrosoft);
586 assert!(uuid6.get_variant().unwrap() == VariantNCS);
587 }
588
589 #[test]
590 fn test_parse_uuid_v4() {
591 use super::{ErrorInvalidCharacter, ErrorInvalidGroups,
592 ErrorInvalidGroupLength, ErrorInvalidLength};
593
594 // Invalid
595 assert!(Uuid::parse_string("").is_err());
596 assert!(Uuid::parse_string("!").is_err());
597 assert!(Uuid::parse_string("F9168C5E-CEB2-4faa-B6BF-329BF39FA1E45").is_err());
598 assert!(Uuid::parse_string("F9168C5E-CEB2-4faa-BBF-329BF39FA1E4").is_err());
599 assert!(Uuid::parse_string("F9168C5E-CEB2-4faa-BGBF-329BF39FA1E4").is_err());
600 assert!(Uuid::parse_string("F9168C5E-CEB2-4faa-B6BFF329BF39FA1E4").is_err());
601 assert!(Uuid::parse_string("F9168C5E-CEB2-4faa").is_err());
602 assert!(Uuid::parse_string("F9168C5E-CEB2-4faaXB6BFF329BF39FA1E4").is_err());
603 assert!(Uuid::parse_string("F9168C5E-CEB-24fa-eB6BFF32-BF39FA1E4").is_err());
604 assert!(Uuid::parse_string("01020304-1112-2122-3132-41424344").is_err());
605 assert!(Uuid::parse_string("67e5504410b1426f9247bb680e5fe0c").is_err());
606 assert!(Uuid::parse_string("67e5504410b1426f9247bb680e5fe0c88").is_err());
607 assert!(Uuid::parse_string("67e5504410b1426f9247bb680e5fe0cg8").is_err());
608 assert!(Uuid::parse_string("67e5504410b1426%9247bb680e5fe0c8").is_err());
609
610 // Valid
611 assert!(Uuid::parse_string("00000000000000000000000000000000").is_ok());
612 assert!(Uuid::parse_string("67e55044-10b1-426f-9247-bb680e5fe0c8").is_ok());
613 assert!(Uuid::parse_string("67e55044-10b1-426f-9247-bb680e5fe0c8").is_ok());
614 assert!(Uuid::parse_string("F9168C5E-CEB2-4faa-B6BF-329BF39FA1E4").is_ok());
615 assert!(Uuid::parse_string("67e5504410b1426f9247bb680e5fe0c8").is_ok());
616 assert!(Uuid::parse_string("01020304-1112-2122-3132-414243444546").is_ok());
617 assert!(Uuid::parse_string("urn:uuid:67e55044-10b1-426f-9247-bb680e5fe0c8").is_ok());
618
619 // Nil
620 let nil = Uuid::nil();
621 assert!(Uuid::parse_string("00000000000000000000000000000000").unwrap() == nil);
622 assert!(Uuid::parse_string("00000000-0000-0000-0000-000000000000").unwrap() == nil);
623
624 // Round-trip
625 let uuid_orig = Uuid::new_v4();
626 let orig_str = uuid_orig.to_str();
627 let uuid_out = Uuid::parse_string(orig_str).unwrap();
628 assert!(uuid_orig == uuid_out);
629
630 // Test error reporting
631 let e = Uuid::parse_string("67e5504410b1426f9247bb680e5fe0c").unwrap_err();
632 assert!(match e { ErrorInvalidLength(n) => n==31, _ => false });
633
634 let e = Uuid::parse_string("67e550X410b1426f9247bb680e5fe0cd").unwrap_err();
635 assert!(match e { ErrorInvalidCharacter(c, n) => c=='X' && n==6, _ => false });
636
637 let e = Uuid::parse_string("67e550-4105b1426f9247bb680e5fe0c").unwrap_err();
638 assert!(match e { ErrorInvalidGroups(n) => n==2, _ => false });
639
640 let e = Uuid::parse_string("F9168C5E-CEB2-4faa-B6BF1-02BF39FA1E4").unwrap_err();
641 assert!(match e { ErrorInvalidGroupLength(g, n, e) => g==3 && n==5 && e==4, _ => false });
642 }
643
644 #[test]
645 fn test_to_simple_str() {
646 let uuid1 = Uuid::new_v4();
647 let s = uuid1.to_simple_str();
648
649 assert!(s.len() == 32);
650 assert!(s.chars().all(|c| c.is_digit_radix(16)));
651 }
652
653 #[test]
654 fn test_to_str() {
655 let uuid1 = Uuid::new_v4();
656 let s = uuid1.to_str();
657
658 assert!(s.len() == 32);
659 assert!(s.chars().all(|c| c.is_digit_radix(16)));
660 }
661
662 #[test]
663 fn test_to_hyphenated_str() {
664 let uuid1 = Uuid::new_v4();
665 let s = uuid1.to_hyphenated_str();
666
667 assert!(s.len() == 36);
668 assert!(s.chars().all(|c| c.is_digit_radix(16) || c == '-'));
669 }
670
671 #[test]
672 fn test_to_urn_str() {
673 let uuid1 = Uuid::new_v4();
674 let ss = uuid1.to_urn_str();
675 let s = ss.slice(9, ss.len());
676
677 assert!(ss.starts_with("urn:uuid:"));
678 assert!(s.len() == 36);
679 assert!(s.chars().all(|c| c.is_digit_radix(16) || c == '-'));
680 }
681
682 #[test]
683 fn test_to_str_matching() {
684 let uuid1 = Uuid::new_v4();
685
686 let hs = uuid1.to_hyphenated_str();
687 let ss = uuid1.to_str();
688
689 let hsn = str::from_chars(hs.chars()
690 .filter(|&c| c != '-')
691 .collect::<Vec<char>>()
692 .as_slice());
693
694 assert!(hsn == ss);
695 }
696
697 #[test]
698 fn test_string_roundtrip() {
699 let uuid = Uuid::new_v4();
700
701 let hs = uuid.to_hyphenated_str();
702 let uuid_hs = Uuid::parse_string(hs).unwrap();
703 assert!(uuid_hs == uuid);
704
705 let ss = uuid.to_str();
706 let uuid_ss = Uuid::parse_string(ss).unwrap();
707 assert!(uuid_ss == uuid);
708 }
709
710 #[test]
711 fn test_compare() {
712 let uuid1 = Uuid::new_v4();
713 let uuid2 = Uuid::new_v4();
714
715 assert!(uuid1 == uuid1);
716 assert!(uuid2 == uuid2);
717 assert!(uuid1 != uuid2);
718 assert!(uuid2 != uuid1);
719 }
720
721 #[test]
722 fn test_from_fields() {
723 let d1: u32 = 0xa1a2a3a4;
724 let d2: u16 = 0xb1b2;
725 let d3: u16 = 0xc1c2;
726 let d4: Vec<u8> = vec!(0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8);
727
728 let u = Uuid::from_fields(d1, d2, d3, d4.as_slice());
729
730 let expected = "a1a2a3a4b1b2c1c2d1d2d3d4d5d6d7d8".to_owned();
731 let result = u.to_simple_str();
732 assert!(result == expected);
733 }
734
735 #[test]
736 fn test_from_bytes() {
737 let b = vec!( 0xa1, 0xa2, 0xa3, 0xa4, 0xb1, 0xb2, 0xc1, 0xc2,
738 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8 );
739
740 let u = Uuid::from_bytes(b.as_slice()).unwrap();
741 let expected = "a1a2a3a4b1b2c1c2d1d2d3d4d5d6d7d8".to_owned();
742
743 assert!(u.to_simple_str() == expected);
744 }
745
746 #[test]
747 fn test_as_bytes() {
748 let u = Uuid::new_v4();
749 let ub = u.as_bytes();
750
751 assert!(ub.len() == 16);
752 assert!(! ub.iter().all(|&b| b == 0));
753 }
754
755 #[test]
756 fn test_bytes_roundtrip() {
757 let b_in: [u8, ..16] = [ 0xa1, 0xa2, 0xa3, 0xa4, 0xb1, 0xb2, 0xc1, 0xc2,
758 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8 ];
759
760 let u = Uuid::from_bytes(b_in.clone()).unwrap();
761
762 let b_out = u.as_bytes();
763
764 assert!(b_in == b_out);
765 }
766
767 #[test]
768 fn test_operator_eq() {
769 let u1 = Uuid::new_v4();
770 let u2 = u1.clone();
771 let u3 = Uuid::new_v4();
772
773 assert!(u1 == u1);
774 assert!(u1 == u2);
775 assert!(u2 == u1);
776
777 assert!(u1 != u3);
778 assert!(u3 != u1);
779 assert!(u2 != u3);
780 assert!(u3 != u2);
781 }
782
783 #[test]
784 fn test_rand_rand() {
785 let mut rng = rand::task_rng();
786 let u: Box<Uuid> = rand::Rand::rand(&mut rng);
787 let ub = u.as_bytes();
788
789 assert!(ub.len() == 16);
790 assert!(! ub.iter().all(|&b| b == 0));
791 }
792
793 #[test]
794 fn test_serialize_round_trip() {
795 use serialize::ebml;
796 use serialize::{Encodable, Decodable};
797
798 let u = Uuid::new_v4();
799 let mut wr = MemWriter::new();
800 let _ = u.encode(&mut ebml::writer::Encoder(&mut wr));
801 let doc = ebml::reader::Doc(wr.get_ref());
802 let u2 = Decodable::decode(&mut ebml::reader::Decoder(doc)).unwrap();
803 assert_eq!(u, u2);
804 }
805
806 #[test]
807 fn test_iterbytes_impl_for_uuid() {
808 use self::collections::HashSet;
809 let mut set = HashSet::new();
810 let id1 = Uuid::new_v4();
811 let id2 = Uuid::new_v4();
812 set.insert(id1);
813 assert!(set.contains(&id1));
814 assert!(!set.contains(&id2));
815 }
816 }
817
818 #[cfg(test)]
819 mod bench {
820 extern crate test;
821 use self::test::Bencher;
822 use super::Uuid;
823
824 #[bench]
825 pub fn create_uuids(b: &mut Bencher) {
826 b.iter(|| {
827 Uuid::new_v4();
828 })
829 }
830
831 #[bench]
832 pub fn uuid_to_str(b: &mut Bencher) {
833 let u = Uuid::new_v4();
834 b.iter(|| {
835 u.to_str();
836 })
837 }
838
839 #[bench]
840 pub fn parse_str(b: &mut Bencher) {
841 let s = "urn:uuid:F9168C5E-CEB2-4faa-B6BF-329BF39FA1E4";
842 b.iter(|| {
843 Uuid::parse_string(s).unwrap();
844 })
845 }
846 }
libuuid/lib.rs:131:75-131:75 -struct- definition:
/// A UUID stored as fields (identical to UUID, used only for conversions)
struct UuidFields {
/// First field, 32-bit word
references:- 2215: // First construct a temporary field-based struct
216: let mut fields = UuidFields {
217: data1: 0,
--
341: // Ensure fields are in network byte order, as per RFC.
342: let mut uf: UuidFields;
343: unsafe {
libuuid/lib.rs:144:22-144:22 -enum- definition:
pub enum ParseError {
ErrorInvalidLength(uint),
ErrorInvalidCharacter(char, uint),
references:- 2152: /// Converts a ParseError to a string
153: impl fmt::Show for ParseError {
154: fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
--
371: /// supported by this parsing function.
372: pub fn parse_string(us: &str) -> Result<Uuid, ParseError> {
libuuid/lib.rs:119:43-119:43 -struct- definition:
/// A Universally Unique Identifier (UUID)
pub struct Uuid {
/// The 128-bit number stored in 16 bytes
references:- 27178: pub fn nil() -> Uuid {
179: let uuid = Uuid{ bytes: [0, .. 16] };
180: uuid
--
511: let ub = rng.gen_vec(16);
512: let mut uuid = Uuid{ bytes: [0, .. 16] };
513: slice::bytes::copy_memory(uuid.bytes, ub.as_slice());
libuuid/lib.rs:107:16-107:16 -enum- definition:
pub enum UuidVariant {
/// Reserved by the NCS for backward compatibility
VariantNCS,
references:- 5106: /// The reserved variants of UUIDs
108: pub enum UuidVariant {
--
247: /// Specifies the variant of the UUID structure
248: fn set_variant(&mut self, v: UuidVariant) {
249: // Octet 8 contains the variant in the most significant 3 bits
--
267: /// * [Variant Reference](http://tools.ietf.org/html/rfc4122#section-4.1.1)
268: pub fn get_variant(&self) -> Option<UuidVariant> {
269: if self.bytes[8] & 0x80 == 0x00 {
libuuid/lib.rs:92:16-92:16 -enum- definition:
pub enum UuidVersion {
/// Version 1: MAC address
Version1Mac = 1,
references:- 6304: /// This represents the algorithm used to generate the contents
305: pub fn get_version(&self) -> Option<UuidVersion> {
306: let v = self.bytes[6] >> 4;