uuid-1.10.0/.cargo_vcs_info.json0000644000000001360000000000100120610ustar { "git": { "sha1": "4b4c590ae323b683a7ba80f05c83d3002ddc2fc5" }, "path_in_vcs": "" }uuid-1.10.0/Cargo.toml0000644000000075070000000000100100700ustar # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies. # # If you are reading this file be aware that the original Cargo.toml # will likely look very different (and much more reasonable). # See Cargo.toml.orig for the original contents. [package] edition = "2018" rust-version = "1.60.0" name = "uuid" version = "1.10.0" authors = [ "Ashley Mannix", "Dylan DPC", "Hunar Roop Kahlon", ] include = [ "src", "README.md", "LICENSE-APACHE", "LICENSE-MIT", ] description = "A library to generate and parse UUIDs." homepage = "https://github.com/uuid-rs/uuid" documentation = "https://docs.rs/uuid" readme = "README.md" keywords = [ "guid", "unique", "uuid", ] categories = [ "data-structures", "no-std", "parser-implementations", "wasm", ] license = "Apache-2.0 OR MIT" repository = "https://github.com/uuid-rs/uuid" [package.metadata.docs.rs] features = [ "serde", "arbitrary", "slog", "borsh", "v1", "v3", "v4", "v5", "v6", "v7", "v8", ] rustc-args = [ "--cfg", "uuid_unstable", ] rustdoc-args = [ "--cfg", "uuid_unstable", ] targets = ["x86_64-unknown-linux-gnu"] [package.metadata.playground] features = [ "serde", "v1", "v3", "v4", "v5", "v6", "v7", "v8", ] [dependencies.arbitrary] version = "1.1.3" optional = true [dependencies.atomic] version = "0.6" optional = true default-features = false [dependencies.borsh] version = "1" optional = true default-features = false [dependencies.borsh-derive] version = "1" optional = true default-features = false [dependencies.bytemuck] version = "1.14.0" features = ["derive"] optional = true [dependencies.getrandom] version = "0.2" optional = true [dependencies.md-5] version = "0.10" optional = true default-features = false [dependencies.rand] version = "0.8" optional = true [dependencies.serde] version = "1.0.56" optional = true default-features = false [dependencies.sha1_smol] version = "1" optional = true default-features = false [dependencies.slog] version = "2" optional = true [dependencies.uuid-macro-internal] version = "1.10.0" optional = true [dependencies.zerocopy] version = "0.7" features = ["derive"] optional = true [dev-dependencies.bincode] version = "1.0" [dev-dependencies.rustversion] version = "1" [dev-dependencies.serde_derive] version = "1.0.79" [dev-dependencies.serde_json] version = "1.0" [dev-dependencies.serde_test] version = "1.0.56" [dev-dependencies.trybuild] version = "1.0.52" [features] atomic = ["dep:atomic"] borsh = [ "dep:borsh", "dep:borsh-derive", ] default = ["std"] fast-rng = [ "rng", "dep:rand", ] js = [ "dep:wasm-bindgen", "getrandom?/js", ] macro-diagnostics = ["dep:uuid-macro-internal"] md5 = ["dep:md-5"] rng = ["dep:getrandom"] sha1 = ["dep:sha1_smol"] std = [] v1 = ["atomic"] v3 = ["md5"] v4 = ["rng"] v5 = ["sha1"] v6 = ["atomic"] v7 = ["rng"] v8 = [] [target."cfg(all(target_arch = \"wasm32\", target_vendor = \"unknown\", target_os = \"unknown\"))".dependencies.wasm-bindgen] version = "0.2" optional = true [target."cfg(all(target_arch = \"wasm32\", target_vendor = \"unknown\", target_os = \"unknown\"))".dev-dependencies.wasm-bindgen-test] version = "0.3" [target."cfg(target = \"wasm32-unknown-unknown\")".dev-dependencies.wasm-bindgen] version = "0.2" [badges.is-it-maintained-issue-resolution] repository = "uuid-rs/uuid" [badges.is-it-maintained-open-issues] repository = "uuid-rs/uuid" [badges.maintenance] status = "actively-developed" [lints.rust.unexpected_cfgs] level = "allow" priority = 0 uuid-1.10.0/Cargo.toml.orig000064400000000000000000000102371046102023000135430ustar 00000000000000[package] authors = [ "Ashley Mannix", "Dylan DPC", "Hunar Roop Kahlon" ] categories = [ "data-structures", "no-std", "parser-implementations", "wasm" ] description = "A library to generate and parse UUIDs." documentation = "https://docs.rs/uuid" edition = "2018" include = [ "src", "README.md", "LICENSE-APACHE", "LICENSE-MIT", ] keywords = [ "guid", "unique", "uuid" ] license = "Apache-2.0 OR MIT" homepage = "https://github.com/uuid-rs/uuid" name = "uuid" readme = "README.md" repository = "https://github.com/uuid-rs/uuid" version = "1.10.0" # remember to update html_root_url in lib.rs rust-version = "1.60.0" [package.metadata.docs.rs] rustc-args = ["--cfg", "uuid_unstable"] rustdoc-args = ["--cfg", "uuid_unstable"] targets = ["x86_64-unknown-linux-gnu"] features = ["serde", "arbitrary", "slog", "borsh", "v1", "v3", "v4", "v5", "v6", "v7", "v8"] [package.metadata.playground] features = ["serde", "v1", "v3", "v4", "v5", "v6", "v7", "v8"] [lints.rust] unexpected_cfgs = { level = "allow", check-cfg = ['cfg(uuid_unstable)'] } [badges.is-it-maintained-issue-resolution] repository = "uuid-rs/uuid" [badges.is-it-maintained-open-issues] repository = "uuid-rs/uuid" [badges.maintenance] status = "actively-developed" [features] default = ["std"] std = [] macro-diagnostics = ["dep:uuid-macro-internal"] # NOTE: When adding new features, check the `ci.yml` workflow # and include them where necessary (you can follow along with existing features) v1 = ["atomic"] v3 = ["md5"] v4 = ["rng"] v5 = ["sha1"] v6 = ["atomic"] v7 = ["rng"] v8 = [] js = ["dep:wasm-bindgen", "getrandom?/js"] rng = ["dep:getrandom"] fast-rng = ["rng", "dep:rand"] sha1 = ["dep:sha1_smol"] md5 = ["dep:md-5"] atomic = ["dep:atomic"] borsh = ["dep:borsh", "dep:borsh-derive"] # Public: Used in trait impls on `Uuid` [dependencies.bytemuck] version = "1.14.0" optional = true features = ["derive"] # Public: Used in trait impls on `Uuid` [dependencies.serde] default-features = false optional = true version = "1.0.56" # Public: Used in trait impls on `Uuid` [dependencies.slog] optional = true version = "2" # Public: Used in trait impls on `Uuid` [dependencies.arbitrary] optional = true version = "1.1.3" # Public (unstable): Used in `zerocopy` derive # Unstable: also need RUSTFLAGS="--cfg uuid_unstable" to work # This feature may break between releases, or be removed entirely before # stabilization. # See: https://github.com/uuid-rs/uuid/issues/588 [dependencies.zerocopy] optional = true version = "0.7" features = ["derive"] # Public: Used in trait impls on `Uuid` [dependencies.borsh] optional = true version = "1" default-features = false # Private [dependencies.borsh-derive] optional = true version = "1" default-features = false # Public # Usage of `getrandom`'s pluggable randomness for custom targets is documented # in `uuid`'s library docs [dependencies.getrandom] optional = true version = "0.2" # Private [dependencies.rand] optional = true version = "0.8" # Private [dependencies.md-5] default-features = false optional = true version = "0.10" # Private [dependencies.sha1_smol] default-features = false optional = true version = "1" # Public: Re-exported [dependencies.uuid-macro-internal] version = "1.10.0" path = "macros" optional = true # Private [dependencies.atomic] default-features = false optional = true version = "0.6" # Private [target.'cfg(all(target_arch = "wasm32", target_vendor = "unknown", target_os = "unknown"))'.dependencies.wasm-bindgen] version = "0.2" optional = true [dev-dependencies.bincode] version = "1.0" [dev-dependencies.serde_derive] version = "1.0.79" [dev-dependencies.serde_json] version = "1.0" [dev-dependencies.serde_test] version = "1.0.56" [target.'cfg(target = "wasm32-unknown-unknown")'.dev-dependencies.wasm-bindgen] version = "0.2" [target.'cfg(all(target_arch = "wasm32", target_vendor = "unknown", target_os = "unknown"))'.dev-dependencies.wasm-bindgen-test] version = "0.3" [dev-dependencies.trybuild] version = "1.0.52" [dev-dependencies.rustversion] version = "1" [workspace] members = [ "macros", "examples", "tests/smoke-test", ] uuid-1.10.0/LICENSE-APACHE000064400000000000000000000251371046102023000126050ustar 00000000000000 Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. uuid-1.10.0/LICENSE-MIT000064400000000000000000000022051046102023000123040ustar 00000000000000Copyright (c) 2014 The Rust Project Developers Copyright (c) 2018 Ashley Mannix, Christopher Armstrong, Dylan DPC, Hunar Roop Kahlon Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. uuid-1.10.0/README.md000064400000000000000000000056431046102023000121400ustar 00000000000000# `uuid` [![Latest Version](https://img.shields.io/crates/v/uuid.svg)](https://crates.io/crates/uuid) [![Continuous integration](https://github.com/uuid-rs/uuid/actions/workflows/ci.yml/badge.svg)](https://github.com/uuid-rs/uuid/actions/workflows/ci.yml) Here's an example of a UUID: ```text 67e55044-10b1-426f-9247-bb680e5fe0c8 ``` A UUID is a unique 128-bit value, stored as 16 octets, and regularly formatted as a hex string in five groups. UUIDs are used to assign unique identifiers to entities without requiring a central allocating authority. They are particularly useful in distributed systems, though can be used in disparate areas, such as databases and network protocols. Typically a UUID is displayed in a readable string form as a sequence of hexadecimal digits, separated into groups by hyphens. The uniqueness property is not strictly guaranteed, however for all practical purposes, it can be assumed that an unintentional collision would be extremely unlikely. ## Getting started Add the following to your `Cargo.toml`: ```toml [dependencies.uuid] version = "1.10.0" features = [ "v4", # Lets you generate random UUIDs "fast-rng", # Use a faster (but still sufficiently random) RNG "macro-diagnostics", # Enable better diagnostics for compile-time UUIDs ] ``` When you want a UUID, you can generate one: ```rust use uuid::Uuid; let id = Uuid::new_v4(); ``` If you have a UUID value, you can use its string literal form inline: ```rust use uuid::{uuid, Uuid}; const ID: Uuid = uuid!("67e55044-10b1-426f-9247-bb680e5fe0c8"); ``` You can also parse UUIDs without needing any crate features: ```rust use uuid::{Uuid, Version}; let my_uuid = Uuid::parse_str("67e55044-10b1-426f-9247-bb680e5fe0c8")?; assert_eq!(Some(Version::Random), my_uuid.get_version()); ``` If you'd like to parse UUIDs _really_ fast, check out the [`uuid-simd`](https://github.com/nugine/uuid-simd) library. For more details on using `uuid`, [see the library documentation](https://docs.rs/uuid/1.10.0/uuid). ## References * [`uuid` library docs](https://docs.rs/uuid/1.10.0/uuid). * [Wikipedia: Universally Unique Identifier](http://en.wikipedia.org/wiki/Universally_unique_identifier). * [RFC 9562: Universally Unique IDentifiers (UUID)](https://www.ietf.org/rfc/rfc9562.html). --- # License Licensed under either of * Apache License, Version 2.0, (LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0) * MIT license (LICENSE-MIT or https://opensource.org/licenses/MIT) at your option. [![FOSSA Status](https://app.fossa.com/api/projects/git%2Bgithub.com%2Fuuid-rs%2Fuuid.svg?type=large)](https://app.fossa.com/projects/git%2Bgithub.com%2Fuuid-rs%2Fuuid?ref=badge_large) ## Contribution Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions. uuid-1.10.0/src/builder.rs000064400000000000000000000632261046102023000134450ustar 00000000000000// Copyright 2013-2014 The Rust Project Developers. // Copyright 2018 The Uuid Project Developers. // // See the COPYRIGHT file at the top-level directory of this distribution. // // Licensed under the Apache License, Version 2.0 or the MIT license // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. //! A Builder type for [`Uuid`]s. //! //! [`Uuid`]: ../struct.Uuid.html use crate::{error::*, timestamp, Bytes, Uuid, Variant, Version}; /// A builder for creating a UUID. /// /// This type is useful if you need to mutate individual fields of a [`Uuid`] /// while constructing it. Since the [`Uuid`] type is `Copy`, it doesn't offer /// any methods to mutate in place. They live on the `Builder` instead. /// /// The `Builder` type also always exposes APIs to construct [`Uuid`]s for any /// version without needing crate features or additional dependencies. It's a /// lower-level API than the methods on [`Uuid`]. /// /// # Examples /// /// Creating a version 4 UUID from externally generated random bytes: /// /// ``` /// # use uuid::{Builder, Version, Variant}; /// # let rng = || [ /// # 70, 235, 208, 238, 14, 109, 67, 201, 185, 13, 204, 195, 90, /// # 145, 63, 62, /// # ]; /// let random_bytes = rng(); /// /// let uuid = Builder::from_random_bytes(random_bytes).into_uuid(); /// /// assert_eq!(Some(Version::Random), uuid.get_version()); /// assert_eq!(Variant::RFC4122, uuid.get_variant()); /// ``` #[allow(missing_copy_implementations)] #[derive(Debug)] pub struct Builder(Uuid); impl Uuid { /// The 'nil UUID' (all zeros). /// /// The nil UUID is a special form of UUID that is specified to have all /// 128 bits set to zero. /// /// # References /// /// * [Nil UUID in RFC 9562](https://www.ietf.org/rfc/rfc9562.html#section-5.9) /// /// # Examples /// /// Basic usage: /// /// ``` /// # use uuid::Uuid; /// let uuid = Uuid::nil(); /// /// assert_eq!( /// "00000000-0000-0000-0000-000000000000", /// uuid.hyphenated().to_string(), /// ); /// ``` pub const fn nil() -> Self { Uuid::from_bytes([0; 16]) } /// The 'max UUID' (all ones). /// /// The max UUID is a special form of UUID that is specified to have all /// 128 bits set to one. /// /// # References /// /// * [Max UUID in RFC 9562](https://www.ietf.org/rfc/rfc9562.html#section-5.10) /// /// # Examples /// /// Basic usage: /// /// ``` /// # use uuid::Uuid; /// let uuid = Uuid::max(); /// /// assert_eq!( /// "ffffffff-ffff-ffff-ffff-ffffffffffff", /// uuid.hyphenated().to_string(), /// ); /// ``` pub const fn max() -> Self { Uuid::from_bytes([0xFF; 16]) } /// Creates a UUID from four field values. /// /// # Examples /// /// Basic usage: /// /// ``` /// # use uuid::Uuid; /// let d1 = 0xa1a2a3a4; /// let d2 = 0xb1b2; /// let d3 = 0xc1c2; /// let d4 = [0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8]; /// /// let uuid = Uuid::from_fields(d1, d2, d3, &d4); /// /// assert_eq!( /// "a1a2a3a4-b1b2-c1c2-d1d2-d3d4d5d6d7d8", /// uuid.hyphenated().to_string(), /// ); /// ``` pub const fn from_fields(d1: u32, d2: u16, d3: u16, d4: &[u8; 8]) -> Uuid { Uuid::from_bytes([ (d1 >> 24) as u8, (d1 >> 16) as u8, (d1 >> 8) as u8, d1 as u8, (d2 >> 8) as u8, d2 as u8, (d3 >> 8) as u8, d3 as u8, d4[0], d4[1], d4[2], d4[3], d4[4], d4[5], d4[6], d4[7], ]) } /// Creates a UUID from four field values in little-endian order. /// /// The bytes in the `d1`, `d2` and `d3` fields will be flipped to convert /// into big-endian order. This is based on the endianness of the UUID, /// rather than the target environment so bytes will be flipped on both /// big and little endian machines. /// /// # Examples /// /// Basic usage: /// /// ``` /// # use uuid::Uuid; /// let d1 = 0xa1a2a3a4; /// let d2 = 0xb1b2; /// let d3 = 0xc1c2; /// let d4 = [0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8]; /// /// let uuid = Uuid::from_fields_le(d1, d2, d3, &d4); /// /// assert_eq!( /// "a4a3a2a1-b2b1-c2c1-d1d2-d3d4d5d6d7d8", /// uuid.hyphenated().to_string(), /// ); /// ``` pub const fn from_fields_le(d1: u32, d2: u16, d3: u16, d4: &[u8; 8]) -> Uuid { Uuid::from_bytes([ d1 as u8, (d1 >> 8) as u8, (d1 >> 16) as u8, (d1 >> 24) as u8, (d2) as u8, (d2 >> 8) as u8, d3 as u8, (d3 >> 8) as u8, d4[0], d4[1], d4[2], d4[3], d4[4], d4[5], d4[6], d4[7], ]) } /// Creates a UUID from a 128bit value. /// /// # Examples /// /// Basic usage: /// /// ``` /// # use uuid::Uuid; /// let v = 0xa1a2a3a4b1b2c1c2d1d2d3d4d5d6d7d8u128; /// /// let uuid = Uuid::from_u128(v); /// /// assert_eq!( /// "a1a2a3a4-b1b2-c1c2-d1d2-d3d4d5d6d7d8", /// uuid.hyphenated().to_string(), /// ); /// ``` pub const fn from_u128(v: u128) -> Self { Uuid::from_bytes([ (v >> 120) as u8, (v >> 112) as u8, (v >> 104) as u8, (v >> 96) as u8, (v >> 88) as u8, (v >> 80) as u8, (v >> 72) as u8, (v >> 64) as u8, (v >> 56) as u8, (v >> 48) as u8, (v >> 40) as u8, (v >> 32) as u8, (v >> 24) as u8, (v >> 16) as u8, (v >> 8) as u8, v as u8, ]) } /// Creates a UUID from a 128bit value in little-endian order. /// /// The entire value will be flipped to convert into big-endian order. /// This is based on the endianness of the UUID, rather than the target /// environment so bytes will be flipped on both big and little endian /// machines. /// /// # Examples /// /// Basic usage: /// /// ``` /// # use uuid::Uuid; /// let v = 0xa1a2a3a4b1b2c1c2d1d2d3d4d5d6d7d8u128; /// /// let uuid = Uuid::from_u128_le(v); /// /// assert_eq!( /// "d8d7d6d5-d4d3-d2d1-c2c1-b2b1a4a3a2a1", /// uuid.hyphenated().to_string(), /// ); /// ``` pub const fn from_u128_le(v: u128) -> Self { Uuid::from_bytes([ v as u8, (v >> 8) as u8, (v >> 16) as u8, (v >> 24) as u8, (v >> 32) as u8, (v >> 40) as u8, (v >> 48) as u8, (v >> 56) as u8, (v >> 64) as u8, (v >> 72) as u8, (v >> 80) as u8, (v >> 88) as u8, (v >> 96) as u8, (v >> 104) as u8, (v >> 112) as u8, (v >> 120) as u8, ]) } /// Creates a UUID from two 64bit values. /// /// # Examples /// /// Basic usage: /// /// ``` /// # use uuid::Uuid; /// let hi = 0xa1a2a3a4b1b2c1c2u64; /// let lo = 0xd1d2d3d4d5d6d7d8u64; /// /// let uuid = Uuid::from_u64_pair(hi, lo); /// /// assert_eq!( /// "a1a2a3a4-b1b2-c1c2-d1d2-d3d4d5d6d7d8", /// uuid.hyphenated().to_string(), /// ); /// ``` pub const fn from_u64_pair(high_bits: u64, low_bits: u64) -> Self { Uuid::from_bytes([ (high_bits >> 56) as u8, (high_bits >> 48) as u8, (high_bits >> 40) as u8, (high_bits >> 32) as u8, (high_bits >> 24) as u8, (high_bits >> 16) as u8, (high_bits >> 8) as u8, high_bits as u8, (low_bits >> 56) as u8, (low_bits >> 48) as u8, (low_bits >> 40) as u8, (low_bits >> 32) as u8, (low_bits >> 24) as u8, (low_bits >> 16) as u8, (low_bits >> 8) as u8, low_bits as u8, ]) } /// Creates a UUID using the supplied bytes. /// /// # Errors /// /// This function will return an error if `b` has any length other than 16. /// /// # Examples /// /// Basic usage: /// /// ``` /// # fn main() -> Result<(), uuid::Error> { /// # use uuid::Uuid; /// let bytes = [ /// 0xa1, 0xa2, 0xa3, 0xa4, /// 0xb1, 0xb2, /// 0xc1, 0xc2, /// 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, /// ]; /// /// let uuid = Uuid::from_slice(&bytes)?; /// /// assert_eq!( /// "a1a2a3a4-b1b2-c1c2-d1d2-d3d4d5d6d7d8", /// uuid.hyphenated().to_string(), /// ); /// # Ok(()) /// # } /// ``` pub fn from_slice(b: &[u8]) -> Result { if b.len() != 16 { return Err(Error(ErrorKind::ByteLength { len: b.len() })); } let mut bytes: Bytes = [0; 16]; bytes.copy_from_slice(b); Ok(Uuid::from_bytes(bytes)) } /// Creates a UUID using the supplied bytes in little endian order. /// /// The individual fields encoded in the buffer will be flipped. /// /// # Errors /// /// This function will return an error if `b` has any length other than 16. /// /// # Examples /// /// Basic usage: /// /// ``` /// # fn main() -> Result<(), uuid::Error> { /// # use uuid::Uuid; /// let bytes = [ /// 0xa1, 0xa2, 0xa3, 0xa4, /// 0xb1, 0xb2, /// 0xc1, 0xc2, /// 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, /// ]; /// /// let uuid = Uuid::from_slice_le(&bytes)?; /// /// assert_eq!( /// uuid.hyphenated().to_string(), /// "a4a3a2a1-b2b1-c2c1-d1d2-d3d4d5d6d7d8" /// ); /// # Ok(()) /// # } /// ``` pub fn from_slice_le(b: &[u8]) -> Result { if b.len() != 16 { return Err(Error(ErrorKind::ByteLength { len: b.len() })); } let mut bytes: Bytes = [0; 16]; bytes.copy_from_slice(b); Ok(Uuid::from_bytes_le(bytes)) } /// Creates a UUID using the supplied bytes. /// /// # Examples /// /// Basic usage: /// /// ``` /// # fn main() -> Result<(), uuid::Error> { /// # use uuid::Uuid; /// let bytes = [ /// 0xa1, 0xa2, 0xa3, 0xa4, /// 0xb1, 0xb2, /// 0xc1, 0xc2, /// 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, /// ]; /// /// let uuid = Uuid::from_bytes(bytes); /// /// assert_eq!( /// uuid.hyphenated().to_string(), /// "a1a2a3a4-b1b2-c1c2-d1d2-d3d4d5d6d7d8" /// ); /// # Ok(()) /// # } /// ``` #[inline] pub const fn from_bytes(bytes: Bytes) -> Uuid { Uuid(bytes) } /// Creates a UUID using the supplied bytes in little endian order. /// /// The individual fields encoded in the buffer will be flipped. /// /// # Examples /// /// Basic usage: /// /// ``` /// # fn main() -> Result<(), uuid::Error> { /// # use uuid::Uuid; /// let bytes = [ /// 0xa1, 0xa2, 0xa3, 0xa4, /// 0xb1, 0xb2, /// 0xc1, 0xc2, /// 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, /// ]; /// /// let uuid = Uuid::from_bytes_le(bytes); /// /// assert_eq!( /// "a4a3a2a1-b2b1-c2c1-d1d2-d3d4d5d6d7d8", /// uuid.hyphenated().to_string(), /// ); /// # Ok(()) /// # } /// ``` pub const fn from_bytes_le(b: Bytes) -> Uuid { Uuid([ b[3], b[2], b[1], b[0], b[5], b[4], b[7], b[6], b[8], b[9], b[10], b[11], b[12], b[13], b[14], b[15], ]) } /// Creates a reference to a UUID from a reference to the supplied bytes. /// /// # Examples /// /// Basic usage: /// /// ``` /// # fn main() -> Result<(), uuid::Error> { /// # use uuid::Uuid; /// let bytes = [ /// 0xa1, 0xa2, 0xa3, 0xa4, /// 0xb1, 0xb2, /// 0xc1, 0xc2, /// 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, /// ]; /// /// let uuid = Uuid::from_bytes_ref(&bytes); /// /// assert_eq!( /// uuid.hyphenated().to_string(), /// "a1a2a3a4-b1b2-c1c2-d1d2-d3d4d5d6d7d8" /// ); /// /// assert!(std::ptr::eq( /// uuid as *const Uuid as *const u8, /// &bytes as *const [u8; 16] as *const u8, /// )); /// # Ok(()) /// # } /// ``` #[inline] pub fn from_bytes_ref(bytes: &Bytes) -> &Uuid { // SAFETY: `Bytes` and `Uuid` have the same ABI unsafe { &*(bytes as *const Bytes as *const Uuid) } } // NOTE: There is no `from_u128_ref` because in little-endian // environments the value isn't properly encoded. Callers would // need to use `.to_be()` themselves. } impl Builder { /// Creates a `Builder` using the supplied bytes. /// /// # Examples /// /// Basic usage: /// /// ``` /// # use uuid::Builder; /// let bytes = [ /// 0xa1, 0xa2, 0xa3, 0xa4, /// 0xb1, 0xb2, /// 0xc1, 0xc2, /// 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, /// ]; /// /// let uuid = Builder::from_bytes(bytes).into_uuid(); /// /// assert_eq!( /// "a1a2a3a4-b1b2-c1c2-d1d2-d3d4d5d6d7d8", /// uuid.hyphenated().to_string(), /// ); /// ``` pub const fn from_bytes(b: Bytes) -> Self { Builder(Uuid::from_bytes(b)) } /// Creates a `Builder` using the supplied bytes in little endian order. /// /// The individual fields encoded in the buffer will be flipped. /// /// # Examples /// /// Basic usage: /// /// ``` /// # fn main() -> Result<(), uuid::Error> { /// # use uuid::{Builder, Uuid}; /// let bytes = [ /// 0xa1, 0xa2, 0xa3, 0xa4, /// 0xb1, 0xb2, /// 0xc1, 0xc2, /// 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, /// ]; /// /// let uuid = Builder::from_bytes_le(bytes).into_uuid(); /// /// assert_eq!( /// "a4a3a2a1-b2b1-c2c1-d1d2-d3d4d5d6d7d8", /// uuid.hyphenated().to_string(), /// ); /// # Ok(()) /// # } /// ``` pub const fn from_bytes_le(b: Bytes) -> Self { Builder(Uuid::from_bytes_le(b)) } /// Creates a `Builder` for a version 1 UUID using the supplied timestamp, counter, and node ID. pub const fn from_gregorian_timestamp(ticks: u64, counter: u16, node_id: &[u8; 6]) -> Self { Builder(timestamp::encode_gregorian_timestamp( ticks, counter, node_id, )) } /// Creates a `Builder` for a version 3 UUID using the supplied MD5 hashed bytes. pub const fn from_md5_bytes(md5_bytes: Bytes) -> Self { Builder(Uuid::from_bytes(md5_bytes)) .with_variant(Variant::RFC4122) .with_version(Version::Md5) } /// Creates a `Builder` for a version 4 UUID using the supplied random bytes. /// /// This method assumes the bytes are already sufficiently random, it will only /// set the appropriate bits for the UUID version and variant. /// /// # Examples /// /// ``` /// # use uuid::{Builder, Variant, Version}; /// # let rng = || [ /// # 70, 235, 208, 238, 14, 109, 67, 201, 185, 13, 204, 195, 90, /// # 145, 63, 62, /// # ]; /// let random_bytes = rng(); /// let uuid = Builder::from_random_bytes(random_bytes).into_uuid(); /// /// assert_eq!(Some(Version::Random), uuid.get_version()); /// assert_eq!(Variant::RFC4122, uuid.get_variant()); /// ``` pub const fn from_random_bytes(random_bytes: Bytes) -> Self { Builder(Uuid::from_bytes(random_bytes)) .with_variant(Variant::RFC4122) .with_version(Version::Random) } /// Creates a `Builder` for a version 5 UUID using the supplied SHA-1 hashed bytes. /// /// This method assumes the bytes are already a SHA-1 hash, it will only set the appropriate /// bits for the UUID version and variant. pub const fn from_sha1_bytes(sha1_bytes: Bytes) -> Self { Builder(Uuid::from_bytes(sha1_bytes)) .with_variant(Variant::RFC4122) .with_version(Version::Sha1) } /// Creates a `Builder` for a version 6 UUID using the supplied timestamp, counter, and node ID. /// /// This method will encode the ticks, counter, and node ID in a sortable UUID. pub const fn from_sorted_gregorian_timestamp( ticks: u64, counter: u16, node_id: &[u8; 6], ) -> Self { Builder(timestamp::encode_sorted_gregorian_timestamp( ticks, counter, node_id, )) } /// Creates a `Builder` for a version 7 UUID using the supplied Unix timestamp and counter bytes. /// /// This method will set the variant field within the counter bytes without attempting to shift /// the data around it. Callers using the counter as a monotonic value should be careful not to /// store significant data in the 2 least significant bits of the 3rd byte. /// /// # Examples /// /// Creating a UUID using the current system timestamp: /// /// ``` /// # use std::convert::TryInto; /// use std::time::{Duration, SystemTime}; /// # fn main() -> Result<(), Box> { /// # use uuid::{Builder, Uuid, Variant, Version, Timestamp, NoContext}; /// # let rng = || [ /// # 70, 235, 208, 238, 14, 109, 67, 201, 185, 13 /// # ]; /// let ts = SystemTime::now().duration_since(SystemTime::UNIX_EPOCH)?; /// /// let random_bytes = rng(); /// /// let uuid = Builder::from_unix_timestamp_millis(ts.as_millis().try_into()?, &random_bytes).into_uuid(); /// /// assert_eq!(Some(Version::SortRand), uuid.get_version()); /// assert_eq!(Variant::RFC4122, uuid.get_variant()); /// # Ok(()) /// # } /// ``` pub const fn from_unix_timestamp_millis(millis: u64, counter_random_bytes: &[u8; 10]) -> Self { Builder(timestamp::encode_unix_timestamp_millis( millis, counter_random_bytes, )) } /// Creates a `Builder` for a version 8 UUID using the supplied user-defined bytes. /// /// This method won't interpret the given bytes in any way, except to set the appropriate /// bits for the UUID version and variant. pub const fn from_custom_bytes(custom_bytes: Bytes) -> Self { Builder::from_bytes(custom_bytes) .with_variant(Variant::RFC4122) .with_version(Version::Custom) } /// Creates a `Builder` using the supplied bytes. /// /// # Errors /// /// This function will return an error if `b` has any length other than 16. /// /// # Examples /// /// Basic usage: /// /// ``` /// # use uuid::Builder; /// # fn main() -> Result<(), uuid::Error> { /// let bytes = [ /// 0xa1, 0xa2, 0xa3, 0xa4, /// 0xb1, 0xb2, /// 0xc1, 0xc2, /// 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, /// ]; /// /// let uuid = Builder::from_slice(&bytes)?.into_uuid(); /// /// assert_eq!( /// "a1a2a3a4-b1b2-c1c2-d1d2-d3d4d5d6d7d8", /// uuid.hyphenated().to_string(), /// ); /// # Ok(()) /// # } /// ``` pub fn from_slice(b: &[u8]) -> Result { Ok(Builder(Uuid::from_slice(b)?)) } /// Creates a `Builder` using the supplied bytes in little endian order. /// /// The individual fields encoded in the buffer will be flipped. /// /// # Errors /// /// This function will return an error if `b` has any length other than 16. /// /// # Examples /// /// Basic usage: /// /// ``` /// # use uuid::Builder; /// # fn main() -> Result<(), uuid::Error> { /// let bytes = [ /// 0xa1, 0xa2, 0xa3, 0xa4, /// 0xb1, 0xb2, /// 0xc1, 0xc2, /// 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, /// ]; /// /// let uuid = Builder::from_slice_le(&bytes)?.into_uuid(); /// /// assert_eq!( /// "a4a3a2a1-b2b1-c2c1-d1d2-d3d4d5d6d7d8", /// uuid.hyphenated().to_string(), /// ); /// # Ok(()) /// # } /// ``` pub fn from_slice_le(b: &[u8]) -> Result { Ok(Builder(Uuid::from_slice_le(b)?)) } /// Creates a `Builder` from four field values. /// /// # Examples /// /// Basic usage: /// /// ``` /// # use uuid::Builder; /// let d1 = 0xa1a2a3a4; /// let d2 = 0xb1b2; /// let d3 = 0xc1c2; /// let d4 = [0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8]; /// /// let uuid = Builder::from_fields(d1, d2, d3, &d4).into_uuid(); /// /// assert_eq!( /// uuid.hyphenated().to_string(), /// "a1a2a3a4-b1b2-c1c2-d1d2-d3d4d5d6d7d8" /// ); /// ``` pub const fn from_fields(d1: u32, d2: u16, d3: u16, d4: &[u8; 8]) -> Self { Builder(Uuid::from_fields(d1, d2, d3, d4)) } /// Creates a `Builder` from four field values. /// /// # Examples /// /// Basic usage: /// /// ``` /// # use uuid::Builder; /// let d1 = 0xa1a2a3a4; /// let d2 = 0xb1b2; /// let d3 = 0xc1c2; /// let d4 = [0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8]; /// /// let uuid = Builder::from_fields_le(d1, d2, d3, &d4).into_uuid(); /// /// assert_eq!( /// uuid.hyphenated().to_string(), /// "a4a3a2a1-b2b1-c2c1-d1d2-d3d4d5d6d7d8" /// ); /// ``` pub const fn from_fields_le(d1: u32, d2: u16, d3: u16, d4: &[u8; 8]) -> Self { Builder(Uuid::from_fields_le(d1, d2, d3, d4)) } /// Creates a `Builder` from a 128bit value. /// /// # Examples /// /// Basic usage: /// /// ``` /// # use uuid::Builder; /// let v = 0xa1a2a3a4b1b2c1c2d1d2d3d4d5d6d7d8u128; /// /// let uuid = Builder::from_u128(v).into_uuid(); /// /// assert_eq!( /// "a1a2a3a4-b1b2-c1c2-d1d2-d3d4d5d6d7d8", /// uuid.hyphenated().to_string(), /// ); /// ``` pub const fn from_u128(v: u128) -> Self { Builder(Uuid::from_u128(v)) } /// Creates a UUID from a 128bit value in little-endian order. /// /// # Examples /// /// Basic usage: /// /// ``` /// # use uuid::Builder; /// let v = 0xa1a2a3a4b1b2c1c2d1d2d3d4d5d6d7d8u128; /// /// let uuid = Builder::from_u128_le(v).into_uuid(); /// /// assert_eq!( /// "d8d7d6d5-d4d3-d2d1-c2c1-b2b1a4a3a2a1", /// uuid.hyphenated().to_string(), /// ); /// ``` pub const fn from_u128_le(v: u128) -> Self { Builder(Uuid::from_u128_le(v)) } /// Creates a `Builder` with an initial [`Uuid::nil`]. /// /// # Examples /// /// Basic usage: /// /// ``` /// # use uuid::Builder; /// let uuid = Builder::nil().into_uuid(); /// /// assert_eq!( /// "00000000-0000-0000-0000-000000000000", /// uuid.hyphenated().to_string(), /// ); /// ``` pub const fn nil() -> Self { Builder(Uuid::nil()) } /// Specifies the variant of the UUID. pub fn set_variant(&mut self, v: Variant) -> &mut Self { *self = Builder(self.0).with_variant(v); self } /// Specifies the variant of the UUID. pub const fn with_variant(mut self, v: Variant) -> Self { let byte = (self.0).0[8]; (self.0).0[8] = match v { Variant::NCS => byte & 0x7f, Variant::RFC4122 => (byte & 0x3f) | 0x80, Variant::Microsoft => (byte & 0x1f) | 0xc0, Variant::Future => byte | 0xe0, }; self } /// Specifies the version number of the UUID. pub fn set_version(&mut self, v: Version) -> &mut Self { *self = Builder(self.0).with_version(v); self } /// Specifies the version number of the UUID. pub const fn with_version(mut self, v: Version) -> Self { (self.0).0[6] = ((self.0).0[6] & 0x0f) | ((v as u8) << 4); self } /// Get a reference to the underlying [`Uuid`]. /// /// # Examples /// /// Basic usage: /// /// ``` /// # use uuid::Builder; /// let builder = Builder::nil(); /// /// let uuid1 = builder.as_uuid(); /// let uuid2 = builder.as_uuid(); /// /// assert_eq!(uuid1, uuid2); /// ``` pub const fn as_uuid(&self) -> &Uuid { &self.0 } /// Convert the builder into a [`Uuid`]. /// /// # Examples /// /// Basic usage: /// /// ``` /// # use uuid::Builder; /// let uuid = Builder::nil().into_uuid(); /// /// assert_eq!( /// uuid.hyphenated().to_string(), /// "00000000-0000-0000-0000-000000000000" /// ); /// ``` pub const fn into_uuid(self) -> Uuid { self.0 } } #[doc(hidden)] impl Builder { #[deprecated( since = "1.10.0", note = "use `Builder::from_gregorian_timestamp(ticks, counter, node_id)`" )] pub const fn from_rfc4122_timestamp(ticks: u64, counter: u16, node_id: &[u8; 6]) -> Self { Builder::from_gregorian_timestamp(ticks, counter, node_id) } #[deprecated( since = "1.10.0", note = "use `Builder::from_sorted_gregorian_timestamp(ticks, counter, node_id)`" )] pub const fn from_sorted_rfc4122_timestamp( ticks: u64, counter: u16, node_id: &[u8; 6], ) -> Self { Builder::from_sorted_gregorian_timestamp(ticks, counter, node_id) } } uuid-1.10.0/src/error.rs000064400000000000000000000140131046102023000131360ustar 00000000000000use crate::std::fmt; /// A general error that can occur when working with UUIDs. #[derive(Clone, Debug, Eq, Hash, PartialEq)] pub struct Error(pub(crate) ErrorKind); #[derive(Clone, Debug, Eq, Hash, PartialEq)] pub(crate) enum ErrorKind { /// Invalid character in the [`Uuid`] string. /// /// [`Uuid`]: ../struct.Uuid.html Char { character: char, index: usize }, /// A simple [`Uuid`] didn't contain 32 characters. /// /// [`Uuid`]: ../struct.Uuid.html SimpleLength { len: usize }, /// A byte array didn't contain 16 bytes ByteLength { len: usize }, /// A hyphenated [`Uuid`] didn't contain 5 groups /// /// [`Uuid`]: ../struct.Uuid.html GroupCount { count: usize }, /// A hyphenated [`Uuid`] had a group that wasn't the right length /// /// [`Uuid`]: ../struct.Uuid.html GroupLength { group: usize, len: usize, index: usize, }, /// The input was not a valid UTF8 string InvalidUTF8, /// Some other error occurred. Other, } /// A string that is guaranteed to fail to parse to a [`Uuid`]. /// /// This type acts as a lightweight error indicator, suggesting /// that the string cannot be parsed but offering no error /// details. To get details, use `InvalidUuid::into_err`. /// /// [`Uuid`]: ../struct.Uuid.html #[derive(Clone, Debug, Eq, Hash, PartialEq)] pub struct InvalidUuid<'a>(pub(crate) &'a [u8]); impl<'a> InvalidUuid<'a> { /// Converts the lightweight error type into detailed diagnostics. pub fn into_err(self) -> Error { // Check whether or not the input was ever actually a valid UTF8 string let input_str = match std::str::from_utf8(self.0) { Ok(s) => s, Err(_) => return Error(ErrorKind::InvalidUTF8), }; let (uuid_str, offset, simple) = match input_str.as_bytes() { [b'{', s @ .., b'}'] => (s, 1, false), [b'u', b'r', b'n', b':', b'u', b'u', b'i', b'd', b':', s @ ..] => { (s, "urn:uuid:".len(), false) } s => (s, 0, true), }; let mut hyphen_count = 0; let mut group_bounds = [0; 4]; // SAFETY: the byte array came from a valid utf8 string, // and is aligned along char boundaries. let uuid_str = unsafe { std::str::from_utf8_unchecked(uuid_str) }; for (index, character) in uuid_str.char_indices() { let byte = character as u8; if character as u32 - byte as u32 > 0 { // Multibyte char return Error(ErrorKind::Char { character, index: index + offset + 1, }); } else if byte == b'-' { // While we search, also count group breaks if hyphen_count < 4 { group_bounds[hyphen_count] = index; } hyphen_count += 1; } else if !byte.is_ascii_hexdigit() { // Non-hex char return Error(ErrorKind::Char { character: byte as char, index: index + offset + 1, }); } } if hyphen_count == 0 && simple { // This means that we tried and failed to parse a simple uuid. // Since we verified that all the characters are valid, this means // that it MUST have an invalid length. Error(ErrorKind::SimpleLength { len: input_str.len(), }) } else if hyphen_count != 4 { // We tried to parse a hyphenated variant, but there weren't // 5 groups (4 hyphen splits). Error(ErrorKind::GroupCount { count: hyphen_count + 1, }) } else { // There are 5 groups, one of them has an incorrect length const BLOCK_STARTS: [usize; 5] = [0, 9, 14, 19, 24]; for i in 0..4 { if group_bounds[i] != BLOCK_STARTS[i + 1] - 1 { return Error(ErrorKind::GroupLength { group: i, len: group_bounds[i] - BLOCK_STARTS[i], index: offset + BLOCK_STARTS[i] + 1, }); } } // The last group must be too long Error(ErrorKind::GroupLength { group: 4, len: input_str.len() - BLOCK_STARTS[4], index: offset + BLOCK_STARTS[4] + 1, }) } } } // NOTE: This impl is part of the public API. Breaking changes to it should be carefully considered impl fmt::Display for Error { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self.0 { ErrorKind::Char { character, index, .. } => { write!(f, "invalid character: expected an optional prefix of `urn:uuid:` followed by [0-9a-fA-F-], found `{}` at {}", character, index) } ErrorKind::SimpleLength { len } => { write!( f, "invalid length: expected length 32 for simple format, found {}", len ) } ErrorKind::ByteLength { len } => { write!(f, "invalid length: expected 16 bytes, found {}", len) } ErrorKind::GroupCount { count } => { write!(f, "invalid group count: expected 5, found {}", count) } ErrorKind::GroupLength { group, len, .. } => { let expected = [8, 4, 4, 4, 12][group]; write!( f, "invalid group length in group {}: expected {}, found {}", group, expected, len ) } ErrorKind::InvalidUTF8 => write!(f, "non-UTF8 input"), ErrorKind::Other => write!(f, "failed to parse a UUID"), } } } #[cfg(feature = "std")] mod std_support { use super::*; use crate::std::error; impl error::Error for Error {} } uuid-1.10.0/src/external/arbitrary_support.rs000064400000000000000000000021401046102023000174200ustar 00000000000000use crate::{std::convert::TryInto, Builder, Uuid}; use arbitrary::{Arbitrary, Unstructured}; impl Arbitrary<'_> for Uuid { fn arbitrary(u: &mut Unstructured<'_>) -> arbitrary::Result { let b = u .bytes(16)? .try_into() .map_err(|_| arbitrary::Error::NotEnoughData)?; Ok(Builder::from_random_bytes(b).into_uuid()) } fn size_hint(_: usize) -> (usize, Option) { (16, Some(16)) } } #[cfg(test)] mod tests { use super::*; use crate::{Variant, Version}; #[test] fn test_arbitrary() { let mut bytes = Unstructured::new(&[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]); let uuid = Uuid::arbitrary(&mut bytes).unwrap(); assert_eq!(Some(Version::Random), uuid.get_version()); assert_eq!(Variant::RFC4122, uuid.get_variant()); } #[test] fn test_arbitrary_empty() { let mut bytes = Unstructured::new(&[]); // Ensure we don't panic when building an arbitrary `Uuid` let uuid = Uuid::arbitrary(&mut bytes); assert!(uuid.is_err()); } } uuid-1.10.0/src/external/borsh_support.rs000064400000000000000000000013551046102023000165450ustar 00000000000000#[cfg(test)] mod borsh_tests { use crate::Uuid; use std::string::ToString; #[test] fn test_serialize() { let uuid_str = "f9168c5e-ceb2-4faa-b6bf-329bf39fa1e4"; let uuid = Uuid::parse_str(uuid_str).unwrap(); let uuid_bytes = uuid.as_bytes().to_vec(); let borsh_bytes = borsh::to_vec(&uuid).unwrap(); assert_eq!(uuid_bytes, borsh_bytes); } #[test] fn test_deserialize() { let uuid_str = "f9168c5e-ceb2-4faa-b6bf-329bf39fa1e4"; let uuid = Uuid::parse_str(uuid_str).unwrap(); let uuid_bytes = uuid.as_bytes().to_vec(); let deserialized = borsh::from_slice::(&uuid_bytes).unwrap().to_string(); assert_eq!(uuid_str, deserialized); } } uuid-1.10.0/src/external/serde_support.rs000064400000000000000000000617301046102023000165350ustar 00000000000000// Copyright 2013-2014 The Rust Project Developers. // Copyright 2018 The Uuid Project Developers. // // See the COPYRIGHT file at the top-level directory of this distribution. // // Licensed under the Apache License, Version 2.0 or the MIT license // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. use crate::{ error::*, fmt::{Braced, Hyphenated, Simple, Urn}, std::fmt, Uuid, }; use serde::{ de::{self, Error as _}, Deserialize, Deserializer, Serialize, Serializer, }; impl Serialize for Uuid { fn serialize(&self, serializer: S) -> Result { if serializer.is_human_readable() { serializer.serialize_str(self.hyphenated().encode_lower(&mut Uuid::encode_buffer())) } else { serializer.serialize_bytes(self.as_bytes()) } } } impl Serialize for Hyphenated { fn serialize(&self, serializer: S) -> Result { serializer.serialize_str(self.encode_lower(&mut Uuid::encode_buffer())) } } impl Serialize for Simple { fn serialize(&self, serializer: S) -> Result { serializer.serialize_str(self.encode_lower(&mut Uuid::encode_buffer())) } } impl Serialize for Urn { fn serialize(&self, serializer: S) -> Result { serializer.serialize_str(self.encode_lower(&mut Uuid::encode_buffer())) } } impl Serialize for Braced { fn serialize(&self, serializer: S) -> Result { serializer.serialize_str(self.encode_lower(&mut Uuid::encode_buffer())) } } impl<'de> Deserialize<'de> for Uuid { fn deserialize>(deserializer: D) -> Result { fn de_error(e: Error) -> E { E::custom(format_args!("UUID parsing failed: {}", e)) } if deserializer.is_human_readable() { struct UuidVisitor; impl<'vi> de::Visitor<'vi> for UuidVisitor { type Value = Uuid; fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { write!(formatter, "a UUID string") } fn visit_str(self, value: &str) -> Result { value.parse::().map_err(de_error) } fn visit_bytes(self, value: &[u8]) -> Result { Uuid::from_slice(value).map_err(de_error) } fn visit_seq(self, mut seq: A) -> Result where A: de::SeqAccess<'vi>, { #[rustfmt::skip] let bytes = [ match seq.next_element()? { Some(e) => e, None => return Err(A::Error::invalid_length(0, &self)) }, match seq.next_element()? { Some(e) => e, None => return Err(A::Error::invalid_length(1, &self)) }, match seq.next_element()? { Some(e) => e, None => return Err(A::Error::invalid_length(2, &self)) }, match seq.next_element()? { Some(e) => e, None => return Err(A::Error::invalid_length(3, &self)) }, match seq.next_element()? { Some(e) => e, None => return Err(A::Error::invalid_length(4, &self)) }, match seq.next_element()? { Some(e) => e, None => return Err(A::Error::invalid_length(5, &self)) }, match seq.next_element()? { Some(e) => e, None => return Err(A::Error::invalid_length(6, &self)) }, match seq.next_element()? { Some(e) => e, None => return Err(A::Error::invalid_length(7, &self)) }, match seq.next_element()? { Some(e) => e, None => return Err(A::Error::invalid_length(8, &self)) }, match seq.next_element()? { Some(e) => e, None => return Err(A::Error::invalid_length(9, &self)) }, match seq.next_element()? { Some(e) => e, None => return Err(A::Error::invalid_length(10, &self)) }, match seq.next_element()? { Some(e) => e, None => return Err(A::Error::invalid_length(11, &self)) }, match seq.next_element()? { Some(e) => e, None => return Err(A::Error::invalid_length(12, &self)) }, match seq.next_element()? { Some(e) => e, None => return Err(A::Error::invalid_length(13, &self)) }, match seq.next_element()? { Some(e) => e, None => return Err(A::Error::invalid_length(14, &self)) }, match seq.next_element()? { Some(e) => e, None => return Err(A::Error::invalid_length(15, &self)) }, ]; Ok(Uuid::from_bytes(bytes)) } } deserializer.deserialize_str(UuidVisitor) } else { struct UuidBytesVisitor; impl<'vi> de::Visitor<'vi> for UuidBytesVisitor { type Value = Uuid; fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { write!(formatter, "bytes") } fn visit_bytes(self, value: &[u8]) -> Result { Uuid::from_slice(value).map_err(de_error) } } deserializer.deserialize_bytes(UuidBytesVisitor) } } } enum ExpectedFormat { Simple, Braced, Urn, } impl std::fmt::Display for ExpectedFormat { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let s = match self { ExpectedFormat::Simple => "a simple Uuid string like 67e5504410b1426f9247bb680e5fe0c8", ExpectedFormat::Braced => { "a braced Uuid string like {67e55044-10b1-426f-9247-bb680e5fe0c8}" } ExpectedFormat::Urn => { "a URN Uuid string like urn:uuid:67e55044-10b1-426f-9247-bb680e5fe0c8" } }; f.write_str(s) } } impl de::Expected for ExpectedFormat { fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { ::fmt(self, formatter) } } pub mod compact { //! Serialize a [`Uuid`] as a `[u8; 16]`. //! //! [`Uuid`]: ../../struct.Uuid.html /// Serialize from a [`Uuid`] as a `[u8; 16]` /// /// [`Uuid`]: ../../struct.Uuid.html pub fn serialize(u: &crate::Uuid, serializer: S) -> Result where S: serde::Serializer, { serde::Serialize::serialize(u.as_bytes(), serializer) } /// Deserialize a `[u8; 16]` as a [`Uuid`] /// /// [`Uuid`]: ../../struct.Uuid.html pub fn deserialize<'de, D>(deserializer: D) -> Result where D: serde::Deserializer<'de>, { let bytes: [u8; 16] = serde::Deserialize::deserialize(deserializer)?; Ok(crate::Uuid::from_bytes(bytes)) } #[cfg(test)] mod tests { use serde_derive::*; use serde_test::Configure; #[test] fn test_serialize_compact() { #[derive(Serialize, Debug, Deserialize, PartialEq)] struct UuidContainer { #[serde(with = "crate::serde::compact")] u: crate::Uuid, } let uuid_bytes = b"F9168C5E-CEB2-4F"; let container = UuidContainer { u: crate::Uuid::from_slice(uuid_bytes).unwrap(), }; // more complex because of the struct wrapping the actual UUID // serialization serde_test::assert_tokens( &container.compact(), &[ serde_test::Token::Struct { name: "UuidContainer", len: 1, }, serde_test::Token::Str("u"), serde_test::Token::Tuple { len: 16 }, serde_test::Token::U8(uuid_bytes[0]), serde_test::Token::U8(uuid_bytes[1]), serde_test::Token::U8(uuid_bytes[2]), serde_test::Token::U8(uuid_bytes[3]), serde_test::Token::U8(uuid_bytes[4]), serde_test::Token::U8(uuid_bytes[5]), serde_test::Token::U8(uuid_bytes[6]), serde_test::Token::U8(uuid_bytes[7]), serde_test::Token::U8(uuid_bytes[8]), serde_test::Token::U8(uuid_bytes[9]), serde_test::Token::U8(uuid_bytes[10]), serde_test::Token::U8(uuid_bytes[11]), serde_test::Token::U8(uuid_bytes[12]), serde_test::Token::U8(uuid_bytes[13]), serde_test::Token::U8(uuid_bytes[14]), serde_test::Token::U8(uuid_bytes[15]), serde_test::Token::TupleEnd, serde_test::Token::StructEnd, ], ) } } } /// Serialize from a [`Uuid`] as a `uuid::fmt::Simple` /// /// [`Uuid`]: ../../struct.Uuid.html /// /// ## Example /// /// ```rust /// #[derive(serde_derive::Serialize, serde_derive::Deserialize)] /// struct StructA { /// // This will change both serailization and deserialization /// #[serde(with = "uuid::serde::simple")] /// id: uuid::Uuid, /// } /// /// #[derive(serde_derive::Serialize, serde_derive::Deserialize)] /// struct StructB { /// // This will be serialized as uuid::fmt::Simple and deserialize from all valid formats /// #[serde(serialize_with = "uuid::serde::simple::serialize")] /// id: uuid::Uuid, /// } /// ``` pub mod simple { use serde::{de, Deserialize}; use crate::{parser::parse_simple, Uuid}; use super::ExpectedFormat; /// Serialize from a [`Uuid`] as a `uuid::fmt::Simple` /// /// [`Uuid`]: ../../struct.Uuid.html /// /// # Example /// /// ```rust /// #[derive(serde_derive::Serialize)] /// struct Struct { /// // This will be serialize as uuid::fmt::Simple /// #[serde(serialize_with = "uuid::serde::simple::serialize")] /// id: uuid::Uuid, /// } /// /// ``` pub fn serialize(u: &crate::Uuid, serializer: S) -> Result where S: serde::Serializer, { serde::Serialize::serialize(u.as_simple(), serializer) } /// Deserialize a simple Uuid string as a [`Uuid`] /// /// [`Uuid`]: ../../struct.Uuid.html pub fn deserialize<'de, D>(deserializer: D) -> Result where D: serde::Deserializer<'de>, { let s = <&str as Deserialize>::deserialize(deserializer)?; let bytes = parse_simple(s.as_bytes()).map_err(|_| { de::Error::invalid_value(de::Unexpected::Str(s), &ExpectedFormat::Simple) })?; Ok(Uuid::from_bytes(bytes)) } #[cfg(test)] mod tests { use serde::de::{self, Error}; use serde_test::{Readable, Token}; use crate::{external::serde_support::ExpectedFormat, Uuid}; const HYPHENATED_UUID_STR: &'static str = "f9168c5e-ceb2-4faa-b6bf-329bf39fa1e4"; const SIMPLE_UUID_STR: &'static str = "f9168c5eceb24faab6bf329bf39fa1e4"; #[test] fn test_serialize_as_simple() { #[derive(serde_derive::Serialize)] struct Struct(#[serde(with = "super")] crate::Uuid); let u = Struct(Uuid::parse_str(HYPHENATED_UUID_STR).unwrap()); serde_test::assert_ser_tokens( &u, &[ Token::NewtypeStruct { name: "Struct" }, Token::Str(SIMPLE_UUID_STR), ], ); } #[test] fn test_de_from_simple() { #[derive(PartialEq, Debug, serde_derive::Deserialize)] struct Struct(#[serde(with = "super")] crate::Uuid); let s = Struct(HYPHENATED_UUID_STR.parse().unwrap()); serde_test::assert_de_tokens::( &s, &[ Token::TupleStruct { name: "Struct", len: 1, }, Token::BorrowedStr(SIMPLE_UUID_STR), Token::TupleStructEnd, ], ); } #[test] fn test_de_reject_hypenated() { #[derive(PartialEq, Debug, serde_derive::Deserialize)] struct Struct(#[serde(with = "super")] crate::Uuid); serde_test::assert_de_tokens_error::>( &[ Token::TupleStruct { name: "Struct", len: 1, }, Token::BorrowedStr(HYPHENATED_UUID_STR), Token::TupleStructEnd, ], &format!( "{}", de::value::Error::invalid_value( de::Unexpected::Str(HYPHENATED_UUID_STR), &ExpectedFormat::Simple, ) ), ); } } } /// Serialize from a [`Uuid`] as a `uuid::fmt::Braced` /// /// [`Uuid`]: ../../struct.Uuid.html /// /// ## Example /// /// ```rust /// #[derive(serde_derive::Serialize, serde_derive::Deserialize)] /// struct StructA { /// // This will change both serailization and deserialization /// #[serde(with = "uuid::serde::braced")] /// id: uuid::Uuid, /// } /// /// #[derive(serde_derive::Serialize, serde_derive::Deserialize)] /// struct StructB { /// // This will be serialized as uuid::fmt::Urn and deserialize from all valid formats /// #[serde(serialize_with = "uuid::serde::braced::serialize")] /// id: uuid::Uuid, /// } /// ``` pub mod braced { use serde::{de, Deserialize}; use crate::parser::parse_braced; use super::ExpectedFormat; /// Serialize from a [`Uuid`] as a `uuid::fmt::Braced` /// /// [`Uuid`]: ../../struct.Uuid.html /// /// # Example /// /// ```rust /// #[derive(serde_derive::Serialize)] /// struct Struct { /// // This will be serialize as uuid::fmt::Braced /// #[serde(serialize_with = "uuid::serde::braced::serialize")] /// id: uuid::Uuid, /// } /// /// ``` pub fn serialize(u: &crate::Uuid, serializer: S) -> Result where S: serde::Serializer, { serde::Serialize::serialize(u.as_braced(), serializer) } /// Deserialize a braced Uuid string as a [`Uuid`] /// /// [`Uuid`]: ../../struct.Uuid.html pub fn deserialize<'de, D>(deserializer: D) -> Result where D: serde::Deserializer<'de>, { let s = <&str as Deserialize>::deserialize(deserializer)?; let bytes = parse_braced(s.as_bytes()).map_err(|_| { de::Error::invalid_value(de::Unexpected::Str(s), &ExpectedFormat::Braced) })?; Ok(crate::Uuid::from_bytes(bytes)) } #[cfg(test)] mod tests { use serde::de::{self, Error}; use serde_test::{Readable, Token}; use crate::{external::serde_support::ExpectedFormat, Uuid}; const HYPHENATED_UUID_STR: &'static str = "f9168c5e-ceb2-4faa-b6bf-329bf39fa1e4"; const BRACED_UUID_STR: &'static str = "{f9168c5e-ceb2-4faa-b6bf-329bf39fa1e4}"; #[test] fn test_serialize_as_braced() { #[derive(serde_derive::Serialize)] struct Struct(#[serde(with = "super")] crate::Uuid); let u = Struct(Uuid::parse_str(HYPHENATED_UUID_STR).unwrap()); serde_test::assert_ser_tokens( &u, &[ Token::NewtypeStruct { name: "Struct" }, Token::Str(BRACED_UUID_STR), ], ); } #[test] fn test_de_from_braced() { #[derive(PartialEq, Debug, serde_derive::Deserialize)] struct Struct(#[serde(with = "super")] crate::Uuid); let s = Struct(HYPHENATED_UUID_STR.parse().unwrap()); serde_test::assert_de_tokens::( &s, &[ Token::TupleStruct { name: "Struct", len: 1, }, Token::BorrowedStr(BRACED_UUID_STR), Token::TupleStructEnd, ], ); } #[test] fn test_de_reject_hypenated() { #[derive(PartialEq, Debug, serde_derive::Deserialize)] struct Struct(#[serde(with = "super")] crate::Uuid); serde_test::assert_de_tokens_error::>( &[ Token::TupleStruct { name: "Struct", len: 1, }, Token::BorrowedStr(HYPHENATED_UUID_STR), Token::TupleStructEnd, ], &format!( "{}", de::value::Error::invalid_value( de::Unexpected::Str(HYPHENATED_UUID_STR), &ExpectedFormat::Braced, ) ), ); } } } /// Serialize from a [`Uuid`] as a `uuid::fmt::Urn` /// /// [`Uuid`]: ../../struct.Uuid.html /// /// ## Example /// /// ```rust /// #[derive(serde_derive::Serialize, serde_derive::Deserialize)] /// struct StructA { /// // This will change both serailization and deserialization /// #[serde(with = "uuid::serde::urn")] /// id: uuid::Uuid, /// } /// /// #[derive(serde_derive::Serialize, serde_derive::Deserialize)] /// struct StructB { /// // This will be serialized as uuid::fmt::Urn and deserialize from all valid formats /// #[serde(serialize_with = "uuid::serde::urn::serialize")] /// id: uuid::Uuid, /// } /// ``` pub mod urn { use serde::{de, Deserialize}; use crate::parser::parse_urn; use super::ExpectedFormat; /// Serialize from a [`Uuid`] as a `uuid::fmt::Urn` /// /// [`Uuid`]: ../../struct.Uuid.html /// /// # Example /// /// ```rust /// #[derive(serde_derive::Serialize)] /// struct Struct { /// // This will be serialize as uuid::fmt::Urn /// #[serde(serialize_with = "uuid::serde::urn::serialize")] /// id: uuid::Uuid, /// } /// /// ``` pub fn serialize(u: &crate::Uuid, serializer: S) -> Result where S: serde::Serializer, { serde::Serialize::serialize(u.as_urn(), serializer) } /// Deserialize a urn Uuid string as a [`Uuid`] /// /// [`Uuid`]: ../../struct.Uuid.html pub fn deserialize<'de, D>(deserializer: D) -> Result where D: serde::Deserializer<'de>, { let s = <&str as Deserialize>::deserialize(deserializer)?; let bytes = parse_urn(s.as_bytes()) .map_err(|_| de::Error::invalid_value(de::Unexpected::Str(s), &ExpectedFormat::Urn))?; Ok(crate::Uuid::from_bytes(bytes)) } #[cfg(test)] mod tests { use serde::de::{self, Error}; use serde_test::{Readable, Token}; use crate::{external::serde_support::ExpectedFormat, Uuid}; const HYPHENATED_UUID_STR: &'static str = "f9168c5e-ceb2-4faa-b6bf-329bf39fa1e4"; const URN_UUID_STR: &'static str = "urn:uuid:f9168c5e-ceb2-4faa-b6bf-329bf39fa1e4"; #[test] fn test_serialize_as_urn() { #[derive(serde_derive::Serialize)] struct Struct(#[serde(with = "super")] crate::Uuid); let u = Struct(Uuid::parse_str(HYPHENATED_UUID_STR).unwrap()); serde_test::assert_ser_tokens( &u, &[ Token::NewtypeStruct { name: "Struct" }, Token::Str(URN_UUID_STR), ], ); } #[test] fn test_de_from_urn() { #[derive(PartialEq, Debug, serde_derive::Deserialize)] struct Struct(#[serde(with = "super")] crate::Uuid); let s = Struct(HYPHENATED_UUID_STR.parse().unwrap()); serde_test::assert_de_tokens::( &s, &[ Token::TupleStruct { name: "Struct", len: 1, }, Token::BorrowedStr(URN_UUID_STR), Token::TupleStructEnd, ], ); } #[test] fn test_de_reject_hypenated() { #[derive(PartialEq, Debug, serde_derive::Deserialize)] struct Struct(#[serde(with = "super")] crate::Uuid); serde_test::assert_de_tokens_error::>( &[ Token::TupleStruct { name: "Struct", len: 1, }, Token::BorrowedStr(HYPHENATED_UUID_STR), Token::TupleStructEnd, ], &format!( "{}", de::value::Error::invalid_value( de::Unexpected::Str(HYPHENATED_UUID_STR), &ExpectedFormat::Urn, ) ), ); } } } #[cfg(test)] mod serde_tests { use super::*; use serde_test::{Compact, Configure, Readable, Token}; #[test] fn test_serialize_readable_string() { let uuid_str = "f9168c5e-ceb2-4faa-b6bf-329bf39fa1e4"; let u = Uuid::parse_str(uuid_str).unwrap(); serde_test::assert_tokens(&u.readable(), &[Token::Str(uuid_str)]); } #[test] fn test_deserialize_readable_compact() { let uuid_bytes = b"F9168C5E-CEB2-4F"; let u = Uuid::from_slice(uuid_bytes).unwrap(); serde_test::assert_de_tokens( &u.readable(), &[ serde_test::Token::Tuple { len: 16 }, serde_test::Token::U8(uuid_bytes[0]), serde_test::Token::U8(uuid_bytes[1]), serde_test::Token::U8(uuid_bytes[2]), serde_test::Token::U8(uuid_bytes[3]), serde_test::Token::U8(uuid_bytes[4]), serde_test::Token::U8(uuid_bytes[5]), serde_test::Token::U8(uuid_bytes[6]), serde_test::Token::U8(uuid_bytes[7]), serde_test::Token::U8(uuid_bytes[8]), serde_test::Token::U8(uuid_bytes[9]), serde_test::Token::U8(uuid_bytes[10]), serde_test::Token::U8(uuid_bytes[11]), serde_test::Token::U8(uuid_bytes[12]), serde_test::Token::U8(uuid_bytes[13]), serde_test::Token::U8(uuid_bytes[14]), serde_test::Token::U8(uuid_bytes[15]), serde_test::Token::TupleEnd, ], ); } #[test] fn test_deserialize_readable_bytes() { let uuid_bytes = b"F9168C5E-CEB2-4F"; let u = Uuid::from_slice(uuid_bytes).unwrap(); serde_test::assert_de_tokens(&u.readable(), &[serde_test::Token::Bytes(uuid_bytes)]); } #[test] fn test_serialize_hyphenated() { let uuid_str = "f9168c5e-ceb2-4faa-b6bf-329bf39fa1e4"; let u = Uuid::parse_str(uuid_str).unwrap(); serde_test::assert_ser_tokens(&u.hyphenated(), &[Token::Str(uuid_str)]); } #[test] fn test_serialize_simple() { let uuid_str = "f9168c5eceb24faab6bf329bf39fa1e4"; let u = Uuid::parse_str(uuid_str).unwrap(); serde_test::assert_ser_tokens(&u.simple(), &[Token::Str(uuid_str)]); } #[test] fn test_serialize_urn() { let uuid_str = "urn:uuid:f9168c5e-ceb2-4faa-b6bf-329bf39fa1e4"; let u = Uuid::parse_str(uuid_str).unwrap(); serde_test::assert_ser_tokens(&u.urn(), &[Token::Str(uuid_str)]); } #[test] fn test_serialize_braced() { let uuid_str = "{f9168c5e-ceb2-4faa-b6bf-329bf39fa1e4}"; let u = Uuid::parse_str(uuid_str).unwrap(); serde_test::assert_ser_tokens(&u.braced(), &[Token::Str(uuid_str)]); } #[test] fn test_serialize_non_human_readable() { let uuid_bytes = b"F9168C5E-CEB2-4F"; let u = Uuid::from_slice(uuid_bytes).unwrap(); serde_test::assert_tokens( &u.compact(), &[serde_test::Token::Bytes(&[ 70, 57, 49, 54, 56, 67, 53, 69, 45, 67, 69, 66, 50, 45, 52, 70, ])], ); } #[test] fn test_de_failure() { serde_test::assert_de_tokens_error::>( &[Token::Str("hello_world")], "UUID parsing failed: invalid character: expected an optional prefix of `urn:uuid:` followed by [0-9a-fA-F-], found `h` at 1", ); serde_test::assert_de_tokens_error::>( &[Token::Bytes(b"hello_world")], "UUID parsing failed: invalid length: expected 16 bytes, found 11", ); } } uuid-1.10.0/src/external/slog_support.rs000064400000000000000000000020141046102023000163650ustar 00000000000000// Copyright 2013-2014 The Rust Project Developers. // Copyright 2018 The Uuid Project Developers. // // See the COPYRIGHT file at the top-level directory of this distribution. // // Licensed under the Apache License, Version 2.0 or the MIT license // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. use crate::Uuid; impl slog::Value for Uuid { fn serialize( &self, _: &slog::Record<'_>, key: slog::Key, serializer: &mut dyn slog::Serializer, ) -> Result<(), slog::Error> { serializer.emit_arguments(key, &format_args!("{}", self)) } } #[cfg(test)] mod tests { use crate::tests::new; use slog::{crit, Drain}; #[test] fn test_slog_kv() { let root = slog::Logger::root(slog::Discard.fuse(), slog::o!()); let u1 = new(); crit!(root, "test"; "u1" => u1); } } uuid-1.10.0/src/external.rs000064400000000000000000000003461046102023000136330ustar 00000000000000#[cfg(feature = "arbitrary")] pub(crate) mod arbitrary_support; #[cfg(feature = "borsh")] pub(crate) mod borsh_support; #[cfg(feature = "serde")] pub(crate) mod serde_support; #[cfg(feature = "slog")] pub(crate) mod slog_support; uuid-1.10.0/src/fmt.rs000064400000000000000000000730461046102023000126060ustar 00000000000000// Copyright 2013-2014 The Rust Project Developers. // Copyright 2018 The Uuid Project Developers. // // See the COPYRIGHT file at the top-level directory of this distribution. // // Licensed under the Apache License, Version 2.0 or the MIT license // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. //! Adapters for alternative string formats. use crate::{ std::{borrow::Borrow, fmt, ptr, str}, Uuid, Variant, }; #[cfg(feature = "std")] use crate::std::string::{String, ToString}; impl std::fmt::Debug for Uuid { #[inline] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fmt::LowerHex::fmt(self, f) } } impl fmt::Display for Uuid { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fmt::LowerHex::fmt(self, f) } } #[cfg(feature = "std")] impl From for String { fn from(uuid: Uuid) -> Self { uuid.to_string() } } impl fmt::Display for Variant { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match *self { Variant::NCS => write!(f, "NCS"), Variant::RFC4122 => write!(f, "RFC4122"), Variant::Microsoft => write!(f, "Microsoft"), Variant::Future => write!(f, "Future"), } } } impl fmt::LowerHex for Uuid { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fmt::LowerHex::fmt(self.as_hyphenated(), f) } } impl fmt::UpperHex for Uuid { #[inline] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fmt::UpperHex::fmt(self.as_hyphenated(), f) } } /// Format a [`Uuid`] as a hyphenated string, like /// `67e55044-10b1-426f-9247-bb680e5fe0c8`. #[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)] #[repr(transparent)] pub struct Hyphenated(Uuid); /// Format a [`Uuid`] as a simple string, like /// `67e5504410b1426f9247bb680e5fe0c8`. #[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)] #[repr(transparent)] pub struct Simple(Uuid); /// Format a [`Uuid`] as a URN string, like /// `urn:uuid:67e55044-10b1-426f-9247-bb680e5fe0c8`. #[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)] #[repr(transparent)] pub struct Urn(Uuid); /// Format a [`Uuid`] as a braced hyphenated string, like /// `{67e55044-10b1-426f-9247-bb680e5fe0c8}`. #[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)] #[repr(transparent)] pub struct Braced(Uuid); impl Uuid { /// Get a [`Hyphenated`] formatter. #[inline] pub const fn hyphenated(self) -> Hyphenated { Hyphenated(self) } /// Get a borrowed [`Hyphenated`] formatter. #[inline] pub fn as_hyphenated(&self) -> &Hyphenated { // SAFETY: `Uuid` and `Hyphenated` have the same ABI unsafe { &*(self as *const Uuid as *const Hyphenated) } } /// Get a [`Simple`] formatter. #[inline] pub const fn simple(self) -> Simple { Simple(self) } /// Get a borrowed [`Simple`] formatter. #[inline] pub fn as_simple(&self) -> &Simple { // SAFETY: `Uuid` and `Simple` have the same ABI unsafe { &*(self as *const Uuid as *const Simple) } } /// Get a [`Urn`] formatter. #[inline] pub const fn urn(self) -> Urn { Urn(self) } /// Get a borrowed [`Urn`] formatter. #[inline] pub fn as_urn(&self) -> &Urn { // SAFETY: `Uuid` and `Urn` have the same ABI unsafe { &*(self as *const Uuid as *const Urn) } } /// Get a [`Braced`] formatter. #[inline] pub const fn braced(self) -> Braced { Braced(self) } /// Get a borrowed [`Braced`] formatter. #[inline] pub fn as_braced(&self) -> &Braced { // SAFETY: `Uuid` and `Braced` have the same ABI unsafe { &*(self as *const Uuid as *const Braced) } } } const UPPER: [u8; 16] = [ b'0', b'1', b'2', b'3', b'4', b'5', b'6', b'7', b'8', b'9', b'A', b'B', b'C', b'D', b'E', b'F', ]; const LOWER: [u8; 16] = [ b'0', b'1', b'2', b'3', b'4', b'5', b'6', b'7', b'8', b'9', b'a', b'b', b'c', b'd', b'e', b'f', ]; #[inline] const fn format_simple(src: &[u8; 16], upper: bool) -> [u8; 32] { let lut = if upper { &UPPER } else { &LOWER }; let mut dst = [0; 32]; let mut i = 0; while i < 16 { let x = src[i]; dst[i * 2] = lut[(x >> 4) as usize]; dst[i * 2 + 1] = lut[(x & 0x0f) as usize]; i += 1; } dst } #[inline] const fn format_hyphenated(src: &[u8; 16], upper: bool) -> [u8; 36] { let lut = if upper { &UPPER } else { &LOWER }; let groups = [(0, 8), (9, 13), (14, 18), (19, 23), (24, 36)]; let mut dst = [0; 36]; let mut group_idx = 0; let mut i = 0; while group_idx < 5 { let (start, end) = groups[group_idx]; let mut j = start; while j < end { let x = src[i]; i += 1; dst[j] = lut[(x >> 4) as usize]; dst[j + 1] = lut[(x & 0x0f) as usize]; j += 2; } if group_idx < 4 { dst[end] = b'-'; } group_idx += 1; } dst } #[inline] fn encode_simple<'b>(src: &[u8; 16], buffer: &'b mut [u8], upper: bool) -> &'b mut str { let buf = &mut buffer[..Simple::LENGTH]; let dst = buf.as_mut_ptr(); // SAFETY: `buf` is guaranteed to be at least `LEN` bytes // SAFETY: The encoded buffer is ASCII encoded unsafe { ptr::write(dst.cast(), format_simple(src, upper)); str::from_utf8_unchecked_mut(buf) } } #[inline] fn encode_hyphenated<'b>(src: &[u8; 16], buffer: &'b mut [u8], upper: bool) -> &'b mut str { let buf = &mut buffer[..Hyphenated::LENGTH]; let dst = buf.as_mut_ptr(); // SAFETY: `buf` is guaranteed to be at least `LEN` bytes // SAFETY: The encoded buffer is ASCII encoded unsafe { ptr::write(dst.cast(), format_hyphenated(src, upper)); str::from_utf8_unchecked_mut(buf) } } #[inline] fn encode_braced<'b>(src: &[u8; 16], buffer: &'b mut [u8], upper: bool) -> &'b mut str { let buf = &mut buffer[..Braced::LENGTH]; buf[0] = b'{'; buf[Braced::LENGTH - 1] = b'}'; // SAFETY: `buf` is guaranteed to be at least `LEN` bytes // SAFETY: The encoded buffer is ASCII encoded unsafe { let dst = buf.as_mut_ptr().add(1); ptr::write(dst.cast(), format_hyphenated(src, upper)); str::from_utf8_unchecked_mut(buf) } } #[inline] fn encode_urn<'b>(src: &[u8; 16], buffer: &'b mut [u8], upper: bool) -> &'b mut str { let buf = &mut buffer[..Urn::LENGTH]; buf[..9].copy_from_slice(b"urn:uuid:"); // SAFETY: `buf` is guaranteed to be at least `LEN` bytes // SAFETY: The encoded buffer is ASCII encoded unsafe { let dst = buf.as_mut_ptr().add(9); ptr::write(dst.cast(), format_hyphenated(src, upper)); str::from_utf8_unchecked_mut(buf) } } impl Hyphenated { /// The length of a hyphenated [`Uuid`] string. /// /// [`Uuid`]: ../struct.Uuid.html pub const LENGTH: usize = 36; /// Creates a [`Hyphenated`] from a [`Uuid`]. /// /// [`Uuid`]: ../struct.Uuid.html /// [`Hyphenated`]: struct.Hyphenated.html pub const fn from_uuid(uuid: Uuid) -> Self { Hyphenated(uuid) } /// Writes the [`Uuid`] as a lower-case hyphenated string to /// `buffer`, and returns the subslice of the buffer that contains the /// encoded UUID. /// /// This is slightly more efficient than using the formatting /// infrastructure as it avoids virtual calls, and may avoid /// double buffering. /// /// [`Uuid`]: ../struct.Uuid.html /// /// # Panics /// /// Panics if the buffer is not large enough: it must have length at least /// [`LENGTH`]. [`Uuid::encode_buffer`] can be used to get a /// sufficiently-large temporary buffer. /// /// [`LENGTH`]: #associatedconstant.LENGTH /// [`Uuid::encode_buffer`]: ../struct.Uuid.html#method.encode_buffer /// /// # Examples /// /// ```rust /// use uuid::Uuid; /// /// fn main() -> Result<(), uuid::Error> { /// let uuid = Uuid::parse_str("936DA01f9abd4d9d80c702af85c822a8")?; /// /// // the encoded portion is returned /// assert_eq!( /// uuid.hyphenated() /// .encode_lower(&mut Uuid::encode_buffer()), /// "936da01f-9abd-4d9d-80c7-02af85c822a8" /// ); /// /// // the buffer is mutated directly, and trailing contents remains /// let mut buf = [b'!'; 40]; /// uuid.hyphenated().encode_lower(&mut buf); /// assert_eq!( /// &buf as &[_], /// b"936da01f-9abd-4d9d-80c7-02af85c822a8!!!!" as &[_] /// ); /// /// Ok(()) /// } /// ``` /// */ #[inline] pub fn encode_lower<'buf>(&self, buffer: &'buf mut [u8]) -> &'buf mut str { encode_hyphenated(self.0.as_bytes(), buffer, false) } /// Writes the [`Uuid`] as an upper-case hyphenated string to /// `buffer`, and returns the subslice of the buffer that contains the /// encoded UUID. /// /// This is slightly more efficient than using the formatting /// infrastructure as it avoids virtual calls, and may avoid /// double buffering. /// /// [`Uuid`]: ../struct.Uuid.html /// /// # Panics /// /// Panics if the buffer is not large enough: it must have length at least /// [`LENGTH`]. [`Uuid::encode_buffer`] can be used to get a /// sufficiently-large temporary buffer. /// /// [`LENGTH`]: #associatedconstant.LENGTH /// [`Uuid::encode_buffer`]: ../struct.Uuid.html#method.encode_buffer /// /// # Examples /// /// ```rust /// use uuid::Uuid; /// /// fn main() -> Result<(), uuid::Error> { /// let uuid = Uuid::parse_str("936da01f9abd4d9d80c702af85c822a8")?; /// /// // the encoded portion is returned /// assert_eq!( /// uuid.hyphenated() /// .encode_upper(&mut Uuid::encode_buffer()), /// "936DA01F-9ABD-4D9D-80C7-02AF85C822A8" /// ); /// /// // the buffer is mutated directly, and trailing contents remains /// let mut buf = [b'!'; 40]; /// uuid.hyphenated().encode_upper(&mut buf); /// assert_eq!( /// &buf as &[_], /// b"936DA01F-9ABD-4D9D-80C7-02AF85C822A8!!!!" as &[_] /// ); /// /// Ok(()) /// } /// ``` /// */ #[inline] pub fn encode_upper<'buf>(&self, buffer: &'buf mut [u8]) -> &'buf mut str { encode_hyphenated(self.0.as_bytes(), buffer, true) } /// Get a reference to the underlying [`Uuid`]. /// /// # Examples /// /// ```rust /// use uuid::Uuid; /// /// let hyphenated = Uuid::nil().hyphenated(); /// assert_eq!(*hyphenated.as_uuid(), Uuid::nil()); /// ``` pub const fn as_uuid(&self) -> &Uuid { &self.0 } /// Consumes the [`Hyphenated`], returning the underlying [`Uuid`]. /// /// # Examples /// /// ```rust /// use uuid::Uuid; /// /// let hyphenated = Uuid::nil().hyphenated(); /// assert_eq!(hyphenated.into_uuid(), Uuid::nil()); /// ``` pub const fn into_uuid(self) -> Uuid { self.0 } } impl Braced { /// The length of a braced [`Uuid`] string. /// /// [`Uuid`]: ../struct.Uuid.html pub const LENGTH: usize = 38; /// Creates a [`Braced`] from a [`Uuid`]. /// /// [`Uuid`]: ../struct.Uuid.html /// [`Braced`]: struct.Braced.html pub const fn from_uuid(uuid: Uuid) -> Self { Braced(uuid) } /// Writes the [`Uuid`] as a lower-case hyphenated string surrounded by /// braces to `buffer`, and returns the subslice of the buffer that contains /// the encoded UUID. /// /// This is slightly more efficient than using the formatting /// infrastructure as it avoids virtual calls, and may avoid /// double buffering. /// /// [`Uuid`]: ../struct.Uuid.html /// /// # Panics /// /// Panics if the buffer is not large enough: it must have length at least /// [`LENGTH`]. [`Uuid::encode_buffer`] can be used to get a /// sufficiently-large temporary buffer. /// /// [`LENGTH`]: #associatedconstant.LENGTH /// [`Uuid::encode_buffer`]: ../struct.Uuid.html#method.encode_buffer /// /// # Examples /// /// ```rust /// use uuid::Uuid; /// /// fn main() -> Result<(), uuid::Error> { /// let uuid = Uuid::parse_str("936DA01f9abd4d9d80c702af85c822a8")?; /// /// // the encoded portion is returned /// assert_eq!( /// uuid.braced() /// .encode_lower(&mut Uuid::encode_buffer()), /// "{936da01f-9abd-4d9d-80c7-02af85c822a8}" /// ); /// /// // the buffer is mutated directly, and trailing contents remains /// let mut buf = [b'!'; 40]; /// uuid.braced().encode_lower(&mut buf); /// assert_eq!( /// &buf as &[_], /// b"{936da01f-9abd-4d9d-80c7-02af85c822a8}!!" as &[_] /// ); /// /// Ok(()) /// } /// ``` /// */ #[inline] pub fn encode_lower<'buf>(&self, buffer: &'buf mut [u8]) -> &'buf mut str { encode_braced(self.0.as_bytes(), buffer, false) } /// Writes the [`Uuid`] as an upper-case hyphenated string surrounded by /// braces to `buffer`, and returns the subslice of the buffer that contains /// the encoded UUID. /// /// This is slightly more efficient than using the formatting /// infrastructure as it avoids virtual calls, and may avoid /// double buffering. /// /// [`Uuid`]: ../struct.Uuid.html /// /// # Panics /// /// Panics if the buffer is not large enough: it must have length at least /// [`LENGTH`]. [`Uuid::encode_buffer`] can be used to get a /// sufficiently-large temporary buffer. /// /// [`LENGTH`]: #associatedconstant.LENGTH /// [`Uuid::encode_buffer`]: ../struct.Uuid.html#method.encode_buffer /// /// # Examples /// /// ```rust /// use uuid::Uuid; /// /// fn main() -> Result<(), uuid::Error> { /// let uuid = Uuid::parse_str("936da01f9abd4d9d80c702af85c822a8")?; /// /// // the encoded portion is returned /// assert_eq!( /// uuid.braced() /// .encode_upper(&mut Uuid::encode_buffer()), /// "{936DA01F-9ABD-4D9D-80C7-02AF85C822A8}" /// ); /// /// // the buffer is mutated directly, and trailing contents remains /// let mut buf = [b'!'; 40]; /// uuid.braced().encode_upper(&mut buf); /// assert_eq!( /// &buf as &[_], /// b"{936DA01F-9ABD-4D9D-80C7-02AF85C822A8}!!" as &[_] /// ); /// /// Ok(()) /// } /// ``` /// */ #[inline] pub fn encode_upper<'buf>(&self, buffer: &'buf mut [u8]) -> &'buf mut str { encode_braced(self.0.as_bytes(), buffer, true) } /// Get a reference to the underlying [`Uuid`]. /// /// # Examples /// /// ```rust /// use uuid::Uuid; /// /// let braced = Uuid::nil().braced(); /// assert_eq!(*braced.as_uuid(), Uuid::nil()); /// ``` pub const fn as_uuid(&self) -> &Uuid { &self.0 } /// Consumes the [`Braced`], returning the underlying [`Uuid`]. /// /// # Examples /// /// ```rust /// use uuid::Uuid; /// /// let braced = Uuid::nil().braced(); /// assert_eq!(braced.into_uuid(), Uuid::nil()); /// ``` pub const fn into_uuid(self) -> Uuid { self.0 } } impl Simple { /// The length of a simple [`Uuid`] string. /// /// [`Uuid`]: ../struct.Uuid.html pub const LENGTH: usize = 32; /// Creates a [`Simple`] from a [`Uuid`]. /// /// [`Uuid`]: ../struct.Uuid.html /// [`Simple`]: struct.Simple.html pub const fn from_uuid(uuid: Uuid) -> Self { Simple(uuid) } /// Writes the [`Uuid`] as a lower-case simple string to `buffer`, /// and returns the subslice of the buffer that contains the encoded UUID. /// /// This is slightly more efficient than using the formatting /// infrastructure as it avoids virtual calls, and may avoid /// double buffering. /// /// [`Uuid`]: ../struct.Uuid.html /// /// # Panics /// /// Panics if the buffer is not large enough: it must have length at least /// [`LENGTH`]. [`Uuid::encode_buffer`] can be used to get a /// sufficiently-large temporary buffer. /// /// [`LENGTH`]: #associatedconstant.LENGTH /// [`Uuid::encode_buffer`]: ../struct.Uuid.html#method.encode_buffer /// /// # Examples /// /// ```rust /// use uuid::Uuid; /// /// fn main() -> Result<(), uuid::Error> { /// let uuid = Uuid::parse_str("936DA01f9abd4d9d80c702af85c822a8")?; /// /// // the encoded portion is returned /// assert_eq!( /// uuid.simple().encode_lower(&mut Uuid::encode_buffer()), /// "936da01f9abd4d9d80c702af85c822a8" /// ); /// /// // the buffer is mutated directly, and trailing contents remains /// let mut buf = [b'!'; 36]; /// assert_eq!( /// uuid.simple().encode_lower(&mut buf), /// "936da01f9abd4d9d80c702af85c822a8" /// ); /// assert_eq!( /// &buf as &[_], /// b"936da01f9abd4d9d80c702af85c822a8!!!!" as &[_] /// ); /// /// Ok(()) /// } /// ``` /// */ #[inline] pub fn encode_lower<'buf>(&self, buffer: &'buf mut [u8]) -> &'buf mut str { encode_simple(self.0.as_bytes(), buffer, false) } /// Writes the [`Uuid`] as an upper-case simple string to `buffer`, /// and returns the subslice of the buffer that contains the encoded UUID. /// /// [`Uuid`]: ../struct.Uuid.html /// /// # Panics /// /// Panics if the buffer is not large enough: it must have length at least /// [`LENGTH`]. [`Uuid::encode_buffer`] can be used to get a /// sufficiently-large temporary buffer. /// /// [`LENGTH`]: #associatedconstant.LENGTH /// [`Uuid::encode_buffer`]: ../struct.Uuid.html#method.encode_buffer /// /// # Examples /// /// ```rust /// use uuid::Uuid; /// /// fn main() -> Result<(), uuid::Error> { /// let uuid = Uuid::parse_str("936da01f9abd4d9d80c702af85c822a8")?; /// /// // the encoded portion is returned /// assert_eq!( /// uuid.simple().encode_upper(&mut Uuid::encode_buffer()), /// "936DA01F9ABD4D9D80C702AF85C822A8" /// ); /// /// // the buffer is mutated directly, and trailing contents remains /// let mut buf = [b'!'; 36]; /// assert_eq!( /// uuid.simple().encode_upper(&mut buf), /// "936DA01F9ABD4D9D80C702AF85C822A8" /// ); /// assert_eq!( /// &buf as &[_], /// b"936DA01F9ABD4D9D80C702AF85C822A8!!!!" as &[_] /// ); /// /// Ok(()) /// } /// ``` /// */ #[inline] pub fn encode_upper<'buf>(&self, buffer: &'buf mut [u8]) -> &'buf mut str { encode_simple(self.0.as_bytes(), buffer, true) } /// Get a reference to the underlying [`Uuid`]. /// /// # Examples /// /// ```rust /// use uuid::Uuid; /// /// let simple = Uuid::nil().simple(); /// assert_eq!(*simple.as_uuid(), Uuid::nil()); /// ``` pub const fn as_uuid(&self) -> &Uuid { &self.0 } /// Consumes the [`Simple`], returning the underlying [`Uuid`]. /// /// # Examples /// /// ```rust /// use uuid::Uuid; /// /// let simple = Uuid::nil().simple(); /// assert_eq!(simple.into_uuid(), Uuid::nil()); /// ``` pub const fn into_uuid(self) -> Uuid { self.0 } } impl Urn { /// The length of a URN [`Uuid`] string. /// /// [`Uuid`]: ../struct.Uuid.html pub const LENGTH: usize = 45; /// Creates a [`Urn`] from a [`Uuid`]. /// /// [`Uuid`]: ../struct.Uuid.html /// [`Urn`]: struct.Urn.html pub const fn from_uuid(uuid: Uuid) -> Self { Urn(uuid) } /// Writes the [`Uuid`] as a lower-case URN string to /// `buffer`, and returns the subslice of the buffer that contains the /// encoded UUID. /// /// This is slightly more efficient than using the formatting /// infrastructure as it avoids virtual calls, and may avoid /// double buffering. /// /// [`Uuid`]: ../struct.Uuid.html /// /// # Panics /// /// Panics if the buffer is not large enough: it must have length at least /// [`LENGTH`]. [`Uuid::encode_buffer`] can be used to get a /// sufficiently-large temporary buffer. /// /// [`LENGTH`]: #associatedconstant.LENGTH /// [`Uuid::encode_buffer`]: ../struct.Uuid.html#method.encode_buffer /// /// # Examples /// /// ```rust /// use uuid::Uuid; /// /// fn main() -> Result<(), uuid::Error> { /// let uuid = Uuid::parse_str("936DA01f9abd4d9d80c702af85c822a8")?; /// /// // the encoded portion is returned /// assert_eq!( /// uuid.urn().encode_lower(&mut Uuid::encode_buffer()), /// "urn:uuid:936da01f-9abd-4d9d-80c7-02af85c822a8" /// ); /// /// // the buffer is mutated directly, and trailing contents remains /// let mut buf = [b'!'; 49]; /// uuid.urn().encode_lower(&mut buf); /// assert_eq!( /// uuid.urn().encode_lower(&mut buf), /// "urn:uuid:936da01f-9abd-4d9d-80c7-02af85c822a8" /// ); /// assert_eq!( /// &buf as &[_], /// b"urn:uuid:936da01f-9abd-4d9d-80c7-02af85c822a8!!!!" as &[_] /// ); /// /// Ok(()) /// } /// ``` /// */ #[inline] pub fn encode_lower<'buf>(&self, buffer: &'buf mut [u8]) -> &'buf mut str { encode_urn(self.0.as_bytes(), buffer, false) } /// Writes the [`Uuid`] as an upper-case URN string to /// `buffer`, and returns the subslice of the buffer that contains the /// encoded UUID. /// /// This is slightly more efficient than using the formatting /// infrastructure as it avoids virtual calls, and may avoid /// double buffering. /// /// [`Uuid`]: ../struct.Uuid.html /// /// # Panics /// /// Panics if the buffer is not large enough: it must have length at least /// [`LENGTH`]. [`Uuid::encode_buffer`] can be used to get a /// sufficiently-large temporary buffer. /// /// [`LENGTH`]: #associatedconstant.LENGTH /// [`Uuid::encode_buffer`]: ../struct.Uuid.html#method.encode_buffer /// /// # Examples /// /// ```rust /// use uuid::Uuid; /// /// fn main() -> Result<(), uuid::Error> { /// let uuid = Uuid::parse_str("936da01f9abd4d9d80c702af85c822a8")?; /// /// // the encoded portion is returned /// assert_eq!( /// uuid.urn().encode_upper(&mut Uuid::encode_buffer()), /// "urn:uuid:936DA01F-9ABD-4D9D-80C7-02AF85C822A8" /// ); /// /// // the buffer is mutated directly, and trailing contents remains /// let mut buf = [b'!'; 49]; /// assert_eq!( /// uuid.urn().encode_upper(&mut buf), /// "urn:uuid:936DA01F-9ABD-4D9D-80C7-02AF85C822A8" /// ); /// assert_eq!( /// &buf as &[_], /// b"urn:uuid:936DA01F-9ABD-4D9D-80C7-02AF85C822A8!!!!" as &[_] /// ); /// /// Ok(()) /// } /// ``` /// */ #[inline] pub fn encode_upper<'buf>(&self, buffer: &'buf mut [u8]) -> &'buf mut str { encode_urn(self.0.as_bytes(), buffer, true) } /// Get a reference to the underlying [`Uuid`]. /// /// # Examples /// /// ```rust /// use uuid::Uuid; /// /// let urn = Uuid::nil().urn(); /// assert_eq!(*urn.as_uuid(), Uuid::nil()); /// ``` pub const fn as_uuid(&self) -> &Uuid { &self.0 } /// Consumes the [`Urn`], returning the underlying [`Uuid`]. /// /// # Examples /// /// ```rust /// use uuid::Uuid; /// /// let urn = Uuid::nil().urn(); /// assert_eq!(urn.into_uuid(), Uuid::nil()); /// ``` pub const fn into_uuid(self) -> Uuid { self.0 } } macro_rules! impl_fmt_traits { ($($T:ident<$($a:lifetime),*>),+) => {$( impl<$($a),*> fmt::Display for $T<$($a),*> { #[inline] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fmt::LowerHex::fmt(self, f) } } impl<$($a),*> fmt::LowerHex for $T<$($a),*> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.write_str(self.encode_lower(&mut [0; Self::LENGTH])) } } impl<$($a),*> fmt::UpperHex for $T<$($a),*> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.write_str(self.encode_upper(&mut [0; Self::LENGTH])) } } impl_fmt_from!($T<$($a),*>); )+} } macro_rules! impl_fmt_from { ($T:ident<>) => { impl From for $T { #[inline] fn from(f: Uuid) -> Self { $T(f) } } impl From<$T> for Uuid { #[inline] fn from(f: $T) -> Self { f.into_uuid() } } impl AsRef for $T { #[inline] fn as_ref(&self) -> &Uuid { &self.0 } } impl Borrow for $T { #[inline] fn borrow(&self) -> &Uuid { &self.0 } } }; ($T:ident<$a:lifetime>) => { impl<$a> From<&$a Uuid> for $T<$a> { #[inline] fn from(f: &$a Uuid) -> Self { $T::from_uuid_ref(f) } } impl<$a> From<$T<$a>> for &$a Uuid { #[inline] fn from(f: $T<$a>) -> &$a Uuid { f.0 } } impl<$a> AsRef for $T<$a> { #[inline] fn as_ref(&self) -> &Uuid { self.0 } } impl<$a> Borrow for $T<$a> { #[inline] fn borrow(&self) -> &Uuid { self.0 } } }; } impl_fmt_traits! { Hyphenated<>, Simple<>, Urn<>, Braced<> } #[cfg(test)] mod tests { use super::*; #[test] fn hyphenated_trailing() { let mut buf = [b'x'; 100]; let len = Uuid::nil().hyphenated().encode_lower(&mut buf).len(); assert_eq!(len, super::Hyphenated::LENGTH); assert!(buf[len..].iter().all(|x| *x == b'x')); } #[test] fn hyphenated_ref_trailing() { let mut buf = [b'x'; 100]; let len = Uuid::nil().as_hyphenated().encode_lower(&mut buf).len(); assert_eq!(len, super::Hyphenated::LENGTH); assert!(buf[len..].iter().all(|x| *x == b'x')); } #[test] fn simple_trailing() { let mut buf = [b'x'; 100]; let len = Uuid::nil().simple().encode_lower(&mut buf).len(); assert_eq!(len, super::Simple::LENGTH); assert!(buf[len..].iter().all(|x| *x == b'x')); } #[test] fn simple_ref_trailing() { let mut buf = [b'x'; 100]; let len = Uuid::nil().as_simple().encode_lower(&mut buf).len(); assert_eq!(len, super::Simple::LENGTH); assert!(buf[len..].iter().all(|x| *x == b'x')); } #[test] fn urn_trailing() { let mut buf = [b'x'; 100]; let len = Uuid::nil().urn().encode_lower(&mut buf).len(); assert_eq!(len, super::Urn::LENGTH); assert!(buf[len..].iter().all(|x| *x == b'x')); } #[test] fn urn_ref_trailing() { let mut buf = [b'x'; 100]; let len = Uuid::nil().as_urn().encode_lower(&mut buf).len(); assert_eq!(len, super::Urn::LENGTH); assert!(buf[len..].iter().all(|x| *x == b'x')); } #[test] fn braced_trailing() { let mut buf = [b'x'; 100]; let len = Uuid::nil().braced().encode_lower(&mut buf).len(); assert_eq!(len, super::Braced::LENGTH); assert!(buf[len..].iter().all(|x| *x == b'x')); } #[test] fn braced_ref_trailing() { let mut buf = [b'x'; 100]; let len = Uuid::nil().as_braced().encode_lower(&mut buf).len(); assert_eq!(len, super::Braced::LENGTH); assert!(buf[len..].iter().all(|x| *x == b'x')); } #[test] #[should_panic] fn hyphenated_too_small() { Uuid::nil().hyphenated().encode_lower(&mut [0; 35]); } #[test] #[should_panic] fn simple_too_small() { Uuid::nil().simple().encode_lower(&mut [0; 31]); } #[test] #[should_panic] fn urn_too_small() { Uuid::nil().urn().encode_lower(&mut [0; 44]); } #[test] #[should_panic] fn braced_too_small() { Uuid::nil().braced().encode_lower(&mut [0; 37]); } #[test] fn hyphenated_to_inner() { let hyphenated = Uuid::nil().hyphenated(); assert_eq!(Uuid::from(hyphenated), Uuid::nil()); } #[test] fn simple_to_inner() { let simple = Uuid::nil().simple(); assert_eq!(Uuid::from(simple), Uuid::nil()); } #[test] fn urn_to_inner() { let urn = Uuid::nil().urn(); assert_eq!(Uuid::from(urn), Uuid::nil()); } #[test] fn braced_to_inner() { let braced = Uuid::nil().braced(); assert_eq!(Uuid::from(braced), Uuid::nil()); } } uuid-1.10.0/src/lib.rs000064400000000000000000001516001046102023000125570ustar 00000000000000// Copyright 2013-2014 The Rust Project Developers. // Copyright 2018 The Uuid Project Developers. // // See the COPYRIGHT file at the top-level directory of this distribution. // // Licensed under the Apache License, Version 2.0 or the MIT license // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. //! Generate and parse universally unique identifiers (UUIDs). //! //! Here's an example of a UUID: //! //! ```text //! 67e55044-10b1-426f-9247-bb680e5fe0c8 //! ``` //! //! A UUID is a unique 128-bit value, stored as 16 octets, and regularly //! formatted as a hex string in five groups. UUIDs are used to assign unique //! identifiers to entities without requiring a central allocating authority. //! //! They are particularly useful in distributed systems, though can be used in //! disparate areas, such as databases and network protocols. Typically a UUID //! is displayed in a readable string form as a sequence of hexadecimal digits, //! separated into groups by hyphens. //! //! The uniqueness property is not strictly guaranteed, however for all //! practical purposes, it can be assumed that an unintentional collision would //! be extremely unlikely. //! //! UUIDs have a number of standardized encodings that are specified in [RFC 9562](https://www.ietf.org/rfc/rfc9562.html). //! //! # Getting started //! //! Add the following to your `Cargo.toml`: //! //! ```toml //! [dependencies.uuid] //! version = "1.10.0" //! features = [ //! "v4", # Lets you generate random UUIDs //! "fast-rng", # Use a faster (but still sufficiently random) RNG //! "macro-diagnostics", # Enable better diagnostics for compile-time UUIDs //! ] //! ``` //! //! When you want a UUID, you can generate one: //! //! ``` //! # fn main() { //! # #[cfg(feature = "v4")] //! # { //! use uuid::Uuid; //! //! let id = Uuid::new_v4(); //! # } //! # } //! ``` //! //! If you have a UUID value, you can use its string literal form inline: //! //! ``` //! use uuid::{uuid, Uuid}; //! //! const ID: Uuid = uuid!("67e55044-10b1-426f-9247-bb680e5fe0c8"); //! ``` //! //! # Working with different UUID versions //! //! This library supports all standardized methods for generating UUIDs through individual Cargo features. //! //! By default, this crate depends on nothing but the Rust standard library and can parse and format //! UUIDs, but cannot generate them. Depending on the kind of UUID you'd like to work with, there //! are Cargo features that enable generating them: //! //! * `v1` - Version 1 UUIDs using a timestamp and monotonic counter. //! * `v3` - Version 3 UUIDs based on the MD5 hash of some data. //! * `v4` - Version 4 UUIDs with random data. //! * `v5` - Version 5 UUIDs based on the SHA1 hash of some data. //! * `v6` - Version 6 UUIDs using a timestamp and monotonic counter. //! * `v7` - Version 7 UUIDs using a Unix timestamp. //! * `v8` - Version 8 UUIDs using user-defined data. //! //! This library also includes a [`Builder`] type that can be used to help construct UUIDs of any //! version without any additional dependencies or features. It's a lower-level API than [`Uuid`] //! that can be used when you need control over implicit requirements on things like a source //! of randomness. //! //! ## Which UUID version should I use? //! //! If you just want to generate unique identifiers then consider version 4 (`v4`) UUIDs. If you want //! to use UUIDs as database keys or need to sort them then consider version 7 (`v7`) UUIDs. //! Other versions should generally be avoided unless there's an existing need for them. //! //! Some UUID versions supersede others. Prefer version 6 over version 1 and version 5 over version 3. //! //! # Other features //! //! Other crate features can also be useful beyond the version support: //! //! * `macro-diagnostics` - enhances the diagnostics of `uuid!` macro. //! * `serde` - adds the ability to serialize and deserialize a UUID using //! `serde`. //! * `borsh` - adds the ability to serialize and deserialize a UUID using //! `borsh`. //! * `arbitrary` - adds an `Arbitrary` trait implementation to `Uuid` for //! fuzzing. //! * `fast-rng` - uses a faster algorithm for generating random UUIDs. //! This feature requires more dependencies to compile, but is just as suitable for //! UUIDs as the default algorithm. //! * `bytemuck` - adds a `Pod` trait implementation to `Uuid` for byte manipulation //! //! # Unstable features //! //! Some features are unstable. They may be incomplete or depend on other //! unstable libraries. These include: //! //! * `zerocopy` - adds support for zero-copy deserialization using the //! `zerocopy` library. //! //! Unstable features may break between minor releases. //! //! To allow unstable features, you'll need to enable the Cargo feature as //! normal, but also pass an additional flag through your environment to opt-in //! to unstable `uuid` features: //! //! ```text //! RUSTFLAGS="--cfg uuid_unstable" //! ``` //! //! # Building for other targets //! //! ## WebAssembly //! //! For WebAssembly, enable the `js` feature: //! //! ```toml //! [dependencies.uuid] //! version = "1.10.0" //! features = [ //! "v4", //! "v7", //! "js", //! ] //! ``` //! //! ## Embedded //! //! For embedded targets without the standard library, you'll need to //! disable default features when building `uuid`: //! //! ```toml //! [dependencies.uuid] //! version = "1.10.0" //! default-features = false //! ``` //! //! Some additional features are supported in no-std environments: //! //! * `v1`, `v3`, `v5`, `v6`, and `v8`. //! * `serde`. //! //! If you need to use `v4` or `v7` in a no-std environment, you'll need to //! follow [`getrandom`'s docs] on configuring a source of randomness //! on currently unsupported targets. Alternatively, you can produce //! random bytes yourself and then pass them to [`Builder::from_random_bytes`] //! without enabling the `v4` or `v7` features. //! //! # Examples //! //! Parse a UUID given in the simple format and print it as a URN: //! //! ``` //! # use uuid::Uuid; //! # fn main() -> Result<(), uuid::Error> { //! let my_uuid = Uuid::parse_str("a1a2a3a4b1b2c1c2d1d2d3d4d5d6d7d8")?; //! //! println!("{}", my_uuid.urn()); //! # Ok(()) //! # } //! ``` //! //! Generate a random UUID and print it out in hexadecimal form: //! //! ``` //! // Note that this requires the `v4` feature to be enabled. //! # use uuid::Uuid; //! # fn main() { //! # #[cfg(feature = "v4")] { //! let my_uuid = Uuid::new_v4(); //! //! println!("{}", my_uuid); //! # } //! # } //! ``` //! //! # References //! //! * [Wikipedia: Universally Unique Identifier](http://en.wikipedia.org/wiki/Universally_unique_identifier) //! * [RFC 9562: Universally Unique IDentifiers (UUID)](https://www.ietf.org/rfc/rfc9562.html). //! //! [`wasm-bindgen`]: https://crates.io/crates/wasm-bindgen //! [`cargo-web`]: https://crates.io/crates/cargo-web //! [`getrandom`'s docs]: https://docs.rs/getrandom #![no_std] #![deny(missing_debug_implementations, missing_docs)] #![allow(clippy::mixed_attributes_style)] #![doc( html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", html_favicon_url = "https://www.rust-lang.org/favicon.ico", html_root_url = "https://docs.rs/uuid/1.10.0" )] #[cfg(any(feature = "std", test))] #[macro_use] extern crate std; #[cfg(all(not(feature = "std"), not(test)))] #[macro_use] extern crate core as std; #[cfg(all(uuid_unstable, feature = "zerocopy"))] use zerocopy::{AsBytes, FromBytes, FromZeroes, Unaligned}; mod builder; mod error; mod parser; pub mod fmt; pub mod timestamp; pub use timestamp::{context::NoContext, ClockSequence, Timestamp}; #[cfg(any(feature = "v1", feature = "v6"))] pub use timestamp::context::Context; #[cfg(feature = "v7")] pub use timestamp::context::ContextV7; #[cfg(feature = "v1")] #[doc(hidden)] // Soft-deprecated (Rust doesn't support deprecating re-exports) // Use `Context` from the crate root instead pub mod v1; #[cfg(feature = "v3")] mod v3; #[cfg(feature = "v4")] mod v4; #[cfg(feature = "v5")] mod v5; #[cfg(feature = "v6")] mod v6; #[cfg(feature = "v7")] mod v7; #[cfg(feature = "v8")] mod v8; #[cfg(feature = "md5")] mod md5; #[cfg(feature = "rng")] mod rng; #[cfg(feature = "sha1")] mod sha1; mod external; #[macro_use] mod macros; #[doc(hidden)] #[cfg(feature = "macro-diagnostics")] pub extern crate uuid_macro_internal; #[doc(hidden)] pub mod __macro_support { pub use crate::std::result::Result::{Err, Ok}; } use crate::std::convert; pub use crate::{builder::Builder, error::Error}; /// A 128-bit (16 byte) buffer containing the UUID. /// /// # ABI /// /// The `Bytes` type is always guaranteed to be have the same ABI as [`Uuid`]. pub type Bytes = [u8; 16]; /// The version of the UUID, denoting the generating algorithm. /// /// # References /// /// * [Version Field in RFC 9562](https://www.ietf.org/rfc/rfc9562.html#section-4.2) #[derive(Clone, Copy, Debug, PartialEq)] #[non_exhaustive] #[repr(u8)] pub enum Version { /// The "nil" (all zeros) UUID. Nil = 0u8, /// Version 1: Timestamp and node ID. Mac = 1, /// Version 2: DCE Security. Dce = 2, /// Version 3: MD5 hash. Md5 = 3, /// Version 4: Random. Random = 4, /// Version 5: SHA-1 hash. Sha1 = 5, /// Version 6: Sortable Timestamp and node ID. SortMac = 6, /// Version 7: Timestamp and random. SortRand = 7, /// Version 8: Custom. Custom = 8, /// The "max" (all ones) UUID. Max = 0xff, } /// The reserved variants of UUIDs. /// /// # References /// /// * [Variant Field in RFC 9562](https://www.ietf.org/rfc/rfc9562.html#section-4.1) #[derive(Clone, Copy, Debug, PartialEq)] #[non_exhaustive] #[repr(u8)] pub enum Variant { /// Reserved by the NCS for backward compatibility. NCS = 0u8, /// As described in the RFC 9562 Specification (default). /// (for backward compatibility it is not yet renamed) RFC4122, /// Reserved by Microsoft for backward compatibility. Microsoft, /// Reserved for future expansion. Future, } /// A Universally Unique Identifier (UUID). /// /// # Examples /// /// Parse a UUID given in the simple format and print it as a urn: /// /// ``` /// # use uuid::Uuid; /// # fn main() -> Result<(), uuid::Error> { /// let my_uuid = Uuid::parse_str("a1a2a3a4b1b2c1c2d1d2d3d4d5d6d7d8")?; /// /// println!("{}", my_uuid.urn()); /// # Ok(()) /// # } /// ``` /// /// Create a new random (V4) UUID and print it out in hexadecimal form: /// /// ``` /// // Note that this requires the `v4` feature enabled in the uuid crate. /// # use uuid::Uuid; /// # fn main() { /// # #[cfg(feature = "v4")] { /// let my_uuid = Uuid::new_v4(); /// /// println!("{}", my_uuid); /// # } /// # } /// ``` /// /// # Formatting /// /// A UUID can be formatted in one of a few ways: /// /// * [`simple`](#method.simple): `a1a2a3a4b1b2c1c2d1d2d3d4d5d6d7d8`. /// * [`hyphenated`](#method.hyphenated): /// `a1a2a3a4-b1b2-c1c2-d1d2-d3d4d5d6d7d8`. /// * [`urn`](#method.urn): `urn:uuid:A1A2A3A4-B1B2-C1C2-D1D2-D3D4D5D6D7D8`. /// * [`braced`](#method.braced): `{a1a2a3a4-b1b2-c1c2-d1d2-d3d4d5d6d7d8}`. /// /// The default representation when formatting a UUID with `Display` is /// hyphenated: /// /// ``` /// # use uuid::Uuid; /// # fn main() -> Result<(), uuid::Error> { /// let my_uuid = Uuid::parse_str("a1a2a3a4b1b2c1c2d1d2d3d4d5d6d7d8")?; /// /// assert_eq!( /// "a1a2a3a4-b1b2-c1c2-d1d2-d3d4d5d6d7d8", /// my_uuid.to_string(), /// ); /// # Ok(()) /// # } /// ``` /// /// Other formats can be specified using adapter methods on the UUID: /// /// ``` /// # use uuid::Uuid; /// # fn main() -> Result<(), uuid::Error> { /// let my_uuid = Uuid::parse_str("a1a2a3a4b1b2c1c2d1d2d3d4d5d6d7d8")?; /// /// assert_eq!( /// "urn:uuid:a1a2a3a4-b1b2-c1c2-d1d2-d3d4d5d6d7d8", /// my_uuid.urn().to_string(), /// ); /// # Ok(()) /// # } /// ``` /// /// # Endianness /// /// The specification for UUIDs encodes the integer fields that make up the /// value in big-endian order. This crate assumes integer inputs are already in /// the correct order by default, regardless of the endianness of the /// environment. Most methods that accept integers have a `_le` variant (such as /// `from_fields_le`) that assumes any integer values will need to have their /// bytes flipped, regardless of the endianness of the environment. /// /// Most users won't need to worry about endianness unless they need to operate /// on individual fields (such as when converting between Microsoft GUIDs). The /// important things to remember are: /// /// - The endianness is in terms of the fields of the UUID, not the environment. /// - The endianness is assumed to be big-endian when there's no `_le` suffix /// somewhere. /// - Byte-flipping in `_le` methods applies to each integer. /// - Endianness roundtrips, so if you create a UUID with `from_fields_le` /// you'll get the same values back out with `to_fields_le`. /// /// # ABI /// /// The `Uuid` type is always guaranteed to be have the same ABI as [`Bytes`]. #[derive(Clone, Copy, Eq, Hash, Ord, PartialEq, PartialOrd)] #[cfg_attr( all(uuid_unstable, feature = "zerocopy"), derive(AsBytes, FromBytes, FromZeroes, Unaligned) )] #[cfg_attr( feature = "borsh", derive(borsh_derive::BorshDeserialize, borsh_derive::BorshSerialize) )] #[repr(transparent)] #[cfg_attr( feature = "bytemuck", derive(bytemuck::Zeroable, bytemuck::Pod, bytemuck::TransparentWrapper) )] pub struct Uuid(Bytes); impl Uuid { /// UUID namespace for Domain Name System (DNS). pub const NAMESPACE_DNS: Self = Uuid([ 0x6b, 0xa7, 0xb8, 0x10, 0x9d, 0xad, 0x11, 0xd1, 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8, ]); /// UUID namespace for ISO Object Identifiers (OIDs). pub const NAMESPACE_OID: Self = Uuid([ 0x6b, 0xa7, 0xb8, 0x12, 0x9d, 0xad, 0x11, 0xd1, 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8, ]); /// UUID namespace for Uniform Resource Locators (URLs). pub const NAMESPACE_URL: Self = Uuid([ 0x6b, 0xa7, 0xb8, 0x11, 0x9d, 0xad, 0x11, 0xd1, 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8, ]); /// UUID namespace for X.500 Distinguished Names (DNs). pub const NAMESPACE_X500: Self = Uuid([ 0x6b, 0xa7, 0xb8, 0x14, 0x9d, 0xad, 0x11, 0xd1, 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8, ]); /// Returns the variant of the UUID structure. /// /// This determines the interpretation of the structure of the UUID. /// This method simply reads the value of the variant byte. It doesn't /// validate the rest of the UUID as conforming to that variant. /// /// # Examples /// /// Basic usage: /// /// ``` /// # use uuid::{Uuid, Variant}; /// # fn main() -> Result<(), uuid::Error> { /// let my_uuid = Uuid::parse_str("02f09a3f-1624-3b1d-8409-44eff7708208")?; /// /// assert_eq!(Variant::RFC4122, my_uuid.get_variant()); /// # Ok(()) /// # } /// ``` /// /// # References /// /// * [Variant Field in RFC 9562](https://www.ietf.org/rfc/rfc9562.html#section-4.1) pub const fn get_variant(&self) -> Variant { match self.as_bytes()[8] { x if x & 0x80 == 0x00 => Variant::NCS, x if x & 0xc0 == 0x80 => Variant::RFC4122, x if x & 0xe0 == 0xc0 => Variant::Microsoft, x if x & 0xe0 == 0xe0 => Variant::Future, // The above match arms are actually exhaustive // We just return `Future` here because we can't // use `unreachable!()` in a `const fn` _ => Variant::Future, } } /// Returns the version number of the UUID. /// /// This represents the algorithm used to generate the value. /// This method is the future-proof alternative to [`Uuid::get_version`]. /// /// # Examples /// /// Basic usage: /// /// ``` /// # use uuid::Uuid; /// # fn main() -> Result<(), uuid::Error> { /// let my_uuid = Uuid::parse_str("02f09a3f-1624-3b1d-8409-44eff7708208")?; /// /// assert_eq!(3, my_uuid.get_version_num()); /// # Ok(()) /// # } /// ``` /// /// # References /// /// * [Version Field in RFC 9562](https://www.ietf.org/rfc/rfc9562.html#section-4.2) pub const fn get_version_num(&self) -> usize { (self.as_bytes()[6] >> 4) as usize } /// Returns the version of the UUID. /// /// This represents the algorithm used to generate the value. /// If the version field doesn't contain a recognized version then `None` /// is returned. If you're trying to read the version for a future extension /// you can also use [`Uuid::get_version_num`] to unconditionally return a /// number. Future extensions may start to return `Some` once they're /// standardized and supported. /// /// # Examples /// /// Basic usage: /// /// ``` /// # use uuid::{Uuid, Version}; /// # fn main() -> Result<(), uuid::Error> { /// let my_uuid = Uuid::parse_str("02f09a3f-1624-3b1d-8409-44eff7708208")?; /// /// assert_eq!(Some(Version::Md5), my_uuid.get_version()); /// # Ok(()) /// # } /// ``` /// /// # References /// /// * [Version Field in RFC 9562](https://www.ietf.org/rfc/rfc9562.html#section-4.2) pub const fn get_version(&self) -> Option { match self.get_version_num() { 0 if self.is_nil() => Some(Version::Nil), 1 => Some(Version::Mac), 2 => Some(Version::Dce), 3 => Some(Version::Md5), 4 => Some(Version::Random), 5 => Some(Version::Sha1), 6 => Some(Version::SortMac), 7 => Some(Version::SortRand), 8 => Some(Version::Custom), 0xf => Some(Version::Max), _ => None, } } /// Returns the four field values of the UUID. /// /// These values can be passed to the [`Uuid::from_fields`] method to get /// the original `Uuid` back. /// /// * The first field value represents the first group of (eight) hex /// digits, taken as a big-endian `u32` value. For V1 UUIDs, this field /// represents the low 32 bits of the timestamp. /// * The second field value represents the second group of (four) hex /// digits, taken as a big-endian `u16` value. For V1 UUIDs, this field /// represents the middle 16 bits of the timestamp. /// * The third field value represents the third group of (four) hex digits, /// taken as a big-endian `u16` value. The 4 most significant bits give /// the UUID version, and for V1 UUIDs, the last 12 bits represent the /// high 12 bits of the timestamp. /// * The last field value represents the last two groups of four and twelve /// hex digits, taken in order. The first 1-3 bits of this indicate the /// UUID variant, and for V1 UUIDs, the next 13-15 bits indicate the clock /// sequence and the last 48 bits indicate the node ID. /// /// # Examples /// /// ``` /// # use uuid::Uuid; /// # fn main() -> Result<(), uuid::Error> { /// let uuid = Uuid::nil(); /// /// assert_eq!(uuid.as_fields(), (0, 0, 0, &[0u8; 8])); /// /// let uuid = Uuid::parse_str("a1a2a3a4-b1b2-c1c2-d1d2-d3d4d5d6d7d8")?; /// /// assert_eq!( /// uuid.as_fields(), /// ( /// 0xa1a2a3a4, /// 0xb1b2, /// 0xc1c2, /// &[0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8], /// ) /// ); /// # Ok(()) /// # } /// ``` pub fn as_fields(&self) -> (u32, u16, u16, &[u8; 8]) { let bytes = self.as_bytes(); let d1 = (bytes[0] as u32) << 24 | (bytes[1] as u32) << 16 | (bytes[2] as u32) << 8 | (bytes[3] as u32); let d2 = (bytes[4] as u16) << 8 | (bytes[5] as u16); let d3 = (bytes[6] as u16) << 8 | (bytes[7] as u16); let d4: &[u8; 8] = convert::TryInto::try_into(&bytes[8..16]).unwrap(); (d1, d2, d3, d4) } /// Returns the four field values of the UUID in little-endian order. /// /// The bytes in the returned integer fields will be converted from /// big-endian order. This is based on the endianness of the UUID, /// rather than the target environment so bytes will be flipped on both /// big and little endian machines. /// /// # Examples /// /// ``` /// use uuid::Uuid; /// /// # fn main() -> Result<(), uuid::Error> { /// let uuid = Uuid::parse_str("a1a2a3a4-b1b2-c1c2-d1d2-d3d4d5d6d7d8")?; /// /// assert_eq!( /// uuid.to_fields_le(), /// ( /// 0xa4a3a2a1, /// 0xb2b1, /// 0xc2c1, /// &[0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8], /// ) /// ); /// # Ok(()) /// # } /// ``` pub fn to_fields_le(&self) -> (u32, u16, u16, &[u8; 8]) { let d1 = (self.as_bytes()[0] as u32) | (self.as_bytes()[1] as u32) << 8 | (self.as_bytes()[2] as u32) << 16 | (self.as_bytes()[3] as u32) << 24; let d2 = (self.as_bytes()[4] as u16) | (self.as_bytes()[5] as u16) << 8; let d3 = (self.as_bytes()[6] as u16) | (self.as_bytes()[7] as u16) << 8; let d4: &[u8; 8] = convert::TryInto::try_into(&self.as_bytes()[8..16]).unwrap(); (d1, d2, d3, d4) } /// Returns a 128bit value containing the value. /// /// The bytes in the UUID will be packed directly into a `u128`. /// /// # Examples /// /// ``` /// # use uuid::Uuid; /// # fn main() -> Result<(), uuid::Error> { /// let uuid = Uuid::parse_str("a1a2a3a4-b1b2-c1c2-d1d2-d3d4d5d6d7d8")?; /// /// assert_eq!( /// uuid.as_u128(), /// 0xa1a2a3a4b1b2c1c2d1d2d3d4d5d6d7d8, /// ); /// # Ok(()) /// # } /// ``` pub const fn as_u128(&self) -> u128 { u128::from_be_bytes(*self.as_bytes()) } /// Returns a 128bit little-endian value containing the value. /// /// The bytes in the `u128` will be flipped to convert into big-endian /// order. This is based on the endianness of the UUID, rather than the /// target environment so bytes will be flipped on both big and little /// endian machines. /// /// Note that this will produce a different result than /// [`Uuid::to_fields_le`], because the entire UUID is reversed, rather /// than reversing the individual fields in-place. /// /// # Examples /// /// ``` /// # use uuid::Uuid; /// # fn main() -> Result<(), uuid::Error> { /// let uuid = Uuid::parse_str("a1a2a3a4-b1b2-c1c2-d1d2-d3d4d5d6d7d8")?; /// /// assert_eq!( /// uuid.to_u128_le(), /// 0xd8d7d6d5d4d3d2d1c2c1b2b1a4a3a2a1, /// ); /// # Ok(()) /// # } /// ``` pub const fn to_u128_le(&self) -> u128 { u128::from_le_bytes(*self.as_bytes()) } /// Returns two 64bit values containing the value. /// /// The bytes in the UUID will be split into two `u64`. /// The first u64 represents the 64 most significant bits, /// the second one represents the 64 least significant. /// /// # Examples /// /// ``` /// # use uuid::Uuid; /// # fn main() -> Result<(), uuid::Error> { /// let uuid = Uuid::parse_str("a1a2a3a4-b1b2-c1c2-d1d2-d3d4d5d6d7d8")?; /// assert_eq!( /// uuid.as_u64_pair(), /// (0xa1a2a3a4b1b2c1c2, 0xd1d2d3d4d5d6d7d8), /// ); /// # Ok(()) /// # } /// ``` pub const fn as_u64_pair(&self) -> (u64, u64) { let value = self.as_u128(); ((value >> 64) as u64, value as u64) } /// Returns a slice of 16 octets containing the value. /// /// This method borrows the underlying byte value of the UUID. /// /// # Examples /// /// ``` /// # use uuid::Uuid; /// let bytes1 = [ /// 0xa1, 0xa2, 0xa3, 0xa4, /// 0xb1, 0xb2, /// 0xc1, 0xc2, /// 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, /// ]; /// let uuid1 = Uuid::from_bytes_ref(&bytes1); /// /// let bytes2 = uuid1.as_bytes(); /// let uuid2 = Uuid::from_bytes_ref(bytes2); /// /// assert_eq!(uuid1, uuid2); /// /// assert!(std::ptr::eq( /// uuid2 as *const Uuid as *const u8, /// &bytes1 as *const [u8; 16] as *const u8, /// )); /// ``` #[inline] pub const fn as_bytes(&self) -> &Bytes { &self.0 } /// Consumes self and returns the underlying byte value of the UUID. /// /// # Examples /// /// ``` /// # use uuid::Uuid; /// let bytes = [ /// 0xa1, 0xa2, 0xa3, 0xa4, /// 0xb1, 0xb2, /// 0xc1, 0xc2, /// 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, /// ]; /// let uuid = Uuid::from_bytes(bytes); /// assert_eq!(bytes, uuid.into_bytes()); /// ``` #[inline] pub const fn into_bytes(self) -> Bytes { self.0 } /// Returns the bytes of the UUID in little-endian order. /// /// The bytes will be flipped to convert into little-endian order. This is /// based on the endianness of the UUID, rather than the target environment /// so bytes will be flipped on both big and little endian machines. /// /// # Examples /// /// ``` /// use uuid::Uuid; /// /// # fn main() -> Result<(), uuid::Error> { /// let uuid = Uuid::parse_str("a1a2a3a4-b1b2-c1c2-d1d2-d3d4d5d6d7d8")?; /// /// assert_eq!( /// uuid.to_bytes_le(), /// ([ /// 0xa4, 0xa3, 0xa2, 0xa1, 0xb2, 0xb1, 0xc2, 0xc1, 0xd1, 0xd2, /// 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8 /// ]) /// ); /// # Ok(()) /// # } /// ``` pub const fn to_bytes_le(&self) -> Bytes { [ self.0[3], self.0[2], self.0[1], self.0[0], self.0[5], self.0[4], self.0[7], self.0[6], self.0[8], self.0[9], self.0[10], self.0[11], self.0[12], self.0[13], self.0[14], self.0[15], ] } /// Tests if the UUID is nil (all zeros). pub const fn is_nil(&self) -> bool { self.as_u128() == u128::MIN } /// Tests if the UUID is max (all ones). pub const fn is_max(&self) -> bool { self.as_u128() == u128::MAX } /// A buffer that can be used for `encode_...` calls, that is /// guaranteed to be long enough for any of the format adapters. /// /// # Examples /// /// ``` /// # use uuid::Uuid; /// let uuid = Uuid::nil(); /// /// assert_eq!( /// uuid.simple().encode_lower(&mut Uuid::encode_buffer()), /// "00000000000000000000000000000000" /// ); /// /// assert_eq!( /// uuid.hyphenated() /// .encode_lower(&mut Uuid::encode_buffer()), /// "00000000-0000-0000-0000-000000000000" /// ); /// /// assert_eq!( /// uuid.urn().encode_lower(&mut Uuid::encode_buffer()), /// "urn:uuid:00000000-0000-0000-0000-000000000000" /// ); /// ``` pub const fn encode_buffer() -> [u8; fmt::Urn::LENGTH] { [0; fmt::Urn::LENGTH] } /// If the UUID is the correct version (v1, v6, or v7) this will return /// the timestamp in a version-agnostic [`Timestamp`]. For other versions /// this will return `None`. /// /// # Roundtripping /// /// This method is unlikely to roundtrip a timestamp in a UUID due to the way /// UUIDs encode timestamps. The timestamp returned from this method will be truncated to /// 100ns precision for version 1 and 6 UUIDs, and to millisecond precision for version 7 UUIDs. pub const fn get_timestamp(&self) -> Option { match self.get_version() { Some(Version::Mac) => { let (ticks, counter) = timestamp::decode_gregorian_timestamp(self); Some(Timestamp::from_gregorian(ticks, counter)) } Some(Version::SortMac) => { let (ticks, counter) = timestamp::decode_sorted_gregorian_timestamp(self); Some(Timestamp::from_gregorian(ticks, counter)) } Some(Version::SortRand) => { let millis = timestamp::decode_unix_timestamp_millis(self); let seconds = millis / 1000; let nanos = ((millis % 1000) * 1_000_000) as u32; Some(Timestamp::from_unix_time(seconds, nanos, 0, 0)) } _ => None, } } /// If the UUID is the correct version (v1, or v6) this will return the /// node value as a 6-byte array. For other versions this will return `None`. pub const fn get_node_id(&self) -> Option<[u8; 6]> { match self.get_version() { Some(Version::Mac) | Some(Version::SortMac) => { let mut node_id = [0; 6]; node_id[0] = self.0[10]; node_id[1] = self.0[11]; node_id[2] = self.0[12]; node_id[3] = self.0[13]; node_id[4] = self.0[14]; node_id[5] = self.0[15]; Some(node_id) } _ => None, } } } impl Default for Uuid { #[inline] fn default() -> Self { Uuid::nil() } } impl AsRef for Uuid { #[inline] fn as_ref(&self) -> &Uuid { self } } impl AsRef<[u8]> for Uuid { #[inline] fn as_ref(&self) -> &[u8] { &self.0 } } #[cfg(feature = "std")] impl From for std::vec::Vec { fn from(value: Uuid) -> Self { value.0.to_vec() } } #[cfg(feature = "std")] impl std::convert::TryFrom> for Uuid { type Error = Error; fn try_from(value: std::vec::Vec) -> Result { Uuid::from_slice(&value) } } #[cfg(feature = "serde")] pub mod serde { //! Adapters for alternative `serde` formats. //! //! This module contains adapters you can use with [`#[serde(with)]`](https://serde.rs/field-attrs.html#with) //! to change the way a [`Uuid`](../struct.Uuid.html) is serialized //! and deserialized. pub use crate::external::serde_support::{braced, compact, simple, urn}; } #[cfg(test)] mod tests { use super::*; use crate::std::string::{String, ToString}; #[cfg(all( target_arch = "wasm32", target_vendor = "unknown", target_os = "unknown" ))] use wasm_bindgen_test::*; macro_rules! check { ($buf:ident, $format:expr, $target:expr, $len:expr, $cond:expr) => { $buf.clear(); write!($buf, $format, $target).unwrap(); assert!($buf.len() == $len); assert!($buf.chars().all($cond), "{}", $buf); }; } pub const fn new() -> Uuid { Uuid::from_bytes([ 0xF9, 0x16, 0x8C, 0x5E, 0xCE, 0xB2, 0x4F, 0xAA, 0xB6, 0xBF, 0x32, 0x9B, 0xF3, 0x9F, 0xA1, 0xE4, ]) } pub const fn new2() -> Uuid { Uuid::from_bytes([ 0xF9, 0x16, 0x8C, 0x5E, 0xCE, 0xB2, 0x4F, 0xAB, 0xB6, 0xBF, 0x32, 0x9B, 0xF3, 0x9F, 0xA1, 0xE4, ]) } #[test] #[cfg_attr( all( target_arch = "wasm32", target_vendor = "unknown", target_os = "unknown" ), wasm_bindgen_test )] fn test_uuid_compare() { let uuid1 = new(); let uuid2 = new2(); assert_eq!(uuid1, uuid1); assert_eq!(uuid2, uuid2); assert_ne!(uuid1, uuid2); assert_ne!(uuid2, uuid1); } #[test] #[cfg_attr( all( target_arch = "wasm32", target_vendor = "unknown", target_os = "unknown" ), wasm_bindgen_test )] fn test_uuid_default() { let default_uuid = Uuid::default(); let nil_uuid = Uuid::nil(); assert_eq!(default_uuid, nil_uuid); } #[test] #[cfg_attr( all( target_arch = "wasm32", target_vendor = "unknown", target_os = "unknown" ), wasm_bindgen_test )] fn test_uuid_display() { use crate::std::fmt::Write; let uuid = new(); let s = uuid.to_string(); let mut buffer = String::new(); assert_eq!(s, uuid.hyphenated().to_string()); check!(buffer, "{}", uuid, 36, |c| c.is_lowercase() || c.is_digit(10) || c == '-'); } #[test] #[cfg_attr( all( target_arch = "wasm32", target_vendor = "unknown", target_os = "unknown" ), wasm_bindgen_test )] fn test_uuid_lowerhex() { use crate::std::fmt::Write; let mut buffer = String::new(); let uuid = new(); check!(buffer, "{:x}", uuid, 36, |c| c.is_lowercase() || c.is_digit(10) || c == '-'); } // noinspection RsAssertEqual #[test] #[cfg_attr( all( target_arch = "wasm32", target_vendor = "unknown", target_os = "unknown" ), wasm_bindgen_test )] fn test_uuid_operator_eq() { let uuid1 = new(); let uuid1_dup = uuid1.clone(); let uuid2 = new2(); assert!(uuid1 == uuid1); assert!(uuid1 == uuid1_dup); assert!(uuid1_dup == uuid1); assert!(uuid1 != uuid2); assert!(uuid2 != uuid1); assert!(uuid1_dup != uuid2); assert!(uuid2 != uuid1_dup); } #[test] #[cfg_attr( all( target_arch = "wasm32", target_vendor = "unknown", target_os = "unknown" ), wasm_bindgen_test )] fn test_uuid_to_string() { use crate::std::fmt::Write; let uuid = new(); let s = uuid.to_string(); let mut buffer = String::new(); assert_eq!(s.len(), 36); check!(buffer, "{}", s, 36, |c| c.is_lowercase() || c.is_digit(10) || c == '-'); } #[test] #[cfg_attr( all( target_arch = "wasm32", target_vendor = "unknown", target_os = "unknown" ), wasm_bindgen_test )] fn test_non_conforming() { let from_bytes = Uuid::from_bytes([4, 54, 67, 12, 43, 2, 2, 76, 32, 50, 87, 5, 1, 33, 43, 87]); assert_eq!(from_bytes.get_version(), None); } #[test] #[cfg_attr( all( target_arch = "wasm32", target_vendor = "unknown", target_os = "unknown" ), wasm_bindgen_test )] fn test_nil() { let nil = Uuid::nil(); let not_nil = new(); assert!(nil.is_nil()); assert!(!not_nil.is_nil()); assert_eq!(nil.get_version(), Some(Version::Nil)); assert_eq!(not_nil.get_version(), Some(Version::Random)); assert_eq!( nil, Builder::from_bytes([0; 16]) .with_version(Version::Nil) .into_uuid() ); } #[test] #[cfg_attr( all( target_arch = "wasm32", target_vendor = "unknown", target_os = "unknown" ), wasm_bindgen_test )] fn test_max() { let max = Uuid::max(); let not_max = new(); assert!(max.is_max()); assert!(!not_max.is_max()); assert_eq!(max.get_version(), Some(Version::Max)); assert_eq!(not_max.get_version(), Some(Version::Random)); assert_eq!( max, Builder::from_bytes([0xff; 16]) .with_version(Version::Max) .into_uuid() ); } #[test] #[cfg_attr( all( target_arch = "wasm32", target_vendor = "unknown", target_os = "unknown" ), wasm_bindgen_test )] fn test_predefined_namespaces() { assert_eq!( Uuid::NAMESPACE_DNS.hyphenated().to_string(), "6ba7b810-9dad-11d1-80b4-00c04fd430c8" ); assert_eq!( Uuid::NAMESPACE_URL.hyphenated().to_string(), "6ba7b811-9dad-11d1-80b4-00c04fd430c8" ); assert_eq!( Uuid::NAMESPACE_OID.hyphenated().to_string(), "6ba7b812-9dad-11d1-80b4-00c04fd430c8" ); assert_eq!( Uuid::NAMESPACE_X500.hyphenated().to_string(), "6ba7b814-9dad-11d1-80b4-00c04fd430c8" ); } #[cfg(feature = "v3")] #[test] #[cfg_attr( all( target_arch = "wasm32", target_vendor = "unknown", target_os = "unknown" ), wasm_bindgen_test )] fn test_get_version_v3() { let uuid = Uuid::new_v3(&Uuid::NAMESPACE_DNS, "rust-lang.org".as_bytes()); assert_eq!(uuid.get_version().unwrap(), Version::Md5); assert_eq!(uuid.get_version_num(), 3); } #[test] #[cfg_attr( all( target_arch = "wasm32", target_vendor = "unknown", target_os = "unknown" ), wasm_bindgen_test )] fn test_get_timestamp_unsupported_version() { let uuid = new(); assert_ne!(Version::Mac, uuid.get_version().unwrap()); assert_ne!(Version::SortMac, uuid.get_version().unwrap()); assert_ne!(Version::SortRand, uuid.get_version().unwrap()); assert!(uuid.get_timestamp().is_none()); } #[test] #[cfg_attr( all( target_arch = "wasm32", target_vendor = "unknown", target_os = "unknown" ), wasm_bindgen_test )] fn test_get_node_id_unsupported_version() { let uuid = new(); assert_ne!(Version::Mac, uuid.get_version().unwrap()); assert_ne!(Version::SortMac, uuid.get_version().unwrap()); assert!(uuid.get_node_id().is_none()); } #[test] #[cfg_attr( all( target_arch = "wasm32", target_vendor = "unknown", target_os = "unknown" ), wasm_bindgen_test )] fn test_get_variant() { let uuid1 = new(); let uuid2 = Uuid::parse_str("550e8400-e29b-41d4-a716-446655440000").unwrap(); let uuid3 = Uuid::parse_str("67e55044-10b1-426f-9247-bb680e5fe0c8").unwrap(); let uuid4 = Uuid::parse_str("936DA01F9ABD4d9dC0C702AF85C822A8").unwrap(); let uuid5 = Uuid::parse_str("F9168C5E-CEB2-4faa-D6BF-329BF39FA1E4").unwrap(); let uuid6 = Uuid::parse_str("f81d4fae-7dec-11d0-7765-00a0c91e6bf6").unwrap(); assert_eq!(uuid1.get_variant(), Variant::RFC4122); assert_eq!(uuid2.get_variant(), Variant::RFC4122); assert_eq!(uuid3.get_variant(), Variant::RFC4122); assert_eq!(uuid4.get_variant(), Variant::Microsoft); assert_eq!(uuid5.get_variant(), Variant::Microsoft); assert_eq!(uuid6.get_variant(), Variant::NCS); } #[test] #[cfg_attr( all( target_arch = "wasm32", target_vendor = "unknown", target_os = "unknown" ), wasm_bindgen_test )] fn test_to_simple_string() { let uuid1 = new(); let s = uuid1.simple().to_string(); assert_eq!(s.len(), 32); assert!(s.chars().all(|c| c.is_digit(16))); } #[test] #[cfg_attr( all( target_arch = "wasm32", target_vendor = "unknown", target_os = "unknown" ), wasm_bindgen_test )] fn test_hyphenated_string() { let uuid1 = new(); let s = uuid1.hyphenated().to_string(); assert_eq!(36, s.len()); assert!(s.chars().all(|c| c.is_digit(16) || c == '-')); } #[test] #[cfg_attr( all( target_arch = "wasm32", target_vendor = "unknown", target_os = "unknown" ), wasm_bindgen_test )] fn test_upper_lower_hex() { use std::fmt::Write; let mut buf = String::new(); let u = new(); macro_rules! check { ($buf:ident, $format:expr, $target:expr, $len:expr, $cond:expr) => { $buf.clear(); write!($buf, $format, $target).unwrap(); assert_eq!($len, buf.len()); assert!($buf.chars().all($cond), "{}", $buf); }; } check!(buf, "{:x}", u, 36, |c| c.is_lowercase() || c.is_digit(10) || c == '-'); check!(buf, "{:X}", u, 36, |c| c.is_uppercase() || c.is_digit(10) || c == '-'); check!(buf, "{:#x}", u, 36, |c| c.is_lowercase() || c.is_digit(10) || c == '-'); check!(buf, "{:#X}", u, 36, |c| c.is_uppercase() || c.is_digit(10) || c == '-'); check!(buf, "{:X}", u.hyphenated(), 36, |c| c.is_uppercase() || c.is_digit(10) || c == '-'); check!(buf, "{:X}", u.simple(), 32, |c| c.is_uppercase() || c.is_digit(10)); check!(buf, "{:#X}", u.hyphenated(), 36, |c| c.is_uppercase() || c.is_digit(10) || c == '-'); check!(buf, "{:#X}", u.simple(), 32, |c| c.is_uppercase() || c.is_digit(10)); check!(buf, "{:x}", u.hyphenated(), 36, |c| c.is_lowercase() || c.is_digit(10) || c == '-'); check!(buf, "{:x}", u.simple(), 32, |c| c.is_lowercase() || c.is_digit(10)); check!(buf, "{:#x}", u.hyphenated(), 36, |c| c.is_lowercase() || c.is_digit(10) || c == '-'); check!(buf, "{:#x}", u.simple(), 32, |c| c.is_lowercase() || c.is_digit(10)); } #[test] #[cfg_attr( all( target_arch = "wasm32", target_vendor = "unknown", target_os = "unknown" ), wasm_bindgen_test )] fn test_to_urn_string() { let uuid1 = new(); let ss = uuid1.urn().to_string(); let s = &ss[9..]; assert!(ss.starts_with("urn:uuid:")); assert_eq!(s.len(), 36); assert!(s.chars().all(|c| c.is_digit(16) || c == '-')); } #[test] #[cfg_attr( all( target_arch = "wasm32", target_vendor = "unknown", target_os = "unknown" ), wasm_bindgen_test )] fn test_to_simple_string_matching() { let uuid1 = new(); let hs = uuid1.hyphenated().to_string(); let ss = uuid1.simple().to_string(); let hsn = hs.chars().filter(|&c| c != '-').collect::(); assert_eq!(hsn, ss); } #[test] #[cfg_attr( all( target_arch = "wasm32", target_vendor = "unknown", target_os = "unknown" ), wasm_bindgen_test )] fn test_string_roundtrip() { let uuid = new(); let hs = uuid.hyphenated().to_string(); let uuid_hs = Uuid::parse_str(&hs).unwrap(); assert_eq!(uuid_hs, uuid); let ss = uuid.to_string(); let uuid_ss = Uuid::parse_str(&ss).unwrap(); assert_eq!(uuid_ss, uuid); } #[test] #[cfg_attr( all( target_arch = "wasm32", target_vendor = "unknown", target_os = "unknown" ), wasm_bindgen_test )] fn test_from_fields() { let d1: u32 = 0xa1a2a3a4; let d2: u16 = 0xb1b2; let d3: u16 = 0xc1c2; let d4 = [0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8]; let u = Uuid::from_fields(d1, d2, d3, &d4); let expected = "a1a2a3a4b1b2c1c2d1d2d3d4d5d6d7d8"; let result = u.simple().to_string(); assert_eq!(result, expected); } #[test] #[cfg_attr( all( target_arch = "wasm32", target_vendor = "unknown", target_os = "unknown" ), wasm_bindgen_test )] fn test_from_fields_le() { let d1: u32 = 0xa4a3a2a1; let d2: u16 = 0xb2b1; let d3: u16 = 0xc2c1; let d4 = [0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8]; let u = Uuid::from_fields_le(d1, d2, d3, &d4); let expected = "a1a2a3a4b1b2c1c2d1d2d3d4d5d6d7d8"; let result = u.simple().to_string(); assert_eq!(result, expected); } #[test] #[cfg_attr( all( target_arch = "wasm32", target_vendor = "unknown", target_os = "unknown" ), wasm_bindgen_test )] fn test_as_fields() { let u = new(); let (d1, d2, d3, d4) = u.as_fields(); assert_ne!(d1, 0); assert_ne!(d2, 0); assert_ne!(d3, 0); assert_eq!(d4.len(), 8); assert!(!d4.iter().all(|&b| b == 0)); } #[test] #[cfg_attr( all( target_arch = "wasm32", target_vendor = "unknown", target_os = "unknown" ), wasm_bindgen_test )] fn test_fields_roundtrip() { let d1_in: u32 = 0xa1a2a3a4; let d2_in: u16 = 0xb1b2; let d3_in: u16 = 0xc1c2; let d4_in = &[0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8]; let u = Uuid::from_fields(d1_in, d2_in, d3_in, d4_in); let (d1_out, d2_out, d3_out, d4_out) = u.as_fields(); assert_eq!(d1_in, d1_out); assert_eq!(d2_in, d2_out); assert_eq!(d3_in, d3_out); assert_eq!(d4_in, d4_out); } #[test] #[cfg_attr( all( target_arch = "wasm32", target_vendor = "unknown", target_os = "unknown" ), wasm_bindgen_test )] fn test_fields_le_roundtrip() { let d1_in: u32 = 0xa4a3a2a1; let d2_in: u16 = 0xb2b1; let d3_in: u16 = 0xc2c1; let d4_in = &[0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8]; let u = Uuid::from_fields_le(d1_in, d2_in, d3_in, d4_in); let (d1_out, d2_out, d3_out, d4_out) = u.to_fields_le(); assert_eq!(d1_in, d1_out); assert_eq!(d2_in, d2_out); assert_eq!(d3_in, d3_out); assert_eq!(d4_in, d4_out); } #[test] #[cfg_attr( all( target_arch = "wasm32", target_vendor = "unknown", target_os = "unknown" ), wasm_bindgen_test )] fn test_fields_le_are_actually_le() { let d1_in: u32 = 0xa1a2a3a4; let d2_in: u16 = 0xb1b2; let d3_in: u16 = 0xc1c2; let d4_in = &[0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8]; let u = Uuid::from_fields(d1_in, d2_in, d3_in, d4_in); let (d1_out, d2_out, d3_out, d4_out) = u.to_fields_le(); assert_eq!(d1_in, d1_out.swap_bytes()); assert_eq!(d2_in, d2_out.swap_bytes()); assert_eq!(d3_in, d3_out.swap_bytes()); assert_eq!(d4_in, d4_out); } #[test] #[cfg_attr( all( target_arch = "wasm32", target_vendor = "unknown", target_os = "unknown" ), wasm_bindgen_test )] fn test_from_u128() { let v_in: u128 = 0xa1a2a3a4b1b2c1c2d1d2d3d4d5d6d7d8; let u = Uuid::from_u128(v_in); let expected = "a1a2a3a4b1b2c1c2d1d2d3d4d5d6d7d8"; let result = u.simple().to_string(); assert_eq!(result, expected); } #[test] #[cfg_attr( all( target_arch = "wasm32", target_vendor = "unknown", target_os = "unknown" ), wasm_bindgen_test )] fn test_from_u128_le() { let v_in: u128 = 0xd8d7d6d5d4d3d2d1c2c1b2b1a4a3a2a1; let u = Uuid::from_u128_le(v_in); let expected = "a1a2a3a4b1b2c1c2d1d2d3d4d5d6d7d8"; let result = u.simple().to_string(); assert_eq!(result, expected); } #[test] #[cfg_attr( all( target_arch = "wasm32", target_vendor = "unknown", target_os = "unknown" ), wasm_bindgen_test )] fn test_from_u64_pair() { let high_in: u64 = 0xa1a2a3a4b1b2c1c2; let low_in: u64 = 0xd1d2d3d4d5d6d7d8; let u = Uuid::from_u64_pair(high_in, low_in); let expected = "a1a2a3a4b1b2c1c2d1d2d3d4d5d6d7d8"; let result = u.simple().to_string(); assert_eq!(result, expected); } #[test] #[cfg_attr( all( target_arch = "wasm32", target_vendor = "unknown", target_os = "unknown" ), wasm_bindgen_test )] fn test_u128_roundtrip() { let v_in: u128 = 0xa1a2a3a4b1b2c1c2d1d2d3d4d5d6d7d8; let u = Uuid::from_u128(v_in); let v_out = u.as_u128(); assert_eq!(v_in, v_out); } #[test] #[cfg_attr( all( target_arch = "wasm32", target_vendor = "unknown", target_os = "unknown" ), wasm_bindgen_test )] fn test_u128_le_roundtrip() { let v_in: u128 = 0xd8d7d6d5d4d3d2d1c2c1b2b1a4a3a2a1; let u = Uuid::from_u128_le(v_in); let v_out = u.to_u128_le(); assert_eq!(v_in, v_out); } #[test] #[cfg_attr( all( target_arch = "wasm32", target_vendor = "unknown", target_os = "unknown" ), wasm_bindgen_test )] fn test_u64_pair_roundtrip() { let high_in: u64 = 0xa1a2a3a4b1b2c1c2; let low_in: u64 = 0xd1d2d3d4d5d6d7d8; let u = Uuid::from_u64_pair(high_in, low_in); let (high_out, low_out) = u.as_u64_pair(); assert_eq!(high_in, high_out); assert_eq!(low_in, low_out); } #[test] #[cfg_attr( all( target_arch = "wasm32", target_vendor = "unknown", target_os = "unknown" ), wasm_bindgen_test )] fn test_u128_le_is_actually_le() { let v_in: u128 = 0xa1a2a3a4b1b2c1c2d1d2d3d4d5d6d7d8; let u = Uuid::from_u128(v_in); let v_out = u.to_u128_le(); assert_eq!(v_in, v_out.swap_bytes()); } #[test] #[cfg_attr( all( target_arch = "wasm32", target_vendor = "unknown", target_os = "unknown" ), wasm_bindgen_test )] fn test_from_slice() { let b = [ 0xa1, 0xa2, 0xa3, 0xa4, 0xb1, 0xb2, 0xc1, 0xc2, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, ]; let u = Uuid::from_slice(&b).unwrap(); let expected = "a1a2a3a4b1b2c1c2d1d2d3d4d5d6d7d8"; assert_eq!(u.simple().to_string(), expected); } #[test] #[cfg_attr( all( target_arch = "wasm32", target_vendor = "unknown", target_os = "unknown" ), wasm_bindgen_test )] fn test_from_bytes() { let b = [ 0xa1, 0xa2, 0xa3, 0xa4, 0xb1, 0xb2, 0xc1, 0xc2, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, ]; let u = Uuid::from_bytes(b); let expected = "a1a2a3a4b1b2c1c2d1d2d3d4d5d6d7d8"; assert_eq!(u.simple().to_string(), expected); } #[test] #[cfg_attr( all( target_arch = "wasm32", target_vendor = "unknown", target_os = "unknown" ), wasm_bindgen_test )] fn test_as_bytes() { let u = new(); let ub = u.as_bytes(); let ur: &[u8] = u.as_ref(); assert_eq!(ub.len(), 16); assert_eq!(ur.len(), 16); assert!(!ub.iter().all(|&b| b == 0)); assert!(!ur.iter().all(|&b| b == 0)); } #[test] #[cfg(feature = "std")] #[cfg_attr( all( target_arch = "wasm32", target_vendor = "unknown", target_os = "unknown" ), wasm_bindgen_test )] fn test_convert_vec() { use crate::std::{convert::TryInto, vec::Vec}; let u = new(); let ub: &[u8] = u.as_ref(); let v: Vec = u.into(); assert_eq!(&v, ub); let uv: Uuid = v.try_into().unwrap(); assert_eq!(uv, u); } #[test] #[cfg_attr( all( target_arch = "wasm32", target_vendor = "unknown", target_os = "unknown" ), wasm_bindgen_test )] fn test_bytes_roundtrip() { let b_in: crate::Bytes = [ 0xa1, 0xa2, 0xa3, 0xa4, 0xb1, 0xb2, 0xc1, 0xc2, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, ]; let u = Uuid::from_slice(&b_in).unwrap(); let b_out = u.as_bytes(); assert_eq!(&b_in, b_out); } #[test] #[cfg_attr( all( target_arch = "wasm32", target_vendor = "unknown", target_os = "unknown" ), wasm_bindgen_test )] fn test_bytes_le_roundtrip() { let b = [ 0xa1, 0xa2, 0xa3, 0xa4, 0xb1, 0xb2, 0xc1, 0xc2, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, ]; let u1 = Uuid::from_bytes(b); let b_le = u1.to_bytes_le(); let u2 = Uuid::from_bytes_le(b_le); assert_eq!(u1, u2); } #[test] #[cfg_attr( all( target_arch = "wasm32", target_vendor = "unknown", target_os = "unknown" ), wasm_bindgen_test )] fn test_iterbytes_impl_for_uuid() { let mut set = std::collections::HashSet::new(); let id1 = new(); let id2 = new2(); set.insert(id1.clone()); assert!(set.contains(&id1)); assert!(!set.contains(&id2)); } } uuid-1.10.0/src/macros.rs000064400000000000000000000052171046102023000132770ustar 00000000000000macro_rules! define_uuid_macro { {$(#[$doc:meta])*} => { $(#[$doc])* #[cfg(feature = "macro-diagnostics")] #[macro_export] macro_rules! uuid { ($uuid:expr) => {{ const OUTPUT: $crate::Uuid = match $crate::Uuid::try_parse($uuid) { $crate::__macro_support::Ok(u) => u, $crate::__macro_support::Err(_) => panic!("invalid UUID"), }; OUTPUT }}; ($uuid:literal) => {{ $crate::Uuid::from_bytes($crate::uuid_macro_internal::parse_lit!($uuid)) }}; } $(#[$doc])* #[cfg(not(feature = "macro-diagnostics"))] #[macro_export] macro_rules! uuid { ($uuid:expr) => {{ const OUTPUT: $crate::Uuid = match $crate::Uuid::try_parse($uuid) { $crate::__macro_support::Ok(u) => u, $crate::__macro_support::Err(_) => panic!("invalid UUID"), }; OUTPUT }}; } } } define_uuid_macro! { /// Parse [`Uuid`][uuid::Uuid]s from string literals at compile time. /// /// ## Usage /// /// This macro transforms the string literal representation of a /// [`Uuid`][uuid::Uuid] into the bytes representation, raising a compilation /// error if it cannot properly be parsed. /// /// ## Examples /// /// Setting a global constant: /// /// ``` /// # use uuid::{uuid, Uuid}; /// pub const SCHEMA_ATTR_CLASS: Uuid = uuid!("00000000-0000-0000-0000-ffff00000000"); /// pub const SCHEMA_ATTR_UUID: Uuid = uuid!("00000000-0000-0000-0000-ffff00000001"); /// pub const SCHEMA_ATTR_NAME: Uuid = uuid!("00000000-0000-0000-0000-ffff00000002"); /// ``` /// /// Defining a local variable: /// /// ``` /// # use uuid::uuid; /// let uuid = uuid!("urn:uuid:F9168C5E-CEB2-4faa-B6BF-329BF39FA1E4"); /// ``` /// Using a const variable: /// ``` /// # use uuid::uuid; /// const UUID_STR: &str = "12345678-1234-5678-1234-567812345678"; /// let UUID = uuid!(UUID_STR); /// ``` /// /// ## Compilation Failures /// /// Invalid UUIDs are rejected: /// /// ```compile_fail /// # use uuid::uuid; /// let uuid = uuid!("F9168C5E-ZEB2-4FAA-B6BF-329BF39FA1E4"); /// ``` /// /// Enable the feature `macro-diagnostics` to see the error messages below. /// /// Provides the following compilation error: /// /// ```txt /// error: invalid character: expected an optional prefix of `urn:uuid:` followed by [0-9a-fA-F-], found Z at 9 /// | /// | let id = uuid!("F9168C5E-ZEB2-4FAA-B6BF-329BF39FA1E4"); /// | ^ /// ``` /// /// [uuid::Uuid]: https://docs.rs/uuid/*/uuid/struct.Uuid.html } uuid-1.10.0/src/md5.rs000064400000000000000000000004351046102023000124750ustar 00000000000000#[cfg(feature = "v3")] pub(crate) fn hash(ns: &[u8], src: &[u8]) -> [u8; 16] { use md5::{Digest, Md5}; let mut hasher = Md5::new(); hasher.update(ns); hasher.update(src); let mut bytes = [0; 16]; bytes.copy_from_slice(&hasher.finalize()[..16]); bytes } uuid-1.10.0/src/parser.rs000064400000000000000000000410301046102023000133000ustar 00000000000000// Copyright 2013-2014 The Rust Project Developers. // Copyright 2018 The Uuid Project Developers. // // See the COPYRIGHT file at the top-level directory of this distribution. // // Licensed under the Apache License, Version 2.0 or the MIT license // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. //! [`Uuid`] parsing constructs and utilities. //! //! [`Uuid`]: ../struct.Uuid.html use crate::{ error::*, std::{convert::TryFrom, str}, Uuid, }; impl str::FromStr for Uuid { type Err = Error; fn from_str(uuid_str: &str) -> Result { Uuid::parse_str(uuid_str) } } impl TryFrom<&'_ str> for Uuid { type Error = Error; fn try_from(uuid_str: &'_ str) -> Result { Uuid::parse_str(uuid_str) } } impl Uuid { /// Parses a `Uuid` from a string of hexadecimal digits with optional /// hyphens. /// /// Any of the formats generated by this module (simple, hyphenated, urn, /// Microsoft GUID) are supported by this parsing function. /// /// Prefer [`try_parse`] unless you need detailed user-facing diagnostics. /// This method will be eventually deprecated in favor of `try_parse`. /// /// # Examples /// /// Parse a hyphenated UUID: /// /// ``` /// # use uuid::{Uuid, Version, Variant}; /// # fn main() -> Result<(), uuid::Error> { /// let uuid = Uuid::parse_str("550e8400-e29b-41d4-a716-446655440000")?; /// /// assert_eq!(Some(Version::Random), uuid.get_version()); /// assert_eq!(Variant::RFC4122, uuid.get_variant()); /// # Ok(()) /// # } /// ``` /// /// [`try_parse`]: #method.try_parse pub fn parse_str(input: &str) -> Result { try_parse(input.as_bytes()) .map(Uuid::from_bytes) .map_err(InvalidUuid::into_err) } /// Parses a `Uuid` from a string of hexadecimal digits with optional /// hyphens. /// /// This function is similar to [`parse_str`], in fact `parse_str` shares /// the same underlying parser. The difference is that if `try_parse` /// fails, it won't generate very useful error messages. The `parse_str` /// function will eventually be deprecated in favor of `try_parse`. /// /// To parse a UUID from a byte stream instead of a UTF8 string, see /// [`try_parse_ascii`]. /// /// # Examples /// /// Parse a hyphenated UUID: /// /// ``` /// # use uuid::{Uuid, Version, Variant}; /// # fn main() -> Result<(), uuid::Error> { /// let uuid = Uuid::try_parse("550e8400-e29b-41d4-a716-446655440000")?; /// /// assert_eq!(Some(Version::Random), uuid.get_version()); /// assert_eq!(Variant::RFC4122, uuid.get_variant()); /// # Ok(()) /// # } /// ``` /// /// [`parse_str`]: #method.parse_str /// [`try_parse_ascii`]: #method.try_parse_ascii pub const fn try_parse(input: &str) -> Result { Self::try_parse_ascii(input.as_bytes()) } /// Parses a `Uuid` from a string of hexadecimal digits with optional /// hyphens. /// /// The input is expected to be a string of ASCII characters. This method /// can be more convenient than [`try_parse`] if the UUID is being /// parsed from a byte stream instead of from a UTF8 string. /// /// # Examples /// /// Parse a hyphenated UUID: /// /// ``` /// # use uuid::{Uuid, Version, Variant}; /// # fn main() -> Result<(), uuid::Error> { /// let uuid = Uuid::try_parse_ascii(b"550e8400-e29b-41d4-a716-446655440000")?; /// /// assert_eq!(Some(Version::Random), uuid.get_version()); /// assert_eq!(Variant::RFC4122, uuid.get_variant()); /// # Ok(()) /// # } /// ``` /// /// [`try_parse`]: #method.try_parse pub const fn try_parse_ascii(input: &[u8]) -> Result { match try_parse(input) { Ok(bytes) => Ok(Uuid::from_bytes(bytes)), // If parsing fails then we don't know exactly what went wrong // In this case, we just return a generic error Err(_) => Err(Error(ErrorKind::Other)), } } } const fn try_parse(input: &[u8]) -> Result<[u8; 16], InvalidUuid> { match (input.len(), input) { // Inputs of 32 bytes must be a non-hyphenated UUID (32, s) => parse_simple(s), // Hyphenated UUIDs may be wrapped in various ways: // - `{UUID}` for braced UUIDs // - `urn:uuid:UUID` for URNs // - `UUID` for a regular hyphenated UUID (36, s) | (38, [b'{', s @ .., b'}']) | (45, [b'u', b'r', b'n', b':', b'u', b'u', b'i', b'd', b':', s @ ..]) => { parse_hyphenated(s) } // Any other shaped input is immediately invalid _ => Err(InvalidUuid(input)), } } #[inline] #[allow(dead_code)] pub(crate) const fn parse_braced(input: &[u8]) -> Result<[u8; 16], InvalidUuid> { if let (38, [b'{', s @ .., b'}']) = (input.len(), input) { parse_hyphenated(s) } else { Err(InvalidUuid(input)) } } #[inline] #[allow(dead_code)] pub(crate) const fn parse_urn(input: &[u8]) -> Result<[u8; 16], InvalidUuid> { if let (45, [b'u', b'r', b'n', b':', b'u', b'u', b'i', b'd', b':', s @ ..]) = (input.len(), input) { parse_hyphenated(s) } else { Err(InvalidUuid(input)) } } #[inline] pub(crate) const fn parse_simple(s: &[u8]) -> Result<[u8; 16], InvalidUuid> { // This length check here removes all other bounds // checks in this function if s.len() != 32 { return Err(InvalidUuid(s)); } let mut buf: [u8; 16] = [0; 16]; let mut i = 0; while i < 16 { // Convert a two-char hex value (like `A8`) // into a byte (like `10101000`) let h1 = HEX_TABLE[s[i * 2] as usize]; let h2 = HEX_TABLE[s[i * 2 + 1] as usize]; // We use `0xff` as a sentinel value to indicate // an invalid hex character sequence (like the letter `G`) if h1 | h2 == 0xff { return Err(InvalidUuid(s)); } // The upper nibble needs to be shifted into position // to produce the final byte value buf[i] = SHL4_TABLE[h1 as usize] | h2; i += 1; } Ok(buf) } #[inline] const fn parse_hyphenated(s: &[u8]) -> Result<[u8; 16], InvalidUuid> { // This length check here removes all other bounds // checks in this function if s.len() != 36 { return Err(InvalidUuid(s)); } // We look at two hex-encoded values (4 chars) at a time because // that's the size of the smallest group in a hyphenated UUID. // The indexes we're interested in are: // // uuid : 936da01f-9abd-4d9d-80c7-02af85c822a8 // | | || || || || | | // hyphens : | | 8| 13| 18| 23| | | // positions: 0 4 9 14 19 24 28 32 // First, ensure the hyphens appear in the right places match [s[8], s[13], s[18], s[23]] { [b'-', b'-', b'-', b'-'] => {} _ => return Err(InvalidUuid(s)), } let positions: [u8; 8] = [0, 4, 9, 14, 19, 24, 28, 32]; let mut buf: [u8; 16] = [0; 16]; let mut j = 0; while j < 8 { let i = positions[j]; // The decoding here is the same as the simple case // We're just dealing with two values instead of one let h1 = HEX_TABLE[s[i as usize] as usize]; let h2 = HEX_TABLE[s[(i + 1) as usize] as usize]; let h3 = HEX_TABLE[s[(i + 2) as usize] as usize]; let h4 = HEX_TABLE[s[(i + 3) as usize] as usize]; if h1 | h2 | h3 | h4 == 0xff { return Err(InvalidUuid(s)); } buf[j * 2] = SHL4_TABLE[h1 as usize] | h2; buf[j * 2 + 1] = SHL4_TABLE[h3 as usize] | h4; j += 1; } Ok(buf) } const HEX_TABLE: &[u8; 256] = &{ let mut buf = [0; 256]; let mut i: u8 = 0; loop { buf[i as usize] = match i { b'0'..=b'9' => i - b'0', b'a'..=b'f' => i - b'a' + 10, b'A'..=b'F' => i - b'A' + 10, _ => 0xff, }; if i == 255 { break buf; } i += 1 } }; const SHL4_TABLE: &[u8; 256] = &{ let mut buf = [0; 256]; let mut i: u8 = 0; loop { buf[i as usize] = i.wrapping_shl(4); if i == 255 { break buf; } i += 1; } }; #[cfg(test)] mod tests { use super::*; use crate::{std::string::ToString, tests::new}; #[test] fn test_parse_uuid_v4_valid() { let from_hyphenated = Uuid::parse_str("67e55044-10b1-426f-9247-bb680e5fe0c8").unwrap(); let from_simple = Uuid::parse_str("67e5504410b1426f9247bb680e5fe0c8").unwrap(); let from_urn = Uuid::parse_str("urn:uuid:67e55044-10b1-426f-9247-bb680e5fe0c8").unwrap(); let from_guid = Uuid::parse_str("{67e55044-10b1-426f-9247-bb680e5fe0c8}").unwrap(); assert_eq!(from_hyphenated, from_simple); assert_eq!(from_hyphenated, from_urn); assert_eq!(from_hyphenated, from_guid); assert!(Uuid::parse_str("00000000000000000000000000000000").is_ok()); assert!(Uuid::parse_str("67e55044-10b1-426f-9247-bb680e5fe0c8").is_ok()); assert!(Uuid::parse_str("F9168C5E-CEB2-4faa-B6BF-329BF39FA1E4").is_ok()); assert!(Uuid::parse_str("67e5504410b1426f9247bb680e5fe0c8").is_ok()); assert!(Uuid::parse_str("01020304-1112-2122-3132-414243444546").is_ok()); assert!(Uuid::parse_str("urn:uuid:67e55044-10b1-426f-9247-bb680e5fe0c8").is_ok()); assert!(Uuid::parse_str("{6d93bade-bd9f-4e13-8914-9474e1e3567b}").is_ok()); // Nil let nil = Uuid::nil(); assert_eq!( Uuid::parse_str("00000000000000000000000000000000").unwrap(), nil ); assert_eq!( Uuid::parse_str("00000000-0000-0000-0000-000000000000").unwrap(), nil ); } #[test] fn test_parse_uuid_v4_invalid() { // Invalid assert_eq!( Uuid::parse_str(""), Err(Error(ErrorKind::SimpleLength { len: 0 })) ); assert_eq!( Uuid::parse_str("!"), Err(Error(ErrorKind::Char { character: '!', index: 1, })) ); assert_eq!( Uuid::parse_str("F9168C5E-CEB2-4faa-B6BF-329BF39FA1E45"), Err(Error(ErrorKind::GroupLength { group: 4, len: 13, index: 25, })) ); assert_eq!( Uuid::parse_str("F9168C5E-CEB2-4faa-BBF-329BF39FA1E4"), Err(Error(ErrorKind::GroupLength { group: 3, len: 3, index: 20, })) ); assert_eq!( Uuid::parse_str("F9168C5E-CEB2-4faa-BGBF-329BF39FA1E4"), Err(Error(ErrorKind::Char { character: 'G', index: 21, })) ); assert_eq!( Uuid::parse_str("F9168C5E-CEB2F4faaFB6BFF329BF39FA1E4"), Err(Error(ErrorKind::GroupCount { count: 2 })) ); assert_eq!( Uuid::parse_str("F9168C5E-CEB2-4faaFB6BFF329BF39FA1E4"), Err(Error(ErrorKind::GroupCount { count: 3 })) ); assert_eq!( Uuid::parse_str("F9168C5E-CEB2-4faa-B6BFF329BF39FA1E4"), Err(Error(ErrorKind::GroupCount { count: 4 })) ); assert_eq!( Uuid::parse_str("F9168C5E-CEB2-4faa"), Err(Error(ErrorKind::GroupCount { count: 3 })) ); assert_eq!( Uuid::parse_str("F9168C5E-CEB2-4faaXB6BFF329BF39FA1E4"), Err(Error(ErrorKind::Char { character: 'X', index: 19, })) ); assert_eq!( Uuid::parse_str("{F9168C5E-CEB2-4faa9B6BFF329BF39FA1E41"), Err(Error(ErrorKind::Char { character: '{', index: 1, })) ); assert_eq!( Uuid::parse_str("{F9168C5E-CEB2-4faa9B6BFF329BF39FA1E41}"), Err(Error(ErrorKind::GroupCount { count: 3 })) ); assert_eq!( Uuid::parse_str("F9168C5E-CEB-24fa-eB6BFF32-BF39FA1E4"), Err(Error(ErrorKind::GroupLength { group: 1, len: 3, index: 10, })) ); // // (group, found, expecting) // // assert_eq!( Uuid::parse_str("01020304-1112-2122-3132-41424344"), Err(Error(ErrorKind::GroupLength { group: 4, len: 8, index: 25, })) ); assert_eq!( Uuid::parse_str("67e5504410b1426f9247bb680e5fe0c"), Err(Error(ErrorKind::SimpleLength { len: 31 })) ); assert_eq!( Uuid::parse_str("67e5504410b1426f9247bb680e5fe0c88"), Err(Error(ErrorKind::SimpleLength { len: 33 })) ); assert_eq!( Uuid::parse_str("67e5504410b1426f9247bb680e5fe0cg8"), Err(Error(ErrorKind::Char { character: 'g', index: 32, })) ); assert_eq!( Uuid::parse_str("67e5504410b1426%9247bb680e5fe0c8"), Err(Error(ErrorKind::Char { character: '%', index: 16, })) ); assert_eq!( Uuid::parse_str("231231212212423424324323477343246663"), Err(Error(ErrorKind::SimpleLength { len: 36 })) ); assert_eq!( Uuid::parse_str("{00000000000000000000000000000000}"), Err(Error(ErrorKind::GroupCount { count: 1 })) ); assert_eq!( Uuid::parse_str("67e5504410b1426f9247bb680e5fe0c"), Err(Error(ErrorKind::SimpleLength { len: 31 })) ); assert_eq!( Uuid::parse_str("67e550X410b1426f9247bb680e5fe0cd"), Err(Error(ErrorKind::Char { character: 'X', index: 7, })) ); assert_eq!( Uuid::parse_str("67e550-4105b1426f9247bb680e5fe0c"), Err(Error(ErrorKind::GroupCount { count: 2 })) ); assert_eq!( Uuid::parse_str("F9168C5E-CEB2-4faa-B6BF1-02BF39FA1E4"), Err(Error(ErrorKind::GroupLength { group: 3, len: 5, index: 20, })) ); assert_eq!( Uuid::parse_str("\u{bcf3c}"), Err(Error(ErrorKind::Char { character: '\u{bcf3c}', index: 1 })) ); } #[test] fn test_roundtrip_default() { let uuid_orig = new(); let orig_str = uuid_orig.to_string(); let uuid_out = Uuid::parse_str(&orig_str).unwrap(); assert_eq!(uuid_orig, uuid_out); } #[test] fn test_roundtrip_hyphenated() { let uuid_orig = new(); let orig_str = uuid_orig.hyphenated().to_string(); let uuid_out = Uuid::parse_str(&orig_str).unwrap(); assert_eq!(uuid_orig, uuid_out); } #[test] fn test_roundtrip_simple() { let uuid_orig = new(); let orig_str = uuid_orig.simple().to_string(); let uuid_out = Uuid::parse_str(&orig_str).unwrap(); assert_eq!(uuid_orig, uuid_out); } #[test] fn test_roundtrip_urn() { let uuid_orig = new(); let orig_str = uuid_orig.urn().to_string(); let uuid_out = Uuid::parse_str(&orig_str).unwrap(); assert_eq!(uuid_orig, uuid_out); } #[test] fn test_roundtrip_braced() { let uuid_orig = new(); let orig_str = uuid_orig.braced().to_string(); let uuid_out = Uuid::parse_str(&orig_str).unwrap(); assert_eq!(uuid_orig, uuid_out); } #[test] fn test_roundtrip_parse_urn() { let uuid_orig = new(); let orig_str = uuid_orig.urn().to_string(); let uuid_out = Uuid::from_bytes(parse_urn(orig_str.as_bytes()).unwrap()); assert_eq!(uuid_orig, uuid_out); } #[test] fn test_roundtrip_parse_braced() { let uuid_orig = new(); let orig_str = uuid_orig.braced().to_string(); let uuid_out = Uuid::from_bytes(parse_braced(orig_str.as_bytes()).unwrap()); assert_eq!(uuid_orig, uuid_out); } #[test] fn test_try_parse_ascii_non_utf8() { assert!(Uuid::try_parse_ascii(b"67e55044-10b1-426f-9247-bb680e5\0e0c8").is_err()); } } uuid-1.10.0/src/rng.rs000064400000000000000000000026511046102023000126000ustar 00000000000000#[cfg(any(feature = "v4", feature = "v7"))] pub(crate) fn u128() -> u128 { #[cfg(not(feature = "fast-rng"))] { let mut bytes = [0u8; 16]; getrandom::getrandom(&mut bytes).unwrap_or_else(|err| { // NB: getrandom::Error has no source; this is adequate display panic!("could not retrieve random bytes for uuid: {}", err) }); u128::from_ne_bytes(bytes) } #[cfg(feature = "fast-rng")] { rand::random() } } #[cfg(any(feature = "v1", feature = "v6"))] pub(crate) fn u16() -> u16 { #[cfg(not(feature = "fast-rng"))] { let mut bytes = [0u8; 2]; getrandom::getrandom(&mut bytes).unwrap_or_else(|err| { // NB: getrandom::Error has no source; this is adequate display panic!("could not retrieve random bytes for uuid: {}", err) }); u16::from_ne_bytes(bytes) } #[cfg(feature = "fast-rng")] { rand::random() } } #[cfg(feature = "v7")] pub(crate) fn u64() -> u64 { #[cfg(not(feature = "fast-rng"))] { let mut bytes = [0u8; 8]; getrandom::getrandom(&mut bytes).unwrap_or_else(|err| { // NB: getrandom::Error has no source; this is adequate display panic!("could not retrieve random bytes for uuid: {}", err) }); u64::from_ne_bytes(bytes) } #[cfg(feature = "fast-rng")] { rand::random() } } uuid-1.10.0/src/sha1.rs000064400000000000000000000004411046102023000126410ustar 00000000000000#[cfg(feature = "v5")] pub(crate) fn hash(ns: &[u8], src: &[u8]) -> [u8; 16] { use sha1_smol::Sha1; let mut hasher = Sha1::new(); hasher.update(ns); hasher.update(src); let mut bytes = [0; 16]; bytes.copy_from_slice(&hasher.digest().bytes()[..16]); bytes } uuid-1.10.0/src/timestamp.rs000064400000000000000000001000271046102023000140110ustar 00000000000000//! Generating UUIDs from timestamps. //! //! Timestamps are used in a few UUID versions as a source of decentralized //! uniqueness (as in versions 1 and 6), and as a way to enable sorting (as //! in versions 6 and 7). Timestamps aren't encoded the same way by all UUID //! versions so this module provides a single [`Timestamp`] type that can //! convert between them. //! //! # Timestamp representations in UUIDs //! //! Versions 1 and 6 UUIDs use a bespoke timestamp that consists of the //! number of 100ns ticks since `1582-10-15 00:00:00`, along with //! a counter value to avoid duplicates. //! //! Version 7 UUIDs use a more standard timestamp that consists of the //! number of millisecond ticks since the Unix epoch (`1970-01-01 00:00:00`). //! //! # References //! //! * [UUID Version 1 in RFC 9562](https://www.ietf.org/rfc/rfc9562.html#section-5.1) //! * [UUID Version 7 in RFC 9562](https://www.ietf.org/rfc/rfc9562.html#section-5.7) //! * [Timestamp Considerations in RFC 9562](https://www.ietf.org/rfc/rfc9562.html#section-6.1) use core::cmp; use crate::Uuid; /// The number of 100 nanosecond ticks between the RFC 9562 epoch /// (`1582-10-15 00:00:00`) and the Unix epoch (`1970-01-01 00:00:00`). pub const UUID_TICKS_BETWEEN_EPOCHS: u64 = 0x01B2_1DD2_1381_4000; /// A timestamp that can be encoded into a UUID. /// /// This type abstracts the specific encoding, so versions 1, 6, and 7 /// UUIDs can both be supported through the same type, even /// though they have a different representation of a timestamp. /// /// # References /// /// * [Timestamp Considerations in RFC 9562](https://www.ietf.org/rfc/rfc9562.html#section-6.1) /// * [UUID Generator States in RFC 9562](https://www.ietf.org/rfc/rfc9562.html#section-6.3) #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct Timestamp { seconds: u64, subsec_nanos: u32, counter: u128, usable_counter_bits: u8, } impl Timestamp { /// Get a timestamp representing the current system time and up to a 128-bit counter. /// /// This method defers to the standard library's `SystemTime` type. #[cfg(feature = "std")] pub fn now(context: impl ClockSequence>) -> Self { let (seconds, subsec_nanos) = now(); let (counter, seconds, subsec_nanos) = context.generate_timestamp_sequence(seconds, subsec_nanos); let counter = counter.into(); let usable_counter_bits = context.usable_bits() as u8; Timestamp { seconds, subsec_nanos, counter, usable_counter_bits, } } /// Construct a `Timestamp` from the number of 100 nanosecond ticks since 00:00:00.00, /// 15 October 1582 (the date of Gregorian reform to the Christian calendar) and a 14-bit /// counter, as used in versions 1 and 6 UUIDs. /// /// # Overflow /// /// If conversion from RFC 9562 ticks to the internal timestamp format would overflow /// it will wrap. pub const fn from_gregorian(ticks: u64, counter: u16) -> Self { let (seconds, subsec_nanos) = Self::gregorian_to_unix(ticks); Timestamp { seconds, subsec_nanos, counter: counter as u128, usable_counter_bits: 14, } } /// Construct a `Timestamp` from a Unix timestamp and up to a 128-bit counter, as used in version 7 UUIDs. pub const fn from_unix_time( seconds: u64, subsec_nanos: u32, counter: u128, usable_counter_bits: u8, ) -> Self { Timestamp { seconds, subsec_nanos, counter, usable_counter_bits, } } /// Construct a `Timestamp` from a Unix timestamp and up to a 128-bit counter, as used in version 7 UUIDs. pub fn from_unix( context: impl ClockSequence>, seconds: u64, subsec_nanos: u32, ) -> Self { let (counter, seconds, subsec_nanos) = context.generate_timestamp_sequence(seconds, subsec_nanos); let counter = counter.into(); let usable_counter_bits = context.usable_bits() as u8; Timestamp { seconds, subsec_nanos, counter, usable_counter_bits, } } /// Get the value of the timestamp as the number of 100 nanosecond ticks since 00:00:00.00, /// 15 October 1582 and a 14-bit counter, as used in versions 1 and 6 UUIDs. /// /// # Overflow /// /// If conversion from the internal timestamp format to ticks would overflow /// then it will wrap. /// /// If the internal counter is wider than 14 bits then it will be truncated to 14 bits. pub const fn to_gregorian(&self) -> (u64, u16) { ( Self::unix_to_gregorian_ticks(self.seconds, self.subsec_nanos), (self.counter as u16) & 0x3FFF, ) } // NOTE: This method is not public; the usable counter bits are lost in a version 7 UUID // so can't be reliably recovered. #[cfg(feature = "v7")] pub(crate) const fn counter(&self) -> (u128, u8) { (self.counter, self.usable_counter_bits) } /// Get the value of the timestamp as a Unix timestamp, as used in version 7 UUIDs. pub const fn to_unix(&self) -> (u64, u32) { (self.seconds, self.subsec_nanos) } const fn unix_to_gregorian_ticks(seconds: u64, nanos: u32) -> u64 { UUID_TICKS_BETWEEN_EPOCHS .wrapping_add(seconds.wrapping_mul(10_000_000)) .wrapping_add(nanos as u64 / 100) } const fn gregorian_to_unix(ticks: u64) -> (u64, u32) { ( ticks.wrapping_sub(UUID_TICKS_BETWEEN_EPOCHS) / 10_000_000, (ticks.wrapping_sub(UUID_TICKS_BETWEEN_EPOCHS) % 10_000_000) as u32 * 100, ) } } #[doc(hidden)] impl Timestamp { #[deprecated(since = "1.10.0", note = "use `Timestamp::from_gregorian(ticks, counter)`")] pub const fn from_rfc4122(ticks: u64, counter: u16) -> Self { Timestamp::from_gregorian(ticks, counter) } #[deprecated(since = "1.10.0", note = "use `Timestamp::to_gregorian()`")] pub const fn to_rfc4122(&self) -> (u64, u16) { self.to_gregorian() } #[deprecated(since = "1.2.0", note = "`Timestamp::to_unix_nanos()` is deprecated and will be removed: use `Timestamp::to_unix()`")] pub const fn to_unix_nanos(&self) -> u32 { panic!("`Timestamp::to_unix_nanos()` is deprecated and will be removed: use `Timestamp::to_unix()`") } } pub(crate) const fn encode_gregorian_timestamp( ticks: u64, counter: u16, node_id: &[u8; 6], ) -> Uuid { let time_low = (ticks & 0xFFFF_FFFF) as u32; let time_mid = ((ticks >> 32) & 0xFFFF) as u16; let time_high_and_version = (((ticks >> 48) & 0x0FFF) as u16) | (1 << 12); let mut d4 = [0; 8]; d4[0] = (((counter & 0x3F00) >> 8) as u8) | 0x80; d4[1] = (counter & 0xFF) as u8; d4[2] = node_id[0]; d4[3] = node_id[1]; d4[4] = node_id[2]; d4[5] = node_id[3]; d4[6] = node_id[4]; d4[7] = node_id[5]; Uuid::from_fields(time_low, time_mid, time_high_and_version, &d4) } pub(crate) const fn decode_gregorian_timestamp(uuid: &Uuid) -> (u64, u16) { let bytes = uuid.as_bytes(); let ticks: u64 = ((bytes[6] & 0x0F) as u64) << 56 | (bytes[7] as u64) << 48 | (bytes[4] as u64) << 40 | (bytes[5] as u64) << 32 | (bytes[0] as u64) << 24 | (bytes[1] as u64) << 16 | (bytes[2] as u64) << 8 | (bytes[3] as u64); let counter: u16 = ((bytes[8] & 0x3F) as u16) << 8 | (bytes[9] as u16); (ticks, counter) } pub(crate) const fn encode_sorted_gregorian_timestamp( ticks: u64, counter: u16, node_id: &[u8; 6], ) -> Uuid { let time_high = ((ticks >> 28) & 0xFFFF_FFFF) as u32; let time_mid = ((ticks >> 12) & 0xFFFF) as u16; let time_low_and_version = ((ticks & 0x0FFF) as u16) | (0x6 << 12); let mut d4 = [0; 8]; d4[0] = (((counter & 0x3F00) >> 8) as u8) | 0x80; d4[1] = (counter & 0xFF) as u8; d4[2] = node_id[0]; d4[3] = node_id[1]; d4[4] = node_id[2]; d4[5] = node_id[3]; d4[6] = node_id[4]; d4[7] = node_id[5]; Uuid::from_fields(time_high, time_mid, time_low_and_version, &d4) } pub(crate) const fn decode_sorted_gregorian_timestamp(uuid: &Uuid) -> (u64, u16) { let bytes = uuid.as_bytes(); let ticks: u64 = ((bytes[0]) as u64) << 52 | (bytes[1] as u64) << 44 | (bytes[2] as u64) << 36 | (bytes[3] as u64) << 28 | (bytes[4] as u64) << 20 | (bytes[5] as u64) << 12 | ((bytes[6] & 0xF) as u64) << 8 | (bytes[7] as u64); let counter: u16 = ((bytes[8] & 0x3F) as u16) << 8 | (bytes[9] as u16); (ticks, counter) } pub(crate) const fn encode_unix_timestamp_millis( millis: u64, counter_random_bytes: &[u8; 10], ) -> Uuid { let millis_high = ((millis >> 16) & 0xFFFF_FFFF) as u32; let millis_low = (millis & 0xFFFF) as u16; let counter_random_version = (counter_random_bytes[1] as u16 | ((counter_random_bytes[0] as u16) << 8) & 0x0FFF) | (0x7 << 12); let mut d4 = [0; 8]; d4[0] = (counter_random_bytes[2] & 0x3F) | 0x80; d4[1] = counter_random_bytes[3]; d4[2] = counter_random_bytes[4]; d4[3] = counter_random_bytes[5]; d4[4] = counter_random_bytes[6]; d4[5] = counter_random_bytes[7]; d4[6] = counter_random_bytes[8]; d4[7] = counter_random_bytes[9]; Uuid::from_fields(millis_high, millis_low, counter_random_version, &d4) } pub(crate) const fn decode_unix_timestamp_millis(uuid: &Uuid) -> u64 { let bytes = uuid.as_bytes(); let millis: u64 = (bytes[0] as u64) << 40 | (bytes[1] as u64) << 32 | (bytes[2] as u64) << 24 | (bytes[3] as u64) << 16 | (bytes[4] as u64) << 8 | (bytes[5] as u64); millis } #[cfg(all( feature = "std", feature = "js", all( target_arch = "wasm32", target_vendor = "unknown", target_os = "unknown" ) ))] fn now() -> (u64, u32) { use wasm_bindgen::prelude::*; #[wasm_bindgen] extern "C" { // NOTE: This signature works around https://bugzilla.mozilla.org/show_bug.cgi?id=1787770 #[wasm_bindgen(js_namespace = Date, catch)] fn now() -> Result; } let now = now().unwrap_throw(); let secs = (now / 1_000.0) as u64; let nanos = ((now % 1_000.0) * 1_000_000.0) as u32; (secs, nanos) } #[cfg(all( feature = "std", not(miri), any( not(feature = "js"), not(all( target_arch = "wasm32", target_vendor = "unknown", target_os = "unknown" )) ) ))] fn now() -> (u64, u32) { let dur = std::time::SystemTime::UNIX_EPOCH.elapsed().expect( "Getting elapsed time since UNIX_EPOCH. If this fails, we've somehow violated causality", ); (dur.as_secs(), dur.subsec_nanos()) } #[cfg(all(feature = "std", miri))] fn now() -> (u64, u32) { use std::{sync::Mutex, time::Duration}; static TS: Mutex = Mutex::new(0); let ts = Duration::from_nanos({ let mut ts = TS.lock().unwrap(); *ts += 1; *ts }); (ts.as_secs(), ts.subsec_nanos()) } /// A counter that can be used by versions 1 and 6 UUIDs to support /// the uniqueness of timestamps. /// /// # References /// /// * [UUID Version 1 in RFC 9562](https://www.ietf.org/rfc/rfc9562.html#section-5.1) /// * [UUID Version 6 in RFC 9562](https://www.ietf.org/rfc/rfc9562.html#section-5.6) /// * [UUID Generator States in RFC 9562](https://www.ietf.org/rfc/rfc9562.html#section-6.3) pub trait ClockSequence { /// The type of sequence returned by this counter. type Output; /// Get the next value in the sequence to feed into a timestamp. /// /// This method will be called each time a [`Timestamp`] is constructed. /// /// Any bits beyond [`ClockSequence::usable_bits`] in the output must be unset. fn generate_sequence(&self, seconds: u64, subsec_nanos: u32) -> Self::Output; /// Get the next value in the sequence, potentially also adjusting the timestamp. /// /// This method should be preferred over `generate_sequence`. /// /// Any bits beyond [`ClockSequence::usable_bits`] in the output must be unset. fn generate_timestamp_sequence( &self, seconds: u64, subsec_nanos: u32, ) -> (Self::Output, u64, u32) { ( self.generate_sequence(seconds, subsec_nanos), seconds, subsec_nanos, ) } /// The number of usable bits from the least significant bit in the result of [`ClockSequence::generate_sequence`] /// or [`ClockSequence::generate_timestamp_sequence`]. /// /// The number of usable bits must not exceed 128. /// /// The number of usable bits is not expected to change between calls. An implementation of `ClockSequence` should /// always return the same value from this method. fn usable_bits(&self) -> usize where Self::Output: Sized, { cmp::min(128, core::mem::size_of::()) } } impl<'a, T: ClockSequence + ?Sized> ClockSequence for &'a T { type Output = T::Output; fn generate_sequence(&self, seconds: u64, subsec_nanos: u32) -> Self::Output { (**self).generate_sequence(seconds, subsec_nanos) } fn generate_timestamp_sequence( &self, seconds: u64, subsec_nanos: u32, ) -> (Self::Output, u64, u32) { (**self).generate_timestamp_sequence(seconds, subsec_nanos) } fn usable_bits(&self) -> usize where Self::Output: Sized, { (**self).usable_bits() } } /// Default implementations for the [`ClockSequence`] trait. pub mod context { use super::ClockSequence; #[cfg(any(feature = "v1", feature = "v6"))] mod v1_support { use super::*; use atomic::{Atomic, Ordering}; #[cfg(all(feature = "std", feature = "rng"))] static CONTEXT: Context = Context { count: Atomic::new(0), }; #[cfg(all(feature = "std", feature = "rng"))] static CONTEXT_INITIALIZED: Atomic = Atomic::new(false); #[cfg(all(feature = "std", feature = "rng"))] pub(crate) fn shared_context() -> &'static Context { // If the context is in its initial state then assign it to a random value // It doesn't matter if multiple threads observe `false` here and initialize the context if CONTEXT_INITIALIZED .compare_exchange(false, true, Ordering::Relaxed, Ordering::Relaxed) .is_ok() { CONTEXT.count.store(crate::rng::u16(), Ordering::Release); } &CONTEXT } /// A thread-safe, wrapping counter that produces 14-bit values. /// /// This type works by: /// /// 1. Atomically incrementing the counter value for each timestamp. /// 2. Wrapping the counter back to zero if it overflows its 14-bit storage. /// /// This type should be used when constructing versions 1 and 6 UUIDs. /// /// This type should not be used when constructing version 7 UUIDs. When used to /// construct a version 7 UUID, the 14-bit counter will be padded with random data. /// Counter overflows are more likely with a 14-bit counter than they are with a /// 42-bit counter when working at millisecond precision. This type doesn't attempt /// to adjust the timestamp on overflow. #[derive(Debug)] pub struct Context { count: Atomic, } impl Context { /// Construct a new context that's initialized with the given value. /// /// The starting value should be a random number, so that UUIDs from /// different systems with the same timestamps are less likely to collide. /// When the `rng` feature is enabled, prefer the [`Context::new_random`] method. pub const fn new(count: u16) -> Self { Self { count: Atomic::::new(count), } } /// Construct a new context that's initialized with a random value. #[cfg(feature = "rng")] pub fn new_random() -> Self { Self { count: Atomic::::new(crate::rng::u16()), } } } impl ClockSequence for Context { type Output = u16; fn generate_sequence(&self, _seconds: u64, _nanos: u32) -> Self::Output { // RFC 9562 reserves 2 bits of the clock sequence so the actual // maximum value is smaller than `u16::MAX`. Since we unconditionally // increment the clock sequence we want to wrap once it becomes larger // than what we can represent in a "u14". Otherwise there'd be patches // where the clock sequence doesn't change regardless of the timestamp self.count.fetch_add(1, Ordering::AcqRel) & (u16::MAX >> 2) } fn usable_bits(&self) -> usize { 14 } } #[cfg(test)] mod tests { use crate::Timestamp; use super::*; #[test] fn context() { let seconds = 1_496_854_535; let subsec_nanos = 812_946_000; let context = Context::new(u16::MAX >> 2); let ts = Timestamp::from_unix(&context, seconds, subsec_nanos); assert_eq!(16383, ts.counter); assert_eq!(14, ts.usable_counter_bits); let seconds = 1_496_854_536; let ts = Timestamp::from_unix(&context, seconds, subsec_nanos); assert_eq!(0, ts.counter); let seconds = 1_496_854_535; let ts = Timestamp::from_unix(&context, seconds, subsec_nanos); assert_eq!(1, ts.counter); } } } #[cfg(any(feature = "v1", feature = "v6"))] pub use v1_support::*; #[cfg(feature = "std")] mod std_support { use super::*; use core::panic::{AssertUnwindSafe, RefUnwindSafe}; use std::{sync::Mutex, thread::LocalKey}; /// A wrapper for a context that uses thread-local storage. pub struct ThreadLocalContext(&'static LocalKey); impl std::fmt::Debug for ThreadLocalContext { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.debug_struct("ThreadLocalContext").finish_non_exhaustive() } } impl ThreadLocalContext { /// Wrap a thread-local container with a context. pub const fn new(local_key: &'static LocalKey) -> Self { ThreadLocalContext(local_key) } } impl ClockSequence for ThreadLocalContext { type Output = C::Output; fn generate_sequence(&self, seconds: u64, subsec_nanos: u32) -> Self::Output { self.0 .with(|ctxt| ctxt.generate_sequence(seconds, subsec_nanos)) } fn generate_timestamp_sequence( &self, seconds: u64, subsec_nanos: u32, ) -> (Self::Output, u64, u32) { self.0 .with(|ctxt| ctxt.generate_timestamp_sequence(seconds, subsec_nanos)) } fn usable_bits(&self) -> usize { self.0.with(|ctxt| ctxt.usable_bits()) } } impl ClockSequence for AssertUnwindSafe { type Output = C::Output; fn generate_sequence(&self, seconds: u64, subsec_nanos: u32) -> Self::Output { self.0.generate_sequence(seconds, subsec_nanos) } fn generate_timestamp_sequence( &self, seconds: u64, subsec_nanos: u32, ) -> (Self::Output, u64, u32) { self.0.generate_timestamp_sequence(seconds, subsec_nanos) } fn usable_bits(&self) -> usize where Self::Output: Sized, { self.0.usable_bits() } } impl ClockSequence for Mutex { type Output = C::Output; fn generate_sequence(&self, seconds: u64, subsec_nanos: u32) -> Self::Output { self.lock() .unwrap_or_else(|err| err.into_inner()) .generate_sequence(seconds, subsec_nanos) } fn generate_timestamp_sequence( &self, seconds: u64, subsec_nanos: u32, ) -> (Self::Output, u64, u32) { self.lock() .unwrap_or_else(|err| err.into_inner()) .generate_timestamp_sequence(seconds, subsec_nanos) } fn usable_bits(&self) -> usize where Self::Output: Sized, { self.lock() .unwrap_or_else(|err| err.into_inner()) .usable_bits() } } } #[cfg(feature = "std")] pub use std_support::*; #[cfg(feature = "v7")] mod v7_support { use super::*; use core::{cell::Cell, panic::RefUnwindSafe}; #[cfg(feature = "std")] static CONTEXT_V7: SharedContextV7 = SharedContextV7(std::sync::Mutex::new(ContextV7::new())); #[cfg(feature = "std")] pub(crate) fn shared_context_v7() -> &'static SharedContextV7 { &CONTEXT_V7 } const USABLE_BITS: usize = 42; // Leave the most significant bit unset // This guarantees the counter has at least 2,199,023,255,552 // values before it will overflow, which is exceptionally unlikely // even in the worst case const RESEED_MASK: u64 = u64::MAX >> 23; const MAX_COUNTER: u64 = u64::MAX >> 22; /// An unsynchronized, reseeding counter that produces 42-bit values. /// /// This type works by: /// /// 1. Reseeding the counter each millisecond with a random 41-bit value. The 42nd bit /// is left unset so the counter can safely increment over the millisecond. /// 2. Wrapping the counter back to zero if it overflows its 42-bit storage and adding a /// millisecond to the timestamp. /// /// This type can be used when constructing version 7 UUIDs. When used to construct a /// version 7 UUID, the 42-bit counter will be padded with random data. This type can /// be used to maintain ordering of UUIDs within the same millisecond. /// /// This type should not be used when constructing version 1 or version 6 UUIDs. /// When used to construct a version 1 or version 6 UUID, only the 14 least significant /// bits of the counter will be used. #[derive(Debug)] pub struct ContextV7 { last_reseed: Cell, counter: Cell, } #[derive(Debug, Default, Clone, Copy)] struct LastReseed { millis: u64, ts_seconds: u64, ts_subsec_nanos: u32, } impl LastReseed { fn from_millis(millis: u64) -> Self { LastReseed { millis, ts_seconds: millis / 1_000, ts_subsec_nanos: (millis % 1_000) as u32 * 1_000_000, } } } impl RefUnwindSafe for ContextV7 {} impl ContextV7 { /// Construct a new context that will reseed its counter on the first /// non-zero timestamp it receives. pub const fn new() -> Self { ContextV7 { last_reseed: Cell::new(LastReseed { millis: 0, ts_seconds: 0, ts_subsec_nanos: 0, }), counter: Cell::new(0), } } } impl ClockSequence for ContextV7 { type Output = u64; fn generate_sequence(&self, seconds: u64, subsec_nanos: u32) -> Self::Output { self.generate_timestamp_sequence(seconds, subsec_nanos).0 } fn generate_timestamp_sequence( &self, seconds: u64, subsec_nanos: u32, ) -> (Self::Output, u64, u32) { let millis = (seconds * 1_000).saturating_add(subsec_nanos as u64 / 1_000_000); let last_reseed = self.last_reseed.get(); // If the observed system time has shifted forwards then regenerate the counter if millis > last_reseed.millis { let last_reseed = LastReseed::from_millis(millis); self.last_reseed.set(last_reseed); let counter = crate::rng::u64() & RESEED_MASK; self.counter.set(counter); (counter, last_reseed.ts_seconds, last_reseed.ts_subsec_nanos) } // If the observed system time has not shifted forwards then increment the counter else { // If the incoming timestamp is earlier than the last observed one then // use it instead. This may happen if the system clock jitters, or if the counter // has wrapped and the timestamp is artificially incremented let millis = (); let _ = millis; // Guaranteed to never overflow u64 let counter = self.counter.get() + 1; // If the counter has not overflowed its 42-bit storage then return it if counter <= MAX_COUNTER { self.counter.set(counter); (counter, last_reseed.ts_seconds, last_reseed.ts_subsec_nanos) } // Unlikely: If the counter has overflowed its 42-bit storage then wrap it // and increment the timestamp. Until the observed system time shifts past // this incremented value, all timestamps will use it to maintain monotonicity else { // Increment the timestamp by 1 milli let last_reseed = LastReseed::from_millis(last_reseed.millis + 1); self.last_reseed.set(last_reseed); // Reseed the counter let counter = crate::rng::u64() & RESEED_MASK; self.counter.set(counter); (counter, last_reseed.ts_seconds, last_reseed.ts_subsec_nanos) } } } fn usable_bits(&self) -> usize { USABLE_BITS } } #[cfg(feature = "std")] pub(crate) struct SharedContextV7(std::sync::Mutex); #[cfg(feature = "std")] impl ClockSequence for SharedContextV7 { type Output = u64; fn generate_sequence(&self, seconds: u64, subsec_nanos: u32) -> Self::Output { self.0.generate_sequence(seconds, subsec_nanos) } fn generate_timestamp_sequence( &self, seconds: u64, subsec_nanos: u32, ) -> (Self::Output, u64, u32) { self.0.generate_timestamp_sequence(seconds, subsec_nanos) } fn usable_bits(&self) -> usize where Self::Output: Sized, { USABLE_BITS } } #[cfg(test)] mod tests { use core::time::Duration; use super::*; use crate::Timestamp; #[test] fn context() { let seconds = 1_496_854_535; let subsec_nanos = 812_946_000; let context = ContextV7::new(); let ts1 = Timestamp::from_unix(&context, seconds, subsec_nanos); assert_eq!(42, ts1.usable_counter_bits); // Backwards second let seconds = 1_496_854_534; let ts2 = Timestamp::from_unix(&context, seconds, subsec_nanos); // The backwards time should be ignored // The counter should still increment assert_eq!(ts1.seconds, ts2.seconds); assert_eq!(ts1.subsec_nanos, ts2.subsec_nanos); assert_eq!(ts1.counter + 1, ts2.counter); // Forwards second let seconds = 1_496_854_536; let ts3 = Timestamp::from_unix(&context, seconds, subsec_nanos); // The counter should have reseeded assert_ne!(ts2.counter + 1, ts3.counter); assert_ne!(0, ts3.counter); } #[test] fn context_wrap() { let seconds = 1_496_854_535u64; let subsec_nanos = 812_946_000u32; let millis = (seconds * 1000).saturating_add(subsec_nanos as u64 / 1_000_000); // This context will wrap let context = ContextV7 { last_reseed: Cell::new(LastReseed::from_millis(millis)), counter: Cell::new(u64::MAX >> 22), }; let ts = Timestamp::from_unix(&context, seconds, subsec_nanos); // The timestamp should be incremented by 1ms let expected_ts = Duration::new(seconds, subsec_nanos / 1_000_000 * 1_000_000) + Duration::from_millis(1); assert_eq!(expected_ts.as_secs(), ts.seconds); assert_eq!(expected_ts.subsec_nanos(), ts.subsec_nanos); // The counter should have reseeded assert!(ts.counter < (u64::MAX >> 22) as u128); assert_ne!(0, ts.counter); } } } #[cfg(feature = "v7")] pub use v7_support::*; /// An empty counter that will always return the value `0`. /// /// This type can be used when constructing version 7 UUIDs. When used to /// construct a version 7 UUID, the entire counter segment of the UUID will be /// filled with a random value. This type does not maintain ordering of UUIDs /// within a millisecond but is efficient. /// /// This type should not be used when constructing version 1 or version 6 UUIDs. /// When used to construct a version 1 or version 6 UUID, the counter /// segment will remain zero. #[derive(Debug, Clone, Copy, Default)] pub struct NoContext; impl ClockSequence for NoContext { type Output = u16; fn generate_sequence(&self, _seconds: u64, _nanos: u32) -> Self::Output { 0 } fn usable_bits(&self) -> usize { 0 } } } #[cfg(all(test, any(feature = "v1", feature = "v6")))] mod tests { use super::*; #[cfg(all( target_arch = "wasm32", target_vendor = "unknown", target_os = "unknown" ))] use wasm_bindgen_test::*; #[test] #[cfg_attr( all( target_arch = "wasm32", target_vendor = "unknown", target_os = "unknown" ), wasm_bindgen_test )] fn gregorian_unix_does_not_panic() { // Ensure timestamp conversions never panic Timestamp::unix_to_gregorian_ticks(u64::MAX, 0); Timestamp::unix_to_gregorian_ticks(0, u32::MAX); Timestamp::unix_to_gregorian_ticks(u64::MAX, u32::MAX); Timestamp::gregorian_to_unix(u64::MAX); } #[test] #[cfg_attr( all( target_arch = "wasm32", target_vendor = "unknown", target_os = "unknown" ), wasm_bindgen_test )] fn to_gregorian_truncates_to_usable_bits() { let ts = Timestamp::from_gregorian(123, u16::MAX); assert_eq!((123, u16::MAX >> 2), ts.to_gregorian()); } } uuid-1.10.0/src/v1.rs000064400000000000000000000127251046102023000123430ustar 00000000000000//! The implementation for Version 1 UUIDs. //! //! This module is soft-deprecated. Instead of using the `Context` type re-exported here, //! use the one from the crate root. use crate::{Builder, Uuid}; #[deprecated(note = "use types from the crate root instead")] pub use crate::{timestamp::context::Context, Timestamp}; impl Uuid { /// Create a new version 1 UUID using the current system time and node ID. /// /// This method is only available if both the `std` and `rng` features are enabled. /// /// This method is a convenient alternative to [`Uuid::new_v1`] that uses the current system time /// as the source timestamp. /// /// Note that usage of this method requires the `v1`, `std`, and `rng` features of this crate /// to be enabled. #[cfg(all(feature = "std", feature = "rng"))] pub fn now_v1(node_id: &[u8; 6]) -> Self { let ts = Timestamp::now(crate::timestamp::context::shared_context()); Self::new_v1(ts, node_id) } /// Create a new version 1 UUID using the given timestamp and node ID. /// /// Also see [`Uuid::now_v1`] for a convenient way to generate version 1 /// UUIDs using the current system time. /// /// When generating [`Timestamp`]s using a [`ClockSequence`], this function /// is only guaranteed to produce unique values if the following conditions /// hold: /// /// 1. The *node ID* is unique for this process, /// 2. The *context* is shared across all threads which are generating version 1 /// UUIDs, /// 3. The [`ClockSequence`] implementation reliably returns unique /// clock sequences (this crate provides [`Context`] for this /// purpose. However you can create your own [`ClockSequence`] /// implementation, if [`Context`] does not meet your needs). /// /// Note that usage of this method requires the `v1` feature of this crate /// to be enabled. /// /// # Examples /// /// A UUID can be created from a unix [`Timestamp`] with a /// [`ClockSequence`]. RFC 9562 requires the clock sequence /// is seeded with a random value: /// /// ``` /// # use uuid::{Timestamp, Context}; /// # use uuid::Uuid; /// # fn random_seed() -> u16 { 42 } /// let context = Context::new(random_seed()); /// let ts = Timestamp::from_unix(&context, 1497624119, 1234); /// /// let uuid = Uuid::new_v1(ts, &[1, 2, 3, 4, 5, 6]); /// /// assert_eq!( /// uuid.hyphenated().to_string(), /// "f3b4958c-52a1-11e7-802a-010203040506" /// ); /// ``` /// /// The timestamp can also be created manually as per RFC 9562: /// /// ``` /// # use uuid::{Uuid, Timestamp, Context, ClockSequence}; /// let context = Context::new(42); /// let ts = Timestamp::from_gregorian(14976234442241191232, context.generate_sequence(0, 0)); /// /// let uuid = Uuid::new_v1(ts, &[1, 2, 3, 4, 5, 6]); /// /// assert_eq!( /// uuid.hyphenated().to_string(), /// "b2c1ad40-45e0-1fd6-802a-010203040506" /// ); /// ``` /// /// # References /// /// * [UUID Version 1 in RFC 9562](https://www.ietf.org/rfc/rfc9562.html#section-5.1) /// /// [`Timestamp`]: v1/struct.Timestamp.html /// [`ClockSequence`]: v1/trait.ClockSequence.html /// [`Context`]: v1/struct.Context.html pub fn new_v1(ts: Timestamp, node_id: &[u8; 6]) -> Self { let (ticks, counter) = ts.to_gregorian(); Builder::from_gregorian_timestamp(ticks, counter, node_id).into_uuid() } } #[cfg(test)] mod tests { use super::*; use crate::{std::string::ToString, Variant, Version}; #[cfg(all( target_arch = "wasm32", target_vendor = "unknown", target_os = "unknown" ))] use wasm_bindgen_test::*; #[test] #[cfg_attr( all( target_arch = "wasm32", target_vendor = "unknown", target_os = "unknown" ), wasm_bindgen_test )] fn test_new() { let time: u64 = 1_496_854_535; let time_fraction: u32 = 812_946_000; let node = [1, 2, 3, 4, 5, 6]; let context = Context::new(0); let uuid = Uuid::new_v1(Timestamp::from_unix(&context, time, time_fraction), &node); assert_eq!(uuid.get_version(), Some(Version::Mac)); assert_eq!(uuid.get_variant(), Variant::RFC4122); assert_eq!( uuid.hyphenated().to_string(), "20616934-4ba2-11e7-8000-010203040506" ); let ts = uuid.get_timestamp().unwrap().to_gregorian(); assert_eq!(ts.0 - 0x01B2_1DD2_1381_4000, 14_968_545_358_129_460); assert_eq!(Some(node), uuid.get_node_id(),); // Ensure parsing the same UUID produces the same timestamp let parsed = Uuid::parse_str("20616934-4ba2-11e7-8000-010203040506").unwrap(); assert_eq!( uuid.get_timestamp().unwrap(), parsed.get_timestamp().unwrap() ); assert_eq!(uuid.get_node_id().unwrap(), parsed.get_node_id().unwrap(),); } #[test] #[cfg_attr( all( target_arch = "wasm32", target_vendor = "unknown", target_os = "unknown" ), wasm_bindgen_test )] #[cfg(all(feature = "std", feature = "rng"))] fn test_now() { let node = [1, 2, 3, 4, 5, 6]; let uuid = Uuid::now_v1(&node); assert_eq!(uuid.get_version(), Some(Version::Mac)); assert_eq!(uuid.get_variant(), Variant::RFC4122); } } uuid-1.10.0/src/v3.rs000064400000000000000000000111731046102023000123410ustar 00000000000000use crate::Uuid; impl Uuid { /// Creates a UUID using a name from a namespace, based on the MD5 /// hash. /// /// A number of namespaces are available as constants in this crate: /// /// * [`NAMESPACE_DNS`] /// * [`NAMESPACE_OID`] /// * [`NAMESPACE_URL`] /// * [`NAMESPACE_X500`] /// /// Note that usage of this method requires the `v3` feature of this crate /// to be enabled. /// /// # Examples /// /// Generating a MD5 DNS UUID for `rust-lang.org`: /// /// ``` /// # use uuid::{Uuid, Version}; /// let uuid = Uuid::new_v3(&Uuid::NAMESPACE_DNS, b"rust-lang.org"); /// /// assert_eq!(Some(Version::Md5), uuid.get_version()); /// ``` /// /// # References /// /// * [UUID Version 3 in RFC 9562](https://www.ietf.org/rfc/rfc9562.html#section-5.3) /// * [Name-Based UUID Generation in RFC 9562](https://www.ietf.org/rfc/rfc9562.html#section-6.5) /// /// [`NAMESPACE_DNS`]: #associatedconstant.NAMESPACE_DNS /// [`NAMESPACE_OID`]: #associatedconstant.NAMESPACE_OID /// [`NAMESPACE_URL`]: #associatedconstant.NAMESPACE_URL /// [`NAMESPACE_X500`]: #associatedconstant.NAMESPACE_X500 pub fn new_v3(namespace: &Uuid, name: &[u8]) -> Uuid { crate::Builder::from_md5_bytes(crate::md5::hash(namespace.as_bytes(), name)).into_uuid() } } #[cfg(test)] mod tests { use super::*; #[cfg(all( target_arch = "wasm32", target_vendor = "unknown", target_os = "unknown" ))] use wasm_bindgen_test::*; use crate::{std::string::ToString, Variant, Version}; static FIXTURE: &'static [(&'static Uuid, &'static str, &'static str)] = &[ ( &Uuid::NAMESPACE_DNS, "example.org", "04738bdf-b25a-3829-a801-b21a1d25095b", ), ( &Uuid::NAMESPACE_DNS, "rust-lang.org", "c6db027c-615c-3b4d-959e-1a917747ca5a", ), ( &Uuid::NAMESPACE_DNS, "42", "5aab6e0c-b7d3-379c-92e3-2bfbb5572511", ), ( &Uuid::NAMESPACE_DNS, "lorem ipsum", "4f8772e9-b59c-3cc9-91a9-5c823df27281", ), ( &Uuid::NAMESPACE_URL, "example.org", "39682ca1-9168-3da2-a1bb-f4dbcde99bf9", ), ( &Uuid::NAMESPACE_URL, "rust-lang.org", "7ed45aaf-e75b-3130-8e33-ee4d9253b19f", ), ( &Uuid::NAMESPACE_URL, "42", "08998a0c-fcf4-34a9-b444-f2bfc15731dc", ), ( &Uuid::NAMESPACE_URL, "lorem ipsum", "e55ad2e6-fb89-34e8-b012-c5dde3cd67f0", ), ( &Uuid::NAMESPACE_OID, "example.org", "f14eec63-2812-3110-ad06-1625e5a4a5b2", ), ( &Uuid::NAMESPACE_OID, "rust-lang.org", "6506a0ec-4d79-3e18-8c2b-f2b6b34f2b6d", ), ( &Uuid::NAMESPACE_OID, "42", "ce6925a5-2cd7-327b-ab1c-4b375ac044e4", ), ( &Uuid::NAMESPACE_OID, "lorem ipsum", "5dd8654f-76ba-3d47-bc2e-4d6d3a78cb09", ), ( &Uuid::NAMESPACE_X500, "example.org", "64606f3f-bd63-363e-b946-fca13611b6f7", ), ( &Uuid::NAMESPACE_X500, "rust-lang.org", "bcee7a9c-52f1-30c6-a3cc-8c72ba634990", ), ( &Uuid::NAMESPACE_X500, "42", "c1073fa2-d4a6-3104-b21d-7a6bdcf39a23", ), ( &Uuid::NAMESPACE_X500, "lorem ipsum", "02f09a3f-1624-3b1d-8409-44eff7708208", ), ]; #[test] #[cfg_attr( all( target_arch = "wasm32", target_vendor = "unknown", target_os = "unknown" ), wasm_bindgen_test )] fn test_new() { for &(ref ns, ref name, _) in FIXTURE { let uuid = Uuid::new_v3(*ns, name.as_bytes()); assert_eq!(uuid.get_version(), Some(Version::Md5)); assert_eq!(uuid.get_variant(), Variant::RFC4122); } } #[test] #[cfg_attr( all( target_arch = "wasm32", target_vendor = "unknown", target_os = "unknown" ), wasm_bindgen_test )] fn test_hyphenated_string() { for &(ref ns, ref name, ref expected) in FIXTURE { let uuid = Uuid::new_v3(*ns, name.as_bytes()); assert_eq!(uuid.hyphenated().to_string(), *expected); } } } uuid-1.10.0/src/v4.rs000064400000000000000000000044611046102023000123440ustar 00000000000000use crate::Uuid; impl Uuid { /// Creates a random UUID. /// /// This uses the [`getrandom`] crate to utilise the operating system's RNG /// as the source of random numbers. If you'd like to use a custom /// generator, don't use this method: generate random bytes using your /// custom generator and pass them to the /// [`uuid::Builder::from_random_bytes`][from_random_bytes] function /// instead. /// /// Note that usage of this method requires the `v4` feature of this crate /// to be enabled. /// /// # Examples /// /// Basic usage: /// /// ``` /// # use uuid::{Uuid, Version}; /// let uuid = Uuid::new_v4(); /// /// assert_eq!(Some(Version::Random), uuid.get_version()); /// ``` /// /// # References /// /// * [UUID Version 4 in RFC 9562](https://www.ietf.org/rfc/rfc9562.html#section-5.4) /// /// [`getrandom`]: https://crates.io/crates/getrandom /// [from_random_bytes]: struct.Builder.html#method.from_random_bytes pub fn new_v4() -> Uuid { // This is an optimized method for generating random UUIDs that just masks // out the bits for the version and variant and sets them both together Uuid::from_u128( crate::rng::u128() & 0xFFFFFFFFFFFF4FFFBFFFFFFFFFFFFFFF | 0x40008000000000000000, ) } } #[cfg(test)] mod tests { use super::*; use crate::{Variant, Version}; #[cfg(all( target_arch = "wasm32", target_vendor = "unknown", target_os = "unknown" ))] use wasm_bindgen_test::*; #[test] #[cfg_attr( all( target_arch = "wasm32", target_vendor = "unknown", target_os = "unknown" ), wasm_bindgen_test )] fn test_new() { let uuid = Uuid::new_v4(); assert_eq!(uuid.get_version(), Some(Version::Random)); assert_eq!(uuid.get_variant(), Variant::RFC4122); } #[test] #[cfg_attr( all( target_arch = "wasm32", target_vendor = "unknown", target_os = "unknown" ), wasm_bindgen_test )] fn test_get_version() { let uuid = Uuid::new_v4(); assert_eq!(uuid.get_version(), Some(Version::Random)); assert_eq!(uuid.get_version_num(), 4) } } uuid-1.10.0/src/v5.rs000064400000000000000000000121761046102023000123470ustar 00000000000000use crate::Uuid; impl Uuid { /// Creates a UUID using a name from a namespace, based on the SHA-1 hash. /// /// A number of namespaces are available as constants in this crate: /// /// * [`NAMESPACE_DNS`] /// * [`NAMESPACE_OID`] /// * [`NAMESPACE_URL`] /// * [`NAMESPACE_X500`] /// /// Note that usage of this method requires the `v5` feature of this crate /// to be enabled. /// /// # Examples /// /// Generating a SHA1 DNS UUID for `rust-lang.org`: /// /// ``` /// # use uuid::{Uuid, Version}; /// let uuid = Uuid::new_v5(&Uuid::NAMESPACE_DNS, b"rust-lang.org"); /// /// assert_eq!(Some(Version::Sha1), uuid.get_version()); /// ``` /// /// # References /// /// * [UUID Version 5 in RFC 9562](https://www.ietf.org/rfc/rfc9562.html#section-5.5) /// * [Name-Based UUID Generation in RFC 9562](https://www.ietf.org/rfc/rfc9562.html#section-6.5) /// /// [`NAMESPACE_DNS`]: struct.Uuid.html#associatedconst.NAMESPACE_DNS /// [`NAMESPACE_OID`]: struct.Uuid.html#associatedconst.NAMESPACE_OID /// [`NAMESPACE_URL`]: struct.Uuid.html#associatedconst.NAMESPACE_URL /// [`NAMESPACE_X500`]: struct.Uuid.html#associatedconst.NAMESPACE_X500 pub fn new_v5(namespace: &Uuid, name: &[u8]) -> Uuid { crate::Builder::from_sha1_bytes(crate::sha1::hash(namespace.as_bytes(), name)).into_uuid() } } #[cfg(test)] mod tests { use super::*; #[cfg(all( target_arch = "wasm32", target_vendor = "unknown", target_os = "unknown" ))] use wasm_bindgen_test::*; use crate::{std::string::ToString, Variant, Version}; static FIXTURE: &'static [(&'static Uuid, &'static str, &'static str)] = &[ ( &Uuid::NAMESPACE_DNS, "example.org", "aad03681-8b63-5304-89e0-8ca8f49461b5", ), ( &Uuid::NAMESPACE_DNS, "rust-lang.org", "c66bbb60-d62e-5f17-a399-3a0bd237c503", ), ( &Uuid::NAMESPACE_DNS, "42", "7c411b5e-9d3f-50b5-9c28-62096e41c4ed", ), ( &Uuid::NAMESPACE_DNS, "lorem ipsum", "97886a05-8a68-5743-ad55-56ab2d61cf7b", ), ( &Uuid::NAMESPACE_URL, "example.org", "54a35416-963c-5dd6-a1e2-5ab7bb5bafc7", ), ( &Uuid::NAMESPACE_URL, "rust-lang.org", "c48d927f-4122-5413-968c-598b1780e749", ), ( &Uuid::NAMESPACE_URL, "42", "5c2b23de-4bad-58ee-a4b3-f22f3b9cfd7d", ), ( &Uuid::NAMESPACE_URL, "lorem ipsum", "15c67689-4b85-5253-86b4-49fbb138569f", ), ( &Uuid::NAMESPACE_OID, "example.org", "34784df9-b065-5094-92c7-00bb3da97a30", ), ( &Uuid::NAMESPACE_OID, "rust-lang.org", "8ef61ecb-977a-5844-ab0f-c25ef9b8d5d6", ), ( &Uuid::NAMESPACE_OID, "42", "ba293c61-ad33-57b9-9671-f3319f57d789", ), ( &Uuid::NAMESPACE_OID, "lorem ipsum", "6485290d-f79e-5380-9e64-cb4312c7b4a6", ), ( &Uuid::NAMESPACE_X500, "example.org", "e3635e86-f82b-5bbc-a54a-da97923e5c76", ), ( &Uuid::NAMESPACE_X500, "rust-lang.org", "26c9c3e9-49b7-56da-8b9f-a0fb916a71a3", ), ( &Uuid::NAMESPACE_X500, "42", "e4b88014-47c6-5fe0-a195-13710e5f6e27", ), ( &Uuid::NAMESPACE_X500, "lorem ipsum", "b11f79a5-1e6d-57ce-a4b5-ba8531ea03d0", ), ]; #[test] #[cfg_attr( all( target_arch = "wasm32", target_vendor = "unknown", target_os = "unknown" ), wasm_bindgen_test )] fn test_get_version() { let uuid = Uuid::new_v5(&Uuid::NAMESPACE_DNS, "rust-lang.org".as_bytes()); assert_eq!(uuid.get_version(), Some(Version::Sha1)); assert_eq!(uuid.get_version_num(), 5); } #[test] #[cfg_attr( all( target_arch = "wasm32", target_vendor = "unknown", target_os = "unknown" ), wasm_bindgen_test )] fn test_hyphenated() { for &(ref ns, ref name, ref expected) in FIXTURE { let uuid = Uuid::new_v5(*ns, name.as_bytes()); assert_eq!(uuid.hyphenated().to_string(), *expected) } } #[test] #[cfg_attr( all( target_arch = "wasm32", target_vendor = "unknown", target_os = "unknown" ), wasm_bindgen_test )] fn test_new() { for &(ref ns, ref name, ref u) in FIXTURE { let uuid = Uuid::new_v5(*ns, name.as_bytes()); assert_eq!(uuid.get_version(), Some(Version::Sha1)); assert_eq!(uuid.get_variant(), Variant::RFC4122); assert_eq!(Ok(uuid), u.parse()); } } } uuid-1.10.0/src/v6.rs000064400000000000000000000130721046102023000123440ustar 00000000000000//! The implementation for Version 6 UUIDs. //! //! Note that you need to enable the `v6` Cargo feature //! in order to use this module. use crate::{Builder, Timestamp, Uuid}; impl Uuid { /// Create a new version 6 UUID using the current system time and node ID. /// /// This method is only available if the `std` feature is enabled. /// /// This method is a convenient alternative to [`Uuid::new_v6`] that uses the current system time /// as the source timestamp. /// /// Note that usage of this method requires the `v6`, `std`, and `rng` features of this crate /// to be enabled. #[cfg(all(feature = "std", feature = "rng"))] pub fn now_v6(node_id: &[u8; 6]) -> Self { let ts = Timestamp::now(crate::timestamp::context::shared_context()); Self::new_v6(ts, node_id) } /// Create a new version 6 UUID using the given timestamp and a node ID. /// /// This is similar to version 1 UUIDs, except that it is lexicographically sortable by timestamp. /// /// Also see [`Uuid::now_v6`] for a convenient way to generate version 6 /// UUIDs using the current system time. /// /// When generating [`Timestamp`]s using a [`ClockSequence`], this function /// is only guaranteed to produce unique values if the following conditions /// hold: /// /// 1. The *node ID* is unique for this process, /// 2. The *context* is shared across all threads which are generating version 6 /// UUIDs, /// 3. The [`ClockSequence`] implementation reliably returns unique /// clock sequences (this crate provides [`Context`] for this /// purpose. However you can create your own [`ClockSequence`] /// implementation, if [`Context`] does not meet your needs). /// /// The NodeID must be exactly 6 bytes long. /// /// Note that usage of this method requires the `v6` feature of this crate /// to be enabled. /// /// # Examples /// /// A UUID can be created from a unix [`Timestamp`] with a /// [`ClockSequence`]. RFC 9562 requires the clock sequence /// is seeded with a random value: /// /// ```rust /// # use uuid::{Uuid, Timestamp, Context}; /// # fn random_seed() -> u16 { 42 } /// let context = Context::new(random_seed()); /// let ts = Timestamp::from_unix(context, 1497624119, 1234); /// /// let uuid = Uuid::new_v6(ts, &[1, 2, 3, 4, 5, 6]); /// /// assert_eq!( /// uuid.hyphenated().to_string(), /// "1e752a1f-3b49-658c-802a-010203040506" /// ); /// ``` /// /// The timestamp can also be created manually as per RFC 9562: /// /// ``` /// # use uuid::{Uuid, Timestamp, Context, ClockSequence}; /// # fn random_seed() -> u16 { 42 } /// let context = Context::new(random_seed()); /// let ts = Timestamp::from_gregorian(14976241191231231313, context.generate_sequence(0, 0)); /// /// let uuid = Uuid::new_v6(ts, &[1, 2, 3, 4, 5, 6]); /// /// assert_eq!( /// uuid.hyphenated().to_string(), /// "fd64c041-1e91-6551-802a-010203040506" /// ); /// ``` /// /// # References /// /// * [UUID Version 6 in RFC 9562](https://www.ietf.org/rfc/rfc9562.html#section-5.6) /// /// [`Timestamp`]: timestamp/struct.Timestamp.html /// [`ClockSequence`]: timestamp/trait.ClockSequence.html /// [`Context`]: timestamp/context/struct.Context.html pub fn new_v6(ts: Timestamp, node_id: &[u8; 6]) -> Self { let (ticks, counter) = ts.to_gregorian(); Builder::from_sorted_gregorian_timestamp(ticks, counter, node_id).into_uuid() } } #[cfg(test)] mod tests { use super::*; use crate::{Context, Variant, Version}; use std::string::ToString; #[cfg(all( target_arch = "wasm32", target_vendor = "unknown", target_os = "unknown" ))] use wasm_bindgen_test::*; #[test] #[cfg_attr( all( target_arch = "wasm32", target_vendor = "unknown", target_os = "unknown" ), wasm_bindgen_test )] fn test_new() { let time: u64 = 1_496_854_535; let time_fraction: u32 = 812_946_000; let node = [1, 2, 3, 4, 5, 6]; let context = Context::new(0); let uuid = Uuid::new_v6(Timestamp::from_unix(context, time, time_fraction), &node); assert_eq!(uuid.get_version(), Some(Version::SortMac)); assert_eq!(uuid.get_variant(), Variant::RFC4122); assert_eq!( uuid.hyphenated().to_string(), "1e74ba22-0616-6934-8000-010203040506" ); let ts = uuid.get_timestamp().unwrap().to_gregorian(); assert_eq!(ts.0 - 0x01B2_1DD2_1381_4000, 14_968_545_358_129_460); assert_eq!(Some(node), uuid.get_node_id(),); // Ensure parsing the same UUID produces the same timestamp let parsed = Uuid::parse_str("1e74ba22-0616-6934-8000-010203040506").unwrap(); assert_eq!( uuid.get_timestamp().unwrap(), parsed.get_timestamp().unwrap() ); assert_eq!(uuid.get_node_id().unwrap(), parsed.get_node_id().unwrap(),); } #[test] #[cfg_attr( all( target_arch = "wasm32", target_vendor = "unknown", target_os = "unknown" ), wasm_bindgen_test )] #[cfg(all(feature = "std", feature = "rng"))] fn test_now() { let node = [1, 2, 3, 4, 5, 6]; let uuid = Uuid::now_v6(&node); assert_eq!(uuid.get_version(), Some(Version::SortMac)); assert_eq!(uuid.get_variant(), Variant::RFC4122); } } uuid-1.10.0/src/v7.rs000064400000000000000000000157671046102023000123620ustar 00000000000000//! The implementation for Version 7 UUIDs. //! //! Note that you need to enable the `v7` Cargo feature //! in order to use this module. use crate::{rng, std::convert::TryInto, timestamp::Timestamp, Builder, Uuid}; impl Uuid { /// Create a new version 7 UUID using the current time value. /// /// This method is a convenient alternative to [`Uuid::new_v7`] that uses the current system time /// as the source timestamp. All UUIDs generated through this method by the same process are /// guaranteed to be ordered by their creation. #[cfg(feature = "std")] pub fn now_v7() -> Self { Self::new_v7(Timestamp::now( crate::timestamp::context::shared_context_v7(), )) } /// Create a new version 7 UUID using a time value and random bytes. /// /// When the `std` feature is enabled, you can also use [`Uuid::now_v7`]. /// /// Note that usage of this method requires the `v7` feature of this crate /// to be enabled. /// /// Also see [`Uuid::now_v7`] for a convenient way to generate version 7 /// UUIDs using the current system time. /// /// # Examples /// /// A v7 UUID can be created from a unix [`Timestamp`] plus a 128 bit /// random number. When supplied as such, the data will be /// /// ```rust /// # use uuid::{Uuid, Timestamp, NoContext}; /// let ts = Timestamp::from_unix(NoContext, 1497624119, 1234); /// /// let uuid = Uuid::new_v7(ts); /// /// assert!( /// uuid.hyphenated().to_string().starts_with("015cb15a-86d8-7") /// ); /// ``` /// /// A v7 UUID can also be created with a counter to ensure batches of /// UUIDs created together remain sortable: /// /// ```rust /// # use uuid::{Uuid, Timestamp, ContextV7}; /// let context = ContextV7::new(); /// let uuid1 = Uuid::new_v7(Timestamp::from_unix(&context, 1497624119, 1234)); /// let uuid2 = Uuid::new_v7(Timestamp::from_unix(&context, 1497624119, 1234)); /// /// assert!(uuid1 < uuid2); /// ``` /// /// # References /// /// * [UUID Version 7 in RFC 9562](https://www.ietf.org/rfc/rfc9562.html#section-5.7) pub fn new_v7(ts: Timestamp) -> Self { let (secs, nanos) = ts.to_unix(); let millis = (secs * 1000).saturating_add(nanos as u64 / 1_000_000); let mut counter_and_random = rng::u128(); let (mut counter, counter_bits) = ts.counter(); debug_assert!(counter_bits <= 128); let mut counter_bits = counter_bits as u32; // If the counter intersects the variant field then shift around it. // This ensures that any bits set in the counter that would intersect // the variant are still preserved if counter_bits > 12 { let mask = u128::MAX << (counter_bits - 12); counter = (counter & !mask) | ((counter & mask) << 2); counter_bits += 2; } counter_and_random &= u128::MAX.overflowing_shr(counter_bits).0; counter_and_random |= counter .overflowing_shl(128u32.saturating_sub(counter_bits)) .0; Builder::from_unix_timestamp_millis( millis, &counter_and_random.to_be_bytes()[..10].try_into().unwrap(), ) .into_uuid() } } #[cfg(test)] mod tests { use super::*; use crate::{std::string::ToString, ClockSequence, NoContext, Variant, Version}; #[cfg(all( target_arch = "wasm32", target_vendor = "unknown", target_os = "unknown" ))] use wasm_bindgen_test::*; #[test] #[cfg_attr( all( target_arch = "wasm32", target_vendor = "unknown", target_os = "unknown" ), wasm_bindgen_test )] fn test_new() { let ts: u64 = 1645557742000; let seconds = ts / 1000; let nanos = ((ts % 1000) * 1_000_000) as u32; let uuid = Uuid::new_v7(Timestamp::from_unix(NoContext, seconds, nanos)); let uustr = uuid.hyphenated().to_string(); assert_eq!(uuid.get_version(), Some(Version::SortRand)); assert_eq!(uuid.get_variant(), Variant::RFC4122); assert!(uuid.hyphenated().to_string().starts_with("017f22e2-79b0-7")); // Ensure parsing the same UUID produces the same timestamp let parsed = Uuid::parse_str(uustr.as_str()).unwrap(); assert_eq!(uuid, parsed); } #[test] #[cfg_attr( all( target_arch = "wasm32", target_vendor = "unknown", target_os = "unknown" ), wasm_bindgen_test )] #[cfg(feature = "std")] fn test_now() { let uuid = Uuid::now_v7(); assert_eq!(uuid.get_version(), Some(Version::SortRand)); assert_eq!(uuid.get_variant(), Variant::RFC4122); } #[test] #[cfg_attr( all( target_arch = "wasm32", target_vendor = "unknown", target_os = "unknown" ), wasm_bindgen_test )] fn test_sorting() { let time1: u64 = 1_496_854_535; let time_fraction1: u32 = 812_000_000; let time2 = time1 + 4000; let time_fraction2 = time_fraction1; let uuid1 = Uuid::new_v7(Timestamp::from_unix(NoContext, time1, time_fraction1)); let uuid2 = Uuid::new_v7(Timestamp::from_unix(NoContext, time2, time_fraction2)); assert!(uuid1.as_bytes() < uuid2.as_bytes()); assert!(uuid1.to_string() < uuid2.to_string()); } #[test] #[cfg_attr( all( target_arch = "wasm32", target_vendor = "unknown", target_os = "unknown" ), wasm_bindgen_test )] fn test_new_timestamp_roundtrip() { let time: u64 = 1_496_854_535; let time_fraction: u32 = 812_000_000; let ts = Timestamp::from_unix(NoContext, time, time_fraction); let uuid = Uuid::new_v7(ts); let decoded_ts = uuid.get_timestamp().unwrap(); assert_eq!(ts.to_unix(), decoded_ts.to_unix()); } #[test] #[cfg_attr( all( target_arch = "wasm32", target_vendor = "unknown", target_os = "unknown" ), wasm_bindgen_test )] fn test_new_max_context() { struct MaxContext; #[cfg(test)] impl ClockSequence for MaxContext { type Output = u128; fn generate_sequence(&self, _seconds: u64, _nanos: u32) -> Self::Output { u128::MAX } fn usable_bits(&self) -> usize { 128 } } let time: u64 = 1_496_854_535; let time_fraction: u32 = 812_000_000; // Ensure we don't overflow here let ts = Timestamp::from_unix(MaxContext, time, time_fraction); let uuid = Uuid::new_v7(ts); assert_eq!(uuid.get_version(), Some(Version::SortRand)); assert_eq!(uuid.get_variant(), Variant::RFC4122); let decoded_ts = uuid.get_timestamp().unwrap(); assert_eq!(ts.to_unix(), decoded_ts.to_unix()); } } uuid-1.10.0/src/v8.rs000064400000000000000000000035741046102023000123540ustar 00000000000000use crate::{Builder, Uuid}; impl Uuid { /// Creates a custom UUID comprised almost entirely of user-supplied bytes. /// /// This will inject the UUID Version at 4 bits starting at the 48th bit /// and the Variant into 2 bits 64th bit. Any existing bits in the user-supplied bytes /// at those locations will be overridden. /// /// Note that usage of this method requires the `v8` feature of this crate /// to be enabled. /// /// # Examples /// /// Basic usage: /// /// ``` /// # use uuid::{Uuid, Version}; /// let buf: [u8; 16] = *b"abcdefghijklmnop"; /// let uuid = Uuid::new_v8(buf); /// /// assert_eq!(Some(Version::Custom), uuid.get_version()); /// ``` /// /// # References /// /// * [UUID Version 8 in RFC 9562](https://www.ietf.org/rfc/rfc9562.html#section-5.8) pub fn new_v8(buf: [u8; 16]) -> Uuid { Builder::from_custom_bytes(buf).into_uuid() } } #[cfg(test)] mod tests { use super::*; use crate::{Variant, Version}; use std::string::ToString; #[cfg(all( target_arch = "wasm32", target_vendor = "unknown", target_os = "unknown" ))] use wasm_bindgen_test::*; #[test] #[cfg_attr( all( target_arch = "wasm32", target_vendor = "unknown", target_os = "unknown" ), wasm_bindgen_test )] fn test_new() { let buf: [u8; 16] = [ 0xf, 0xe, 0xd, 0xc, 0xb, 0xa, 0x9, 0x8, 0x7, 0x6, 0x5, 0x4, 0x3, 0x2, 0x1, 0x0, ]; let uuid = Uuid::new_v8(buf); assert_eq!(uuid.get_version(), Some(Version::Custom)); assert_eq!(uuid.get_variant(), Variant::RFC4122); assert_eq!(uuid.get_version_num(), 8); assert_eq!( uuid.hyphenated().to_string(), "0f0e0d0c-0b0a-8908-8706-050403020100" ); } }