(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(vUuidVersion) -> 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(d1u32, d2u16, d3u16, 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, vUuidVariant) {
 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, vUuidVersion) {
 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 sVec<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 ufUuidFields;
 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_groupsVec<&str> = us.split_str("-").collect();
 397  
 398          // Get the length of each group
 399          let group_lensVec<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:- 2
215:         // 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:- 2
152: /// 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:- 27
178:     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:- 5
106: /// 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:- 6
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;