diff options
Diffstat (limited to 'third_party/rust/uuid')
34 files changed, 5251 insertions, 0 deletions
diff --git a/third_party/rust/uuid/.cargo-checksum.json b/third_party/rust/uuid/.cargo-checksum.json new file mode 100644 index 0000000000..64e293cef3 --- /dev/null +++ b/third_party/rust/uuid/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"CODEOWNERS":"65d3fcb4156a2d5bce80d382a34044753e384d7f1eb71cdc646de400a0b969c8","CODE_OF_CONDUCT.md":"7d9c9062ee835c2dfd348cfddb938c563f3a7b1140dd090444a03ea1d73626b1","CONTRIBUTING.md":"c2b507733d5af2de972d63237a094a135935ad45cc74dedb79c199d841f35a3e","COPYRIGHT":"b4b2c0de2a05de3372d5c828128413ce82bb7dba2272487b7729f09cc3d3519d","Cargo.toml":"94e4df2b560d316a5dbadb38bd95e338d82504f3a7e0d8bf4a98ab33bd12d54b","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"436bc5a105d8e57dcd8778730f3754f7bf39c14d2f530e4cde4bd2d17a83ec3d","README.md":"a58d1918e2e0e9d2c5ae50ebc21c79e52227f3e012f45e7932a2c67d554ee641","README.tpl":"5e94c2dfce3f674229cc3326873da36d94f9592a213d7785b3dfbde9b23ca27f","benches/format_str.rs":"d8cbdcc43d5b78f1674cbdfb4ab7917e110e0e92d91eaa1b0419de1fe38cb4a3","benches/invalid_parse_str.rs":"c1ed6e57b6d7078d698e7301cd05f2ce272acea9856bfb43683bec9b8984ff11","benches/mod.rs":"48b2b66f176d37f207336e2eb074d39273376e24dff30bf375491f8a4532219b","benches/serde_support.rs":"4d051017a7de4d54d5afe5cd33ab97fc725a76e21fdea0f3e3b1efd32afc3f16","benches/slog_support/mod.rs":"26031e0f77ff53fbdf85f519c65e3acdde44971841a2a637fa6b2c4ec0d1b13e","benches/slog_support/parse_str.rs":"b520e1f43baedba95d6d60e184dc4300e8c272b2ad4bf779b357c392c3d319e4","benches/valid_parse_str.rs":"4a8c28d721455ecd9de9c780d421740508e456d545a7ca42fda8909ae3ffb110","src/adapter/compact.rs":"018c02bc2b7f34d669eacff6e00c87cb7a73c8498f0a0927b0ac0f6c95cc23f6","src/adapter/mod.rs":"86124a0ac594f46911bf5197dfef0887964760e90136c0effa3656e5dc2179e9","src/builder/error.rs":"ab2d652a5897cf108dedde0de00776140d4eaaaee81922bcf0310edcabbdfdc1","src/builder/mod.rs":"a9a980bc120d39ffddd598259a2e9c32ceb7c8885e948c1efe73d634601e6873","src/error.rs":"3a1a6d9109f526dc10ccc7e63738ec500d0c0a063dd3322413878474a15e5e9f","src/lib.rs":"5b9200da120444062202ef247c087995328efeb9b27ba6dce0f4026ea91fff79","src/parser/error.rs":"ec136a5497017402797784053f127c4812f126a7f43053624446c4deb301b9a8","src/parser/mod.rs":"39605f6897298df0cd1dc543c7bd735eea369936e5d30d908851fab1d5c014dd","src/prelude.rs":"351f692d433ac98164123413fe2b0a37c8781aeb9680fb2bd7108a833b9e0123","src/serde_support.rs":"3b15f0594db978d6b10dcb27ed5c56956207dd682d7d7e02b262e27916c63941","src/slog_support.rs":"88be60521752f0185256815d9a494a1d2a68f2e5f28910da7a753196ff18d4e2","src/test_util.rs":"2a6b9d22241a8ab598adb6d7634f29c5ab8c575e67a89f261eb45c9df322127b","src/v1.rs":"b2427f37f9a7d6afc226b32179ced8a16c239283cfae89b5eb6ac52ca1fddebb","src/v3.rs":"1ed2ed955feab877944b445eed1638050d4e97a49e1f2954d00d5935454f1269","src/v4.rs":"25715d366c8082d59449654ceaad52814ce8c11f991ca3e88b950837da0e73b5","src/v5.rs":"5acae85b24d6bcf368ee09f07d08fc47f44f9cbae83ff49a6dee1bde8a55a20e","src/winapi_support.rs":"c84279fca11326b6dfe3db823c7b054f697bcbcabea9f4dafcaf822620415d70"},"package":"9fde2f6a4bea1d6e007c4ad38c6839fa71cbb63b6dbf5b595aa38dc9b1093c11"}
\ No newline at end of file diff --git a/third_party/rust/uuid/CODEOWNERS b/third_party/rust/uuid/CODEOWNERS new file mode 100644 index 0000000000..f20b6886d1 --- /dev/null +++ b/third_party/rust/uuid/CODEOWNERS @@ -0,0 +1,16 @@ +# CI +.travis.yml @kinggoesgaming @KodrAus @Dylan-DPC @radix +appveyor.yml @kinggoesgaming @KodrAus @Dylan-DPC @radix + +# Cargo.toml +Cargo.toml @kinggoesgaming @KodrAus @Dylan-DPC @radix + +# Rust +*.rs @kinggoesgaming @KodrAus @Dylan-DPC @radix + +# CODEOWNERS +CODEOWNERS @kinggoesgaming @KodrAus @Dylan-DPC @radix + +#>> Critical +# bors.toml file +bors.toml @kinggoesgaming @KodrAus @Dylan-DPC @radix diff --git a/third_party/rust/uuid/CODE_OF_CONDUCT.md b/third_party/rust/uuid/CODE_OF_CONDUCT.md new file mode 100644 index 0000000000..7f5c4feae9 --- /dev/null +++ b/third_party/rust/uuid/CODE_OF_CONDUCT.md @@ -0,0 +1,77 @@ +# Contributor Covenant Code of Conduct + +The latest version of the CODE OF CONDUCT can be found [here]. + +[here]: https://github.com/uuid-rs/conduct + +## Our Pledge + +In the interest of fostering an open and welcoming environment, we as +contributors and maintainers pledge to making participation in our project and +our community a harassment-free experience for everyone, regardless of age, body +size, disability, ethnicity, gender identity and expression, level of experience, +education, socio-economic status, nationality, personal appearance, race, +religion, or sexual identity and orientation. + +## Our Standards + +Examples of behavior that contributes to creating a positive environment +include: + +* Using welcoming and inclusive language +* Being respectful of differing viewpoints and experiences +* Gracefully accepting constructive criticism +* Focusing on what is best for the community +* Showing empathy towards other community members + +Examples of unacceptable behavior by participants include: + +* The use of sexualized language or imagery and unwelcome sexual attention or + advances +* Trolling, insulting/derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or electronic + address, without explicit permission +* Other conduct which could reasonably be considered inappropriate in a + professional setting + +## Our Responsibilities + +Project maintainers are responsible for clarifying the standards of acceptable +behavior and are expected to take appropriate and fair corrective action in +response to any instances of unacceptable behavior. + +Project maintainers have the right and responsibility to remove, edit, or +reject comments, commits, code, wiki edits, issues, and other contributions +that are not aligned to this Code of Conduct, or to ban temporarily or +permanently any contributor for other behaviors that they deem inappropriate, +threatening, offensive, or harmful. + +## Scope + +This Code of Conduct applies both within project spaces and in public spaces +when an individual is representing the project or its community. Examples of +representing a project or community include using an official project e-mail +address, posting via an official social media account, or acting as an appointed +representative at an online or offline event. Representation of a project may be +further defined and clarified by project maintainers. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported by contacting the project team at report@uuid-rs.groups.io. All +complaints will be reviewed and investigated and will result in a response that +is deemed necessary and appropriate to the circumstances. The project team is +obligated to maintain confidentiality with regard to the reporter of an incident. +Further details of specific enforcement policies may be posted separately. + +Project maintainers who do not follow or enforce the Code of Conduct in good +faith may face temporary or permanent repercussions as determined by other +members of the project's leadership. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, +available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html + +[homepage]: https://www.contributor-covenant.org
\ No newline at end of file diff --git a/third_party/rust/uuid/CONTRIBUTING.md b/third_party/rust/uuid/CONTRIBUTING.md new file mode 100644 index 0000000000..2bd9f87b30 --- /dev/null +++ b/third_party/rust/uuid/CONTRIBUTING.md @@ -0,0 +1,149 @@ +Contributing to Uuid +--- +[Contributing to Uuid]: #contributing-to-uuid + +Thank you for your interest in contributing to the Uuid Project! + +* [Feature Requests](#feature-requests) +* [Bug Reports](#bug-reports) +* [Pull Requests](#pull-requests) +* [Writing Documentation](#writing-documentation) +* [Issue Triage](#issue-triage) +* [Out-of-tree Contributions](#out-of-tree-contributions) +* [Helpful Links](#helpful-links) + +For any questions, please make a post on [users.rust-lang.org][u-r-l-o], post +on [uuid-rs mailing list] or join our [gitter] channel. + +> All contributors need to follow our [Code of Conduct]. + +[Code of Conduct]: CODE_OF_CONDUCT.md + +# Feature Requests +[Feature Requests]: #feature-requests + +The `uuid` crate is still in flux. All features desired may not be present. As +such you are welcome to request for new features. Keep in mind that `uuid` is +a general purpose library. We want to provide features that most users would +find useful. As such not every feature may be accepted. + +If you have the chance, please [search existing issues], as there is a chance +that someone has already requested your feature. + +File your feature request with a descriptive title, as this helps others find +your request. + +You can request your feature by following [this link][Feature Request Link] and +filling it in. + +> We welcome pull requests for your own feature requests, provided they have +been discussed. + +[Feature Request Link]: https://github.com/uuid-rs/uuid/issues/new?template=Feature_request.md + +# Bug Reports +[Bug Reports]: #bug-reports + +While no one likes bugs, they are an unfortunate reality in software. Remember +we can't fix bugs we don't know about, so don't be shy about reporting. + +If you have the chance, please [search existing issues], as there is a chance +that someone has already reported your error. This isn't strictly needed, as +sometimes you might not what exactly you are looking for. + +File your issue with a descriptive title, as this helps others find your issue. + +Reporting a bug is as easy as following [this link][Bug Report Link] and +filling it in. + +Sometimes a backtrace may be needed. In that case, set `RUST_BACKTRACE` +environment variable to `1`. For example: + +```bash +$ RUST_BACKTRACE=1 cargo build +``` + +> We welcome pull requests for your own bug reports, provided they have been +discussed. + +[Bug Report Link]: https://github.com/uuid-rs/uuid/issues/new?template=Bug_report.md + +# Pull Requests +[Pull Requests]: #pull-requests + +Pull requests(PRs) are the primary mechanism we use to change Uuid. GitHub itself +has some [great documentation] on using the Pull Request feature. We use the +"fork and pull" model described [here][fnp], where contributors push changes to +their personal fork and create pull requests to bring those changes into the +source repository. + +Unless the changes are fairly minor (like documentation changes or tiny +patches), we require PRs to relevant issues. + +Please open PRs against branch: +* `master` when making non-breaking changes +* `breaking` when your changes alter the public API in a breaking manner + +If the pull request is still a work in progress, prepend`[WIP] ` in your +title. `WIP bot` will make sure that the PR doesn't accidentally get merged. + +> Uuid Project has a minimum rust version policy. Currently `uuid` should +compile with atleast `1.22.0`, and is enforced on our CI builds. + +When you feel that the PR is ready, please ping one of the maintainers so +they can review your changes. + +[great documentation]: https://help.github.com/articles/about-pull-requests/ +[fnp]: https://help.github.com/articles/about-collaborative-development-models/ + +# Writing Documentation +[Writing Documentation]: #writing-documentation + +Documentation is an important part of Uuid. Lackluster or incorrect +documentation can cause headaches for the users of `uuid`. Therefore, +improvements to documentation are always welcome. + +We follow the documentation style guidelines as given by [RFC 1574]. + +[RFC 1574]: https://github.com/rust-lang/rfcs/blob/master/text/1574-more-api-documentation-conventions.md#appendix-a-full-conventions-text + +# Issue Triage +[Issue Triage]: #issue-triage + +Sometimes, an issue might stay open even after the relevant bug has been fixed. +Other times, the bug report may become invalid. Or we may just forget about the +bug. + +You can help to go through old bug reports and check if they are still valid. +You can follow [this link][lrus] to look for issues like this. + +[lrus]: https://github.com/uuid-rs/uuid/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-asc + +# Out-of-tree Contributions +[Out-of-tree Contributions]: #out-of-tree-contributions + +You can contribute to Uuid in other ways: + +* Answer questions on [users.rust-lang.org][u-r-l-o], [uuid-rs mailing list] and/or +[gitter] channel. +* Find the [crates depending on `uuid`][dependent] and sending PRs to them, +helping them keep their version of `uuid` up-to-date. + +[dependent]: https://crates.io/crates/uuid/reverse_dependencies + +# Helpful Links +[Helpful Links]: #helpful-links + +For people new to Uuid, and just starting to contribute, or even for more +seasoned developers, some useful places to look for information are: + +* The Wikipedia entry on [Universally Unique Identifier][wiki-uuid]. +* [RFC 4122] which gives the specification of Uuids. + +[wiki-uuid]: https://en.wikipedia.org/wiki/Universally_unique_identifier +[RFC 4122]: https://www.ietf.org/rfc/rfc4122.txt + +[u-r-l-o]: https://users.rust-lang.org +[uuid-rs mailing list]: https://uuid-rs.groups.io +[gitter]: https://gitter.im/uuid-rs/Lobby +[search existing issues]: https://github.com/uuid-rs/uuid/search?q=&type=Issues&utf8=%E2%9C%93 diff --git a/third_party/rust/uuid/COPYRIGHT b/third_party/rust/uuid/COPYRIGHT new file mode 100644 index 0000000000..925929c167 --- /dev/null +++ b/third_party/rust/uuid/COPYRIGHT @@ -0,0 +1,8 @@ +The Uuid Project is copyright 2013-2014, The Rust Project Developers and +copyright 2018, The Uuid Developers. + +Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +http://www.apache.org/licenses/LICENSE-2.0> or the MIT License <LICENSE-MIT or +http://opensource.org/licenses/MIT>, at your option. All files in the project +carrying such notice may not be copied, modified, or distributed except +according to those terms. diff --git a/third_party/rust/uuid/Cargo.toml b/third_party/rust/uuid/Cargo.toml new file mode 100644 index 0000000000..dd6684eebf --- /dev/null +++ b/third_party/rust/uuid/Cargo.toml @@ -0,0 +1,92 @@ +# 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 believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +edition = "2018" +name = "uuid" +version = "0.8.1" +authors = ["Ashley Mannix<ashleymannix@live.com.au>", "Christopher Armstrong", "Dylan DPC<dylan.dpc@gmail.com>", "Hunar Roop Kahlon<hunar.roop@gmail.com>"] +exclude = [".github/**", ".travis.yml", "appveyor.yml", "bors.toml"] +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] +default-target = "x86_64-pc-windows-msvc" +features = ["guid", "serde", "slog", "v1", "v3", "v4", "v5"] + +[package.metadata.playground] +features = ["serde", "v1", "v3", "v4", "v5"] +[dependencies.md5] +version = "0.6" +optional = true + +[dependencies.rand] +version = "0.7" +optional = true + +[dependencies.serde] +version = "1.0.56" +features = ["serde_derive"] +optional = true +default-features = false + +[dependencies.sha1] +version = "0.6" +optional = true + +[dependencies.slog] +version = "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" + +[features] +default = ["std"] +guid = ["winapi"] +std = [] +stdweb = ["rand/stdweb"] +v1 = [] +v3 = ["md5"] +v4 = ["rand"] +v5 = ["sha1"] +wasm-bindgen = ["rand/wasm-bindgen"] +[target."cfg(windows)".dependencies.winapi] +version = "0.3" +optional = true +[badges.appveyor] +repository = "uuid-rs/uuid" + +[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" + +[badges.travis-ci] +repository = "uuid-rs/uuid" diff --git a/third_party/rust/uuid/LICENSE-APACHE b/third_party/rust/uuid/LICENSE-APACHE new file mode 100644 index 0000000000..16fe87b06e --- /dev/null +++ b/third_party/rust/uuid/LICENSE-APACHE @@ -0,0 +1,201 @@ + 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. diff --git a/third_party/rust/uuid/LICENSE-MIT b/third_party/rust/uuid/LICENSE-MIT new file mode 100644 index 0000000000..99a3078e62 --- /dev/null +++ b/third_party/rust/uuid/LICENSE-MIT @@ -0,0 +1,26 @@ +Copyright (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. diff --git a/third_party/rust/uuid/README.md b/third_party/rust/uuid/README.md new file mode 100644 index 0000000000..5908eb62e6 --- /dev/null +++ b/third_party/rust/uuid/README.md @@ -0,0 +1,135 @@ +uuid +--------- + +[![Latest Version](https://img.shields.io/crates/v/uuid.svg)](https://crates.io/crates/uuid) +[![Join the chat at https://gitter.im/uuid-rs/Lobby](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/uuid-rs/Lobby?utm_source=badge&utm_medium=badge&utm_content=badge) +![Minimum rustc version](https://img.shields.io/badge/rustc-1.31.0+-yellow.svg) +[![Build Status](https://ci.appveyor.com/api/projects/status/github/uuid-rs/uuid?branch=master&svg=true)](https://ci.appveyor.com/project/uuid-rs/uuid/branch/master) +[![Build Status](https://travis-ci.org/uuid-rs/uuid.svg?branch=master)](https://travis-ci.org/uuid-rs/uuid) +[![Average time to resolve an issue](https://isitmaintained.com/badge/resolution/uuid-rs/uuid.svg)](https://isitmaintained.com/project/uuid-rs/uuid "Average time to resolve an issue") +[![Percentage of issues still open](https://isitmaintained.com/badge/open/uuid-rs/uuid.svg)](https://isitmaintained.com/project/uuid-rs/uuid "Percentage of issues still open") + +--- + +Generate and parse UUIDs. + +Provides support for Universally Unique Identifiers (UUIDs). A UUID is a +unique 128-bit number, stored as 16 octets. 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. + +## Dependencies + +By default, this crate depends on nothing but `std` and cannot generate +[`Uuid`]s. You need to enable the following Cargo features to enable +various pieces of functionality: + +* `v1` - adds the `Uuid::new_v1` function and the ability to create a V1 + using an implementation of `uuid::v1::ClockSequence` (usually +`uuid::v1::Context`) and a timestamp from `time::timespec`. +* `v3` - adds the `Uuid::new_v3` function and the ability to create a V3 + UUID based on the MD5 hash of some data. +* `v4` - adds the `Uuid::new_v4` function and the ability to randomly + generate a `Uuid`. +* `v5` - adds the `Uuid::new_v5` function and the ability to create a V5 + UUID based on the SHA1 hash of some data. +* `serde` - adds the ability to serialize and deserialize a `Uuid` using the + `serde` crate. + +You need to enable one of the following Cargo features together with +`v3`, `v4` or `v5` feature if you're targeting `wasm32` architecture: + +* `stdweb` - enables support for `OsRng` on `wasm32-unknown-unknown` via + `stdweb` combined with `cargo-web` +* `wasm-bindgen` - `wasm-bindgen` enables support for `OsRng` on + `wasm32-unknown-unknown` via [`wasm-bindgen`] + +By default, `uuid` can be depended on with: + +```toml +[dependencies] +uuid = "0.8" +``` + +To activate various features, use syntax like: + +```toml +[dependencies] +uuid = { version = "0.8", features = ["serde", "v4"] } +``` + +You can disable default features with: + +```toml +[dependencies] +uuid = { version = "0.8", default-features = false } +``` + +## Examples + +To parse a UUID given in the simple format and print it as a urn: + +```rust +use uuid::Uuid; + +fn main() { + let my_uuid = + Uuid::parse_str("936DA01F9ABD4d9d80C702AF85C822A8").unwrap(); + println!("{}", my_uuid.to_urn()); +} +``` + +To create a new random (V4) UUID and print it out in hexadecimal form: + +```rust +// Note that this requires the `v4` feature enabled in the uuid crate. + +use uuid::Uuid; + +fn main() { + let my_uuid = Uuid::new_v4(); + println!("{}", my_uuid); +} +``` + +## Strings + +Examples of string representations: + +* simple: `936DA01F9ABD4d9d80C702AF85C822A8` +* hyphenated: `550e8400-e29b-41d4-a716-446655440000` +* urn: `urn:uuid:F9168C5E-CEB2-4faa-B6BF-329BF39FA1E4` + +## References + +* [Wikipedia: Universally Unique Identifier]( http://en.wikipedia.org/wiki/Universally_unique_identifier) +* [RFC4122: A Universally Unique IDentifier (UUID) URN Namespace]( http://tools.ietf.org/html/rfc4122) + +[`wasm-bindgen`]: https://github.com/rustwasm/wasm-bindgen + +[`Uuid`]: https://docs.rs/uuid/0.8.1/uuid/struct.Uuid.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. + +## 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. diff --git a/third_party/rust/uuid/README.tpl b/third_party/rust/uuid/README.tpl new file mode 100644 index 0000000000..82b2960390 --- /dev/null +++ b/third_party/rust/uuid/README.tpl @@ -0,0 +1,29 @@ +{{crate}} +--------- + +[![Latest Version](https://img.shields.io/crates/v/uuid.svg)](https://crates.io/crates/uuid) +[![Join the chat at https://gitter.im/uuid-rs/Lobby](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/uuid-rs/Lobby?utm_source=badge&utm_medium=badge&utm_content=badge) +![Minimum rustc version](https://img.shields.io/badge/rustc-1.31.0+-yellow.svg) +{{badges}} + +--- + +{{readme}} + +[`Uuid`]: https://docs.rs/uuid/{{version}}/uuid/struct.Uuid.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. + +## 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. diff --git a/third_party/rust/uuid/benches/format_str.rs b/third_party/rust/uuid/benches/format_str.rs new file mode 100644 index 0000000000..f029cf03d1 --- /dev/null +++ b/third_party/rust/uuid/benches/format_str.rs @@ -0,0 +1,66 @@ +#![feature(test)] +extern crate test; + +use std::io::Write; +use test::Bencher; +use uuid::Uuid; + +#[bench] +fn bench_hyphen(b: &mut Bencher) { + let uuid = Uuid::parse_str("F9168C5E-CEB2-4faa-B6BF-329BF39FA1E4").unwrap(); + b.iter(|| { + let mut buffer = [0_u8; 36]; + write!(&mut buffer as &mut [_], "{:x}", uuid.to_hyphenated()).unwrap(); + test::black_box(buffer); + }); +} + +#[bench] +fn bench_simple(b: &mut Bencher) { + let uuid = Uuid::parse_str("F9168C5E-CEB2-4faa-B6BF-329BF39FA1E4").unwrap(); + b.iter(|| { + let mut buffer = [0_u8; 32]; + write!(&mut buffer as &mut [_], "{:x}", uuid.to_simple()).unwrap(); + test::black_box(buffer); + }) +} + +#[bench] +fn bench_urn(b: &mut Bencher) { + let uuid = Uuid::parse_str("F9168C5E-CEB2-4faa-B6BF-329BF39FA1E4").unwrap(); + b.iter(|| { + let mut buffer = [0_u8; 36 + 9]; + write!(&mut buffer as &mut [_], "{:x}", uuid.to_urn()).unwrap(); + test::black_box(buffer); + }) +} + +#[bench] +fn bench_encode_hyphen(b: &mut Bencher) { + let uuid = Uuid::parse_str("F9168C5E-CEB2-4faa-B6BF-329BF39FA1E4").unwrap(); + b.iter(|| { + let mut buffer = [0_u8; 36]; + uuid.to_hyphenated().encode_lower(&mut buffer); + test::black_box(buffer); + }); +} + +#[bench] +fn bench_encode_simple(b: &mut Bencher) { + let uuid = Uuid::parse_str("F9168C5E-CEB2-4faa-B6BF-329BF39FA1E4").unwrap(); + b.iter(|| { + let mut buffer = [0_u8; 32]; + uuid.to_simple().encode_lower(&mut buffer); + test::black_box(buffer); + }) +} + +#[bench] +fn bench_encode_urn(b: &mut Bencher) { + let uuid = Uuid::parse_str("F9168C5E-CEB2-4faa-B6BF-329BF39FA1E4").unwrap(); + b.iter(|| { + let mut buffer = [0_u8; 36 + 9]; + uuid.to_urn().encode_lower(&mut buffer); + test::black_box(buffer); + }) +} diff --git a/third_party/rust/uuid/benches/invalid_parse_str.rs b/third_party/rust/uuid/benches/invalid_parse_str.rs new file mode 100644 index 0000000000..7fde28b3bb --- /dev/null +++ b/third_party/rust/uuid/benches/invalid_parse_str.rs @@ -0,0 +1,58 @@ +#![feature(test)] +extern crate test; + +use test::Bencher; +use uuid::Uuid; + +#[bench] +fn bench_parse_invalid_strings(b: &mut Bencher) { + b.iter(|| { + let _ = Uuid::parse_str(""); + let _ = Uuid::parse_str("!"); + let _ = Uuid::parse_str("F9168C5E-CEB2-4faa-B6BF-329BF39FA1E45"); + let _ = Uuid::parse_str("F9168C5E-CEB2-4faa-BBF-329BF39FA1E4"); + let _ = Uuid::parse_str("F9168C5E-CEB2-4faa-BGBF-329BF39FA1E4"); + let _ = Uuid::parse_str("F9168C5E-CEB2-4faa-B6BFF329BF39FA1E4"); + let _ = Uuid::parse_str("F9168C5E-CEB2-4faa"); + let _ = Uuid::parse_str("F9168C5E-CEB2-4faaXB6BFF329BF39FA1E4"); + let _ = Uuid::parse_str("F9168C5E-CEB-24fa-eB6BFF32-BF39FA1E4"); + let _ = Uuid::parse_str("01020304-1112-2122-3132-41424344"); + let _ = Uuid::parse_str("67e5504410b1426f9247bb680e5fe0c88"); + let _ = Uuid::parse_str("67e5504410b1426f9247bb680e5fe0cg8"); + let _ = Uuid::parse_str("67e5504410b1426%9247bb680e5fe0c8"); + + // Test error reporting + let _ = Uuid::parse_str("67e5504410b1426f9247bb680e5fe0c"); + let _ = Uuid::parse_str("67e550X410b1426f9247bb680e5fe0cd"); + let _ = Uuid::parse_str("67e550-4105b1426f9247bb680e5fe0c"); + let _ = Uuid::parse_str("F9168C5E-CEB2-4faa-B6BF1-02BF39FA1E4"); + }); +} + +#[bench] +fn bench_parse_invalid_len(b: &mut Bencher) { + b.iter(|| { + let _ = Uuid::parse_str("F9168C5E-CEB2-4faa-BBF-329BF39FA1E4"); + }) +} + +#[bench] +fn bench_parse_invalid_character(b: &mut Bencher) { + b.iter(|| { + let _ = Uuid::parse_str("F9168C5E-CEB2-4faa-BGBF-329BF39FA1E4"); + }) +} + +#[bench] +fn bench_parse_invalid_group_len(b: &mut Bencher) { + b.iter(|| { + let _ = Uuid::parse_str("01020304-1112-2122-3132-41424344"); + }); +} + +#[bench] +fn bench_parse_invalid_groups(b: &mut Bencher) { + b.iter(|| { + let _ = Uuid::parse_str("F9168C5E-CEB2-4faa-B6BFF329BF39FA1E4"); + }); +} diff --git a/third_party/rust/uuid/benches/mod.rs b/third_party/rust/uuid/benches/mod.rs new file mode 100644 index 0000000000..2ef574f012 --- /dev/null +++ b/third_party/rust/uuid/benches/mod.rs @@ -0,0 +1,4 @@ +#![feature(test)] + +#[cfg(feature = "slog")] +pub mod slog_support; diff --git a/third_party/rust/uuid/benches/serde_support.rs b/third_party/rust/uuid/benches/serde_support.rs new file mode 100644 index 0000000000..a7ce64f824 --- /dev/null +++ b/third_party/rust/uuid/benches/serde_support.rs @@ -0,0 +1,48 @@ +#![cfg(feature = "serde")] +#![feature(test)] + +use bincode; +use serde_json; +extern crate test; + +use test::Bencher; +use uuid::Uuid; + +#[bench] +fn bench_json_encode(b: &mut Bencher) { + let uuid = Uuid::parse_str("F9168C5E-CEB2-4faa-B6BF-329BF39FA1E4").unwrap(); + let mut buffer = [0_u8; 38]; + b.iter(|| { + serde_json::to_writer(&mut buffer as &mut [u8], &uuid).unwrap(); + test::black_box(buffer); + }); + b.bytes = buffer.len() as u64; +} + +#[bench] +fn bench_json_decode(b: &mut Bencher) { + let s = "\"F9168C5E-CEB2-4faa-B6BF-329BF39FA1E4\""; + b.iter(|| serde_json::from_str::<Uuid>(s).unwrap()); + b.bytes = s.len() as u64; +} + +#[bench] +fn bench_bincode_encode(b: &mut Bencher) { + let uuid = Uuid::parse_str("F9168C5E-CEB2-4faa-B6BF-329BF39FA1E4").unwrap(); + let mut buffer = [0_u8; 24]; + b.iter(|| { + bincode::serialize_into(&mut buffer as &mut [u8], &uuid).unwrap(); + test::black_box(buffer); + }); + b.bytes = buffer.len() as u64; +} + +#[bench] +fn bench_bincode_decode(b: &mut Bencher) { + let bytes = [ + 16, 0, 0, 0, 0, 0, 0, 0, 249, 22, 140, 94, 206, 178, 79, 170, 182, 191, + 50, 155, 243, 159, 161, 228, + ]; + b.iter(|| bincode::deserialize::<Uuid>(&bytes).unwrap()); + b.bytes = bytes.len() as u64; +} diff --git a/third_party/rust/uuid/benches/slog_support/mod.rs b/third_party/rust/uuid/benches/slog_support/mod.rs new file mode 100644 index 0000000000..cdc37a7359 --- /dev/null +++ b/third_party/rust/uuid/benches/slog_support/mod.rs @@ -0,0 +1 @@ +pub mod parse_str; diff --git a/third_party/rust/uuid/benches/slog_support/parse_str.rs b/third_party/rust/uuid/benches/slog_support/parse_str.rs new file mode 100644 index 0000000000..fa0e5f7020 --- /dev/null +++ b/third_party/rust/uuid/benches/slog_support/parse_str.rs @@ -0,0 +1,15 @@ +extern crate test; + +#[bench] +#[cfg(feature = "slog")] +pub fn bench_log_discard_kv(b: &mut test::Bencher) { + let u1 = + uuid::Uuid::parse_str("F9168C5E-CEB2-4FAB-B6BF-329BF39FA1E4").unwrap(); + let root = + slog::Logger::root(::slog::Drain::fuse(::slog::Discard), slog::o!()); + + b.iter(|| { + #[cfg(feature = "slog")] + slog::crit!(root, "test"; "u1" => u1); + }); +} diff --git a/third_party/rust/uuid/benches/valid_parse_str.rs b/third_party/rust/uuid/benches/valid_parse_str.rs new file mode 100644 index 0000000000..f20d6e320f --- /dev/null +++ b/third_party/rust/uuid/benches/valid_parse_str.rs @@ -0,0 +1,39 @@ +#![feature(test)] + +extern crate test; + +use test::Bencher; +use uuid::Uuid; + +#[bench] +fn bench_parse_valid_strings(b: &mut Bencher) { + b.iter(|| { + // Valid + let _ = Uuid::parse_str("00000000000000000000000000000000"); + let _ = Uuid::parse_str("67e55044-10b1-426f-9247-bb680e5fe0c8"); + let _ = Uuid::parse_str("67e55044-10b1-426f-9247-bb680e5fe0c8"); + let _ = Uuid::parse_str("F9168C5E-CEB2-4faa-B6BF-329BF39FA1E4"); + let _ = Uuid::parse_str("67e5504410b1426f9247bb680e5fe0c8"); + let _ = Uuid::parse_str("01020304-1112-2122-3132-414243444546"); + let _ = + Uuid::parse_str("urn:uuid:67e55044-10b1-426f-9247-bb680e5fe0c8"); + + // Nil + let _ = Uuid::parse_str("00000000000000000000000000000000"); + let _ = Uuid::parse_str("00000000-0000-0000-0000-000000000000"); + }); +} + +#[bench] +fn bench_valid_hyphenated(b: &mut Bencher) { + b.iter(|| { + let _ = Uuid::parse_str("67e55044-10b1-426f-9247-bb680e5fe0c8"); + }); +} + +#[bench] +fn bench_valid_short(b: &mut Bencher) { + b.iter(|| { + let _ = Uuid::parse_str("67e5504410b1426f9247bb680e5fe0c8"); + }); +} diff --git a/third_party/rust/uuid/src/adapter/compact.rs b/third_party/rust/uuid/src/adapter/compact.rs new file mode 100644 index 0000000000..ad5362affd --- /dev/null +++ b/third_party/rust/uuid/src/adapter/compact.rs @@ -0,0 +1,79 @@ +//! Module for use with `#[serde(with = "...")]` to serialize a [`Uuid`] +//! as a `[u8; 16]`. +//! +//! [`Uuid`]: ../../struct.Uuid.html + +/// Serializer for a [`Uuid`] into a `[u8; 16]` +/// +/// [`Uuid`]: ../../struct.Uuid.html +pub fn serialize<S>(u: &crate::Uuid, serializer: S) -> Result<S::Ok, S::Error> +where + S: serde::Serializer, +{ + serde::Serialize::serialize(u.as_bytes(), serializer) +} + +/// Deserializer from a `[u8; 16]` into a [`Uuid`] +/// +/// [`Uuid`]: ../../struct.Uuid.html +pub fn deserialize<'de, D>(deserializer: D) -> Result<crate::Uuid, D::Error> +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_test; + + #[test] + fn test_serialize_compact() { + #[derive(serde::Serialize, Debug, serde::Deserialize, PartialEq)] + struct UuidContainer { + #[serde(with = "super")] + u: crate::Uuid, + } + use serde_test::Configure; + + 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, + ], + ) + } +} diff --git a/third_party/rust/uuid/src/adapter/mod.rs b/third_party/rust/uuid/src/adapter/mod.rs new file mode 100644 index 0000000000..2f2ea765a3 --- /dev/null +++ b/third_party/rust/uuid/src/adapter/mod.rs @@ -0,0 +1,978 @@ +// 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 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Adapters for various formats for UUIDs + +use crate::prelude::*; +use crate::std::{fmt, str}; + +#[cfg(feature = "serde")] +pub mod compact; + +/// An adaptor for formatting an [`Uuid`] as a hyphenated string. +/// +/// Takes an owned instance of the [`Uuid`]. +/// +/// [`Uuid`]: ../struct.Uuid.html +#[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)] +pub struct Hyphenated(Uuid); + +/// An adaptor for formatting an [`Uuid`] as a hyphenated string. +/// +/// Takes a reference of the [`Uuid`]. +/// +/// [`Uuid`]: ../struct.Uuid.html +#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] +pub struct HyphenatedRef<'a>(&'a Uuid); + +/// An adaptor for formatting an [`Uuid`] as a simple string. +/// +/// Takes an owned instance of the [`Uuid`]. +/// +/// [`Uuid`]: ../struct.Uuid.html +#[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)] +pub struct Simple(Uuid); + +/// An adaptor for formatting an [`Uuid`] as a simple string. +/// +/// Takes a reference of the [`Uuid`]. +/// +/// [`Uuid`]: ../struct.Uuid.html +#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] +pub struct SimpleRef<'a>(&'a Uuid); + +/// An adaptor for formatting an [`Uuid`] as a URN string. +/// +/// Takes an owned instance of the [`Uuid`]. +/// +/// [`Uuid`]: ../struct.Uuid.html +#[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)] +pub struct Urn(Uuid); + +/// An adaptor for formatting an [`Uuid`] as a URN string. +/// +/// Takes a reference of the [`Uuid`]. +/// +/// [`Uuid`]: ../struct.Uuid.html +#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] +pub struct UrnRef<'a>(&'a Uuid); + +impl Uuid { + /// Get a [`Hyphenated`] formatter. + /// + /// [`Hyphenated`]: adapter/struct.Hyphenated.html + #[inline] + pub const fn to_hyphenated(self) -> Hyphenated { + Hyphenated::from_uuid(self) + } + + /// Get a borrowed [`HyphenatedRef`] formatter. + /// + /// [`HyphenatedRef`]: adapter/struct.HyphenatedRef.html + #[inline] + pub const fn to_hyphenated_ref(&self) -> HyphenatedRef<'_> { + HyphenatedRef::from_uuid_ref(self) + } + + /// Get a [`Simple`] formatter. + /// + /// [`Simple`]: adapter/struct.Simple.html + #[inline] + pub const fn to_simple(self) -> Simple { + Simple::from_uuid(self) + } + + /// Get a borrowed [`SimpleRef`] formatter. + /// + /// [`SimpleRef`]: adapter/struct.SimpleRef.html + #[inline] + pub const fn to_simple_ref(&self) -> SimpleRef<'_> { + SimpleRef::from_uuid_ref(self) + } + + /// Get a [`Urn`] formatter. + /// + /// [`Uuid`]: ../struct.Uuid.html + /// [`Urn`]: adapter/struct.Urn.html + #[inline] + pub const fn to_urn(self) -> Urn { + Urn::from_uuid(self) + } + + /// Get a borrowed [`UrnRef`] formatter. + /// + /// [`Uuid`]: ../struct.Uuid.html + /// [`UrnRef`]: adapter/struct.UrnRef.html + #[inline] + pub const fn to_urn_ref(&self) -> UrnRef<'_> { + UrnRef::from_uuid_ref(self) + } +} + +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', +]; +/// The segments of a UUID's [u8; 16] corresponding to each group. +const BYTE_POSITIONS: [usize; 6] = [0, 4, 6, 8, 10, 16]; +/// The locations that hyphens are written into the buffer, after each +/// group. +const HYPHEN_POSITIONS: [usize; 4] = [8, 13, 18, 23]; + +/// Encodes the `uuid` possibly with hyphens, and possibly in upper +/// case, to full_buffer[start..] and returns the str sliced from +/// full_buffer[..start + encoded_length]. +/// +/// The `start` parameter allows writing a prefix (such as +/// "urn:uuid:") to the buffer that's included in the final encoded +/// UUID. +fn encode<'a>( + full_buffer: &'a mut [u8], + start: usize, + uuid: &Uuid, + hyphens: bool, + upper: bool, +) -> &'a mut str { + let len = if hyphens { 36 } else { 32 }; + + { + let buffer = &mut full_buffer[start..start + len]; + let bytes = uuid.as_bytes(); + + let hex = if upper { &UPPER } else { &LOWER }; + + for group in 0..5 { + // If we're writing hyphens, we need to shift the output + // location along by how many of them have been written + // before this point. That's exactly the (0-indexed) group + // number. + let hyphens_before = if hyphens { group } else { 0 }; + for idx in BYTE_POSITIONS[group]..BYTE_POSITIONS[group + 1] { + let b = bytes[idx]; + let out_idx = hyphens_before + 2 * idx; + + buffer[out_idx] = hex[(b >> 4) as usize]; + buffer[out_idx + 1] = hex[(b & 0b1111) as usize]; + } + + if group != 4 && hyphens { + buffer[HYPHEN_POSITIONS[group]] = b'-'; + } + } + } + + str::from_utf8_mut(&mut full_buffer[..start + len]) + .expect("found non-ASCII output characters while encoding a UUID") +} + +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; + /// + /// let uuid = Uuid::parse_str("936DA01f9abd4d9d80c702af85c822a8").unwrap(); + /// + /// // the encoded portion is returned + /// assert_eq!( + /// uuid.to_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.to_hyphenated().encode_lower(&mut buf); + /// assert_eq!( + /// &buf as &[_], + /// b"936da01f-9abd-4d9d-80c7-02af85c822a8!!!!" as &[_] + /// ); + /// ``` + /// */ + pub fn encode_lower<'buf>(&self, buffer: &'buf mut [u8]) -> &'buf mut str { + encode(buffer, 0, &self.0, true, 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; + /// + /// let uuid = Uuid::parse_str("936da01f9abd4d9d80c702af85c822a8").unwrap(); + /// + /// // the encoded portion is returned + /// assert_eq!( + /// uuid.to_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.to_hyphenated().encode_upper(&mut buf); + /// assert_eq!( + /// &buf as &[_], + /// b"936DA01F-9ABD-4D9D-80C7-02AF85C822A8!!!!" as &[_] + /// ); + /// ``` + /// */ + pub fn encode_upper<'buf>(&self, buffer: &'buf mut [u8]) -> &'buf mut str { + encode(buffer, 0, &self.0, true, true) + } +} + +impl<'a> HyphenatedRef<'a> { + /// The length of a hyphenated [`Uuid`] string. + /// + /// [`Uuid`]: ../struct.Uuid.html + pub const LENGTH: usize = 36; + + /// Creates a [`HyphenatedRef`] from a [`Uuid`] reference. + /// + /// [`Uuid`]: ../struct.Uuid.html + /// [`HyphenatedRef`]: struct.HyphenatedRef.html + pub const fn from_uuid_ref(uuid: &'a Uuid) -> Self { + HyphenatedRef(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; + /// + /// let uuid = Uuid::parse_str("936DA01f9abd4d9d80c702af85c822a8").unwrap(); + /// + /// // the encoded portion is returned + /// assert_eq!( + /// uuid.to_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.to_hyphenated().encode_lower(&mut buf); + /// assert_eq!( + /// uuid.to_hyphenated().encode_lower(&mut buf), + /// "936da01f-9abd-4d9d-80c7-02af85c822a8" + /// ); + /// assert_eq!( + /// &buf as &[_], + /// b"936da01f-9abd-4d9d-80c7-02af85c822a8!!!!" as &[_] + /// ); + /// ``` + /// */ + pub fn encode_lower<'buf>(&self, buffer: &'buf mut [u8]) -> &'buf mut str { + encode(buffer, 0, self.0, true, 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; + /// + /// let uuid = Uuid::parse_str("936da01f9abd4d9d80c702af85c822a8").unwrap(); + /// + /// // the encoded portion is returned + /// assert_eq!( + /// uuid.to_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]; + /// assert_eq!( + /// uuid.to_hyphenated().encode_upper(&mut buf), + /// "936DA01F-9ABD-4D9D-80C7-02AF85C822A8" + /// ); + /// assert_eq!( + /// &buf as &[_], + /// b"936DA01F-9ABD-4D9D-80C7-02AF85C822A8!!!!" as &[_] + /// ); + /// ``` + /// */ + pub fn encode_upper<'buf>(&self, buffer: &'buf mut [u8]) -> &'buf mut str { + encode(buffer, 0, self.0, true, true) + } +} + +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; + /// + /// let uuid = Uuid::parse_str("936DA01f9abd4d9d80c702af85c822a8").unwrap(); + /// + /// // the encoded portion is returned + /// assert_eq!( + /// uuid.to_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.to_simple().encode_lower(&mut buf), + /// "936da01f9abd4d9d80c702af85c822a8" + /// ); + /// assert_eq!( + /// &buf as &[_], + /// b"936da01f9abd4d9d80c702af85c822a8!!!!" as &[_] + /// ); + /// ``` + /// */ + pub fn encode_lower<'buf>(&self, buffer: &'buf mut [u8]) -> &'buf mut str { + encode(buffer, 0, &self.0, false, 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; + /// + /// let uuid = Uuid::parse_str("936da01f9abd4d9d80c702af85c822a8").unwrap(); + /// + /// // the encoded portion is returned + /// assert_eq!( + /// uuid.to_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.to_simple().encode_upper(&mut buf), + /// "936DA01F9ABD4D9D80C702AF85C822A8" + /// ); + /// assert_eq!( + /// &buf as &[_], + /// b"936DA01F9ABD4D9D80C702AF85C822A8!!!!" as &[_] + /// ); + /// ``` + /// */ + pub fn encode_upper<'buf>(&self, buffer: &'buf mut [u8]) -> &'buf mut str { + encode(buffer, 0, &self.0, false, true) + } +} + +impl<'a> SimpleRef<'a> { + /// The length of a simple [`Uuid`] string. + /// + /// [`Uuid`]: ../struct.Uuid.html + pub const LENGTH: usize = 32; + + /// Creates a [`SimpleRef`] from a [`Uuid`] reference. + /// + /// [`Uuid`]: ../struct.Uuid.html + /// [`SimpleRef`]: struct.SimpleRef.html + pub const fn from_uuid_ref(uuid: &'a Uuid) -> Self { + SimpleRef(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; + /// + /// let uuid = Uuid::parse_str("936DA01f9abd4d9d80c702af85c822a8").unwrap(); + /// + /// // the encoded portion is returned + /// assert_eq!( + /// uuid.to_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.to_simple().encode_lower(&mut buf), + /// "936da01f9abd4d9d80c702af85c822a8" + /// ); + /// assert_eq!( + /// &buf as &[_], + /// b"936da01f9abd4d9d80c702af85c822a8!!!!" as &[_] + /// ); + /// ``` + /// */ + pub fn encode_lower<'buf>(&self, buffer: &'buf mut [u8]) -> &'buf mut str { + encode(buffer, 0, self.0, false, 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; + /// + /// let uuid = Uuid::parse_str("936da01f9abd4d9d80c702af85c822a8").unwrap(); + /// + /// // the encoded portion is returned + /// assert_eq!( + /// uuid.to_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.to_simple().encode_upper(&mut buf), + /// "936DA01F9ABD4D9D80C702AF85C822A8" + /// ); + /// assert_eq!( + /// &buf as &[_], + /// b"936DA01F9ABD4D9D80C702AF85C822A8!!!!" as &[_] + /// ); + /// ``` + /// */ + pub fn encode_upper<'buf>(&self, buffer: &'buf mut [u8]) -> &'buf mut str { + encode(buffer, 0, self.0, false, true) + } +} + +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; + /// + /// let uuid = Uuid::parse_str("936DA01f9abd4d9d80c702af85c822a8").unwrap(); + /// + /// // the encoded portion is returned + /// assert_eq!( + /// uuid.to_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.to_urn().encode_lower(&mut buf); + /// assert_eq!( + /// uuid.to_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 &[_] + /// ); + /// ``` + /// */ + pub fn encode_lower<'buf>(&self, buffer: &'buf mut [u8]) -> &'buf mut str { + buffer[..9].copy_from_slice(b"urn:uuid:"); + encode(buffer, 9, &self.0, true, 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; + /// + /// let uuid = Uuid::parse_str("936da01f9abd4d9d80c702af85c822a8").unwrap(); + /// + /// // the encoded portion is returned + /// assert_eq!( + /// uuid.to_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.to_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 &[_] + /// ); + /// ``` + /// */ + pub fn encode_upper<'buf>(&self, buffer: &'buf mut [u8]) -> &'buf mut str { + buffer[..9].copy_from_slice(b"urn:uuid:"); + encode(buffer, 9, &self.0, true, true) + } +} + +impl<'a> UrnRef<'a> { + /// The length of a URN [`Uuid`] string. + /// + /// [`Uuid`]: ../struct.Uuid.html + pub const LENGTH: usize = 45; + + /// Creates a [`UrnRef`] from a [`Uuid`] reference. + /// + /// [`Uuid`]: ../struct.Uuid.html + /// [`UrnRef`]: struct.UrnRef.html + pub const fn from_uuid_ref(uuid: &'a Uuid) -> Self { + UrnRef(&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; + /// + /// let uuid = Uuid::parse_str("936DA01f9abd4d9d80c702af85c822a8").unwrap(); + /// + /// // the encoded portion is returned + /// assert_eq!( + /// uuid.to_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.to_urn().encode_lower(&mut buf); + /// assert_eq!( + /// uuid.to_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 &[_] + /// ); + /// ``` + /// */ + pub fn encode_lower<'buf>(&self, buffer: &'buf mut [u8]) -> &'buf mut str { + buffer[..9].copy_from_slice(b"urn:uuid:"); + encode(buffer, 9, self.0, true, 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; + /// + /// let uuid = Uuid::parse_str("936da01f9abd4d9d80c702af85c822a8").unwrap(); + /// + /// // the encoded portion is returned + /// assert_eq!( + /// uuid.to_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.to_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 &[_] + /// ); + /// ``` + /// */ + pub fn encode_upper<'buf>(&self, buffer: &'buf mut [u8]) -> &'buf mut str { + buffer[..9].copy_from_slice(b"urn:uuid:"); + encode(buffer, 9, self.0, true, true) + } +} + +macro_rules! impl_adapter_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 { + // TODO: Self doesn't work https://github.com/rust-lang/rust/issues/52808 + f.write_str(self.encode_lower(&mut [0; $T::LENGTH])) + } + } + + impl<$($a),*> fmt::UpperHex for $T<$($a),*> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + // TODO: Self doesn't work https://github.com/rust-lang/rust/issues/52808 + f.write_str(self.encode_upper(&mut [0; $T::LENGTH])) + } + } + + impl_adapter_from!($T<$($a),*>); + )+} +} + +macro_rules! impl_adapter_from { + ($T:ident<>) => { + impl From<Uuid> for $T { + #[inline] + fn from(f: Uuid) -> Self { + $T::from_uuid(f) + } + } + }; + ($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_adapter_traits! { + Hyphenated<>, + HyphenatedRef<'a>, + Simple<>, + SimpleRef<'a>, + Urn<>, + UrnRef<'a> +} + +#[cfg(test)] +mod tests { + use crate::prelude::*; + + #[test] + fn hyphenated_trailing() { + let mut buf = [b'x'; 100]; + let len = Uuid::nil().to_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().to_hyphenated().encode_lower(&mut buf).len(); + assert_eq!(len, super::HyphenatedRef::LENGTH); + assert!(buf[len..].iter().all(|x| *x == b'x')); + } + + #[test] + fn simple_trailing() { + let mut buf = [b'x'; 100]; + let len = Uuid::nil().to_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().to_simple().encode_lower(&mut buf).len(); + assert_eq!(len, super::SimpleRef::LENGTH); + assert!(buf[len..].iter().all(|x| *x == b'x')); + } + + #[test] + fn urn_trailing() { + let mut buf = [b'x'; 100]; + let len = Uuid::nil().to_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().to_urn().encode_lower(&mut buf).len(); + assert_eq!(len, super::UrnRef::LENGTH); + assert!(buf[len..].iter().all(|x| *x == b'x')); + } + + #[test] + #[should_panic] + fn hyphenated_too_small() { + Uuid::nil().to_hyphenated().encode_lower(&mut [0; 35]); + } + + #[test] + #[should_panic] + fn hyphenated_ref_too_small() { + Uuid::nil().to_hyphenated_ref().encode_lower(&mut [0; 35]); + } + + #[test] + #[should_panic] + fn simple_too_small() { + Uuid::nil().to_simple().encode_lower(&mut [0; 31]); + } + #[test] + #[should_panic] + fn simple_ref_too_small() { + Uuid::nil().to_simple_ref().encode_lower(&mut [0; 31]); + } + #[test] + #[should_panic] + fn urn_too_small() { + Uuid::nil().to_urn().encode_lower(&mut [0; 44]); + } + #[test] + #[should_panic] + fn urn_ref_too_small() { + Uuid::nil().to_urn_ref().encode_lower(&mut [0; 44]); + } +} diff --git a/third_party/rust/uuid/src/builder/error.rs b/third_party/rust/uuid/src/builder/error.rs new file mode 100644 index 0000000000..2c42798f66 --- /dev/null +++ b/third_party/rust/uuid/src/builder/error.rs @@ -0,0 +1,52 @@ +use crate::std::fmt; + +/// The error that can occur when creating a [`Uuid`]. +/// +/// [`Uuid`]: struct.Uuid.html +#[derive(Clone, Debug, Eq, Hash, PartialEq)] +pub(crate) struct Error { + expected: usize, + found: usize, +} + +impl Error { + /// The expected number of bytes. + #[inline] + const fn expected(&self) -> usize { + self.expected + } + + /// The number of bytes found. + #[inline] + const fn found(&self) -> usize { + self.found + } + + /// Create a new [`UuidError`]. + /// + /// [`UuidError`]: struct.UuidError.html + #[inline] + pub(crate) const fn new(expected: usize, found: usize) -> Self { + Error { expected, found } + } +} + +impl fmt::Display for Error { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!( + f, + "invalid bytes length: expected {}, found {}", + self.expected(), + self.found() + ) + } +} + +#[cfg(feature = "std")] +mod std_support { + use super::*; + + use crate::std::error; + + impl error::Error for Error {} +} diff --git a/third_party/rust/uuid/src/builder/mod.rs b/third_party/rust/uuid/src/builder/mod.rs new file mode 100644 index 0000000000..3b5c7491a5 --- /dev/null +++ b/third_party/rust/uuid/src/builder/mod.rs @@ -0,0 +1,474 @@ +// 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 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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 + +mod error; +pub(crate) use self::error::Error; + +use crate::prelude::*; + +impl Uuid { + /// The 'nil UUID'. + /// + /// The nil UUID is special form of UUID that is specified to have all + /// 128 bits set to zero, as defined in [IETF RFC 4122 Section 4.1.7][RFC]. + /// + /// [RFC]: https://tools.ietf.org/html/rfc4122.html#section-4.1.7 + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use uuid::Uuid; + /// + /// let uuid = Uuid::nil(); + /// + /// assert_eq!( + /// uuid.to_hyphenated().to_string(), + /// "00000000-0000-0000-0000-000000000000" + /// ); + /// ``` + pub const fn nil() -> Self { + Uuid::from_bytes([0; 16]) + } + + /// Creates a UUID from four field values in big-endian order. + /// + /// # Errors + /// + /// This function will return an error if `d4`'s length is not 8 bytes. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use uuid::Uuid; + /// + /// let d4 = [12, 3, 9, 56, 54, 43, 8, 9]; + /// + /// let uuid = Uuid::from_fields(42, 12, 5, &d4); + /// let uuid = uuid.map(|uuid| uuid.to_hyphenated().to_string()); + /// + /// let expected_uuid = + /// Ok(String::from("0000002a-000c-0005-0c03-0938362b0809")); + /// + /// assert_eq!(expected_uuid, uuid); + /// ``` + pub fn from_fields( + d1: u32, + d2: u16, + d3: u16, + d4: &[u8], + ) -> Result<Uuid, crate::Error> { + const D4_LEN: usize = 8; + + let len = d4.len(); + + if len != D4_LEN { + Err(Error::new(D4_LEN, len))?; + } + + Ok(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 converted into big-endian order. + /// + /// # Examples + /// + /// ``` + /// use uuid::Uuid; + /// + /// let d1 = 0xAB3F1097u32; + /// let d2 = 0x501Eu16; + /// let d3 = 0xB736u16; + /// let d4 = [12, 3, 9, 56, 54, 43, 8, 9]; + /// + /// let uuid = Uuid::from_fields_le(d1, d2, d3, &d4); + /// let uuid = uuid.map(|uuid| uuid.to_hyphenated().to_string()); + /// + /// let expected_uuid = + /// Ok(String::from("97103fab-1e50-36b7-0c03-0938362b0809")); + /// + /// assert_eq!(expected_uuid, uuid); + /// ``` + pub fn from_fields_le( + d1: u32, + d2: u16, + d3: u16, + d4: &[u8], + ) -> Result<Uuid, crate::Error> { + const D4_LEN: usize = 8; + + let len = d4.len(); + + if len != D4_LEN { + Err(Error::new(D4_LEN, len))?; + } + + Ok(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 in big-endian order. + 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. + 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 using the supplied big-endian bytes. + /// + /// # Errors + /// + /// This function will return an error if `b` has any length other than 16. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use uuid::Uuid; + /// + /// let bytes = [4, 54, 67, 12, 43, 2, 98, 76, 32, 50, 87, 5, 1, 33, 43, 87]; + /// + /// let uuid = Uuid::from_slice(&bytes); + /// let uuid = uuid.map(|uuid| uuid.to_hyphenated().to_string()); + /// + /// let expected_uuid = + /// Ok(String::from("0436430c-2b02-624c-2032-570501212b57")); + /// + /// assert_eq!(expected_uuid, uuid); + /// ``` + /// + /// An incorrect number of bytes: + /// + /// ``` + /// use uuid::Uuid; + /// + /// let bytes = [4, 54, 67, 12, 43, 2, 98, 76]; + /// + /// let uuid = Uuid::from_slice(&bytes); + /// + /// assert!(uuid.is_err()); + /// ``` + pub fn from_slice(b: &[u8]) -> Result<Uuid, crate::Error> { + const BYTES_LEN: usize = 16; + + let len = b.len(); + + if len != BYTES_LEN { + Err(Error::new(BYTES_LEN, len))?; + } + + let mut bytes: Bytes = [0; 16]; + bytes.copy_from_slice(b); + Ok(Uuid::from_bytes(bytes)) + } + + /// Creates a UUID using the supplied big-endian bytes. + pub const fn from_bytes(bytes: Bytes) -> Uuid { + Uuid(bytes) + } +} + +/// A builder struct for creating a UUID. +/// +/// # Examples +/// +/// Creating a v4 UUID from externally generated bytes: +/// +/// ``` +/// 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_bytes(random_bytes) +/// .set_variant(Variant::RFC4122) +/// .set_version(Version::Random) +/// .build(); +/// ``` +#[allow(missing_copy_implementations)] +#[derive(Debug)] +pub struct Builder(crate::Bytes); + +impl Builder { + /// Creates a `Builder` using the supplied big-endian bytes. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// let bytes: uuid::Bytes = [ + /// 70, 235, 208, 238, 14, 109, 67, 201, 185, 13, 204, 195, 90, 145, 63, 62, + /// ]; + /// + /// let mut builder = uuid::Builder::from_bytes(bytes); + /// let uuid = builder.build().to_hyphenated().to_string(); + /// + /// let expected_uuid = String::from("46ebd0ee-0e6d-43c9-b90d-ccc35a913f3e"); + /// + /// assert_eq!(expected_uuid, uuid); + /// ``` + /// + /// An incorrect number of bytes: + /// + /// ```compile_fail + /// let bytes: uuid::Bytes = [4, 54, 67, 12, 43, 2, 98, 76]; // doesn't compile + /// + /// let uuid = uuid::Builder::from_bytes(bytes); + /// ``` + pub const fn from_bytes(b: Bytes) -> Self { + Builder(b) + } + + /// Creates a `Builder` using the supplied big-endian bytes. + /// + /// # Errors + /// + /// This function will return an error if `b` has any length other than 16. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// let bytes = [4, 54, 67, 12, 43, 2, 98, 76, 32, 50, 87, 5, 1, 33, 43, 87]; + /// + /// let builder = uuid::Builder::from_slice(&bytes); + /// let uuid = + /// builder.map(|mut builder| builder.build().to_hyphenated().to_string()); + /// + /// let expected_uuid = + /// Ok(String::from("0436430c-2b02-624c-2032-570501212b57")); + /// + /// assert_eq!(expected_uuid, uuid); + /// ``` + /// + /// An incorrect number of bytes: + /// + /// ``` + /// let bytes = [4, 54, 67, 12, 43, 2, 98, 76]; + /// + /// let builder = uuid::Builder::from_slice(&bytes); + /// + /// assert!(builder.is_err()); + /// ``` + pub fn from_slice(b: &[u8]) -> Result<Self, crate::Error> { + const BYTES_LEN: usize = 16; + + let len = b.len(); + + if len != BYTES_LEN { + Err(Error::new(BYTES_LEN, len))?; + } + + let mut bytes: crate::Bytes = [0; 16]; + bytes.copy_from_slice(b); + Ok(Self::from_bytes(bytes)) + } + + /// Creates a `Builder` from four big-endian field values. + /// + /// # Errors + /// + /// This function will return an error if `d4`'s length is not 8 bytes. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// let d4 = [12, 3, 9, 56, 54, 43, 8, 9]; + /// + /// let builder = uuid::Builder::from_fields(42, 12, 5, &d4); + /// let uuid = + /// builder.map(|mut builder| builder.build().to_hyphenated().to_string()); + /// + /// let expected_uuid = + /// Ok(String::from("0000002a-000c-0005-0c03-0938362b0809")); + /// + /// assert_eq!(expected_uuid, uuid); + /// ``` + /// + /// An invalid length: + /// + /// ``` + /// let d4 = [12]; + /// + /// let builder = uuid::Builder::from_fields(42, 12, 5, &d4); + /// + /// assert!(builder.is_err()); + /// ``` + pub fn from_fields( + d1: u32, + d2: u16, + d3: u16, + d4: &[u8], + ) -> Result<Self, crate::Error> { + Uuid::from_fields(d1, d2, d3, d4).map(|uuid| { + let bytes = *uuid.as_bytes(); + + Builder::from_bytes(bytes) + }) + } + + /// Creates a `Builder` from a big-endian 128bit value. + pub fn from_u128(v: u128) -> Self { + Builder::from_bytes(*Uuid::from_u128(v).as_bytes()) + } + + /// Creates a `Builder` with an initial [`Uuid::nil`]. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use uuid::Builder; + /// + /// let mut builder = Builder::nil(); + /// + /// assert_eq!( + /// builder.build().to_hyphenated().to_string(), + /// "00000000-0000-0000-0000-000000000000" + /// ); + /// ``` + pub const fn nil() -> Self { + Builder([0; 16]) + } + + /// Specifies the variant of the UUID. + pub fn set_variant(&mut self, v: crate::Variant) -> &mut Self { + let byte = self.0[8]; + + self.0[8] = match v { + crate::Variant::NCS => byte & 0x7f, + crate::Variant::RFC4122 => (byte & 0x3f) | 0x80, + crate::Variant::Microsoft => (byte & 0x1f) | 0xc0, + crate::Variant::Future => (byte & 0x1f) | 0xe0, + }; + + self + } + + /// Specifies the version number of the UUID. + pub fn set_version(&mut self, v: crate::Version) -> &mut Self { + self.0[6] = (self.0[6] & 0x0f) | ((v as u8) << 4); + + self + } + + /// Hands over the internal constructed [`Uuid`]. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use uuid::Builder; + /// + /// let uuid = Builder::nil().build(); + /// + /// assert_eq!( + /// uuid.to_hyphenated().to_string(), + /// "00000000-0000-0000-0000-000000000000" + /// ); + /// ``` + /// + /// [`Uuid`]: struct.Uuid.html + pub fn build(&mut self) -> Uuid { + let uuid = Uuid::from_bytes(self.0); + + uuid + } +} diff --git a/third_party/rust/uuid/src/error.rs b/third_party/rust/uuid/src/error.rs new file mode 100644 index 0000000000..433432b98b --- /dev/null +++ b/third_party/rust/uuid/src/error.rs @@ -0,0 +1,79 @@ +use crate::std::fmt; +use crate::{builder, parser}; + +/// A general error that can occur when working with UUIDs. +// TODO: improve the doc +// BODY: This detail should be fine for initial merge +#[derive(Clone, Debug, Eq, Hash, PartialEq)] +pub struct Error(Inner); + +// TODO: write tests for Error +// BODY: not immediately blocking, but should be covered for 1.0 +#[derive(Clone, Debug, Eq, Hash, PartialEq)] +enum Inner { + /// An error occurred while handling [`Uuid`] bytes. + /// + /// See [`BytesError`] + /// + /// [`BytesError`]: struct.BytesError.html + /// [`Uuid`]: struct.Uuid.html + Build(builder::Error), + + /// An error occurred while parsing a [`Uuid`] string. + /// + /// See [`parser::ParseError`] + /// + /// [`parser::ParseError`]: parser/enum.ParseError.html + /// [`Uuid`]: struct.Uuid.html + Parser(parser::Error), +} + +impl From<builder::Error> for Error { + fn from(err: builder::Error) -> Self { + Error(Inner::Build(err)) + } +} + +impl From<parser::Error> for Error { + fn from(err: parser::Error) -> Self { + Error(Inner::Parser(err)) + } +} + +impl fmt::Display for Error { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self.0 { + Inner::Build(ref err) => fmt::Display::fmt(&err, f), + Inner::Parser(ref err) => fmt::Display::fmt(&err, f), + } + } +} + +#[cfg(feature = "std")] +mod std_support { + use super::*; + use crate::std::error; + + impl error::Error for Error { + fn source(&self) -> Option<&(dyn error::Error + 'static)> { + match self.0 { + Inner::Build(ref err) => Some(err), + Inner::Parser(ref err) => Some(err), + } + } + } +} + +#[cfg(test)] +mod test_util { + use super::*; + + impl Error { + pub(crate) fn expect_parser(self) -> parser::Error { + match self.0 { + Inner::Parser(err) => err, + _ => panic!("expected a `parser::Error` variant"), + } + } + } +} diff --git a/third_party/rust/uuid/src/lib.rs b/third_party/rust/uuid/src/lib.rs new file mode 100644 index 0000000000..c3d0d225d2 --- /dev/null +++ b/third_party/rust/uuid/src/lib.rs @@ -0,0 +1,1030 @@ +// 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 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Generate and parse UUIDs. +//! +//! Provides support for Universally Unique Identifiers (UUIDs). A UUID is a +//! unique 128-bit number, stored as 16 octets. 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. +//! +//! # Dependencies +//! +//! By default, this crate depends on nothing but `std` and cannot generate +//! UUIDs. You need to enable the following Cargo features to enable +//! various pieces of functionality: +//! +//! * `v1` - adds the [`Uuid::new_v1`] function and the ability to create a V1 +//! using an implementation of [`v1::ClockSequence`] (usually +//! [`v1::Context`]) and a timestamp from `time::timespec`. +//! * `v3` - adds the [`Uuid::new_v3`] function and the ability to create a V3 +//! UUID based on the MD5 hash of some data. +//! * `v4` - adds the [`Uuid::new_v4`] function and the ability to randomly +//! generate a UUID. +//! * `v5` - adds the [`Uuid::new_v5`] function and the ability to create a V5 +//! UUID based on the SHA1 hash of some data. +//! * `serde` - adds the ability to serialize and deserialize a UUID using the +//! `serde` crate. +//! +//! You need to enable one of the following Cargo features together with +//! `v3`, `v4` or `v5` feature if you're targeting `wasm32` architecture: +//! +//! * `stdweb` - enables support for `OsRng` on `wasm32-unknown-unknown` via +//! [`stdweb`] combined with [`cargo-web`] +//! * `wasm-bindgen` - enables support for `OsRng` on `wasm32-unknown-unknown` +//! via [`wasm-bindgen`] +//! +//! By default, `uuid` can be depended on with: +//! +//! ```toml +//! [dependencies] +//! uuid = "0.8" +//! ``` +//! +//! To activate various features, use syntax like: +//! +//! ```toml +//! [dependencies] +//! uuid = { version = "0.8", features = ["serde", "v4"] } +//! ``` +//! +//! You can disable default features with: +//! +//! ```toml +//! [dependencies] +//! uuid = { version = "0.8", default-features = false } +//! ``` +//! +//! # Examples +//! +//! To parse a UUID given in the simple format and print it as a urn: +//! +//! ```rust +//! use uuid::Uuid; +//! +//! fn main() { +//! let my_uuid = +//! Uuid::parse_str("936DA01F9ABD4d9d80C702AF85C822A8").unwrap(); +//! println!("{}", my_uuid.to_urn()); +//! } +//! ``` +//! +//! To create a new random (V4) UUID and print it out in hexadecimal form: +//! +//! ```ignore,rust +//! // Note that this requires the `v4` feature enabled in the uuid crate. +//! +//! use uuid::Uuid; +//! +//! fn main() { +//! let my_uuid = Uuid::new_v4(); +//! println!("{}", my_uuid); +//! } +//! ``` +//! +//! # Strings +//! +//! Examples of string representations: +//! +//! * simple: `936DA01F9ABD4d9d80C702AF85C822A8` +//! * hyphenated: `550e8400-e29b-41d4-a716-446655440000` +//! * urn: `urn:uuid:F9168C5E-CEB2-4faa-B6BF-329BF39FA1E4` +//! +//! # References +//! +//! * [Wikipedia: Universally Unique +//! Identifier](http://en.wikipedia.org/wiki/Universally_unique_identifier) +//! * [RFC4122: A Universally Unique IDentifier (UUID) URN +//! Namespace](http://tools.ietf.org/html/rfc4122) +//! +//! [`wasm-bindgen`]: https://crates.io/crates/wasm-bindgen +//! [`cargo-web`]: https://crates.io/crates/cargo-web +//! [`stdweb`]: https://crates.io/crates/stdweb +//! [`Uuid`]: struct.Uuid.html +//! [`Uuid::new_v1`]: struct.Uuid.html#method.new_v1 +//! [`Uuid::new_v3`]: struct.Uuid.html#method.new_v3 +//! [`Uuid::new_v4`]: struct.Uuid.html#method.new_v4 +//! [`Uuid::new_v5`]: struct.Uuid.html#method.new_v5 +//! [`v1::ClockSequence`]: v1/trait.ClockSequence.html +//! [`v1::Context`]: v1/struct.Context.html + +#![no_std] +#![deny(missing_debug_implementations, missing_docs)] +#![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/0.8.1" +)] + +#[cfg(any(feature = "std", test))] +#[macro_use] +extern crate std; + +#[cfg(all(not(feature = "std"), not(test)))] +#[macro_use] +extern crate core as std; + +mod builder; +mod error; +mod parser; +mod prelude; + +pub mod adapter; +#[cfg(feature = "v1")] +pub mod v1; + +#[cfg(feature = "serde")] +mod serde_support; +#[cfg(feature = "slog")] +mod slog_support; +#[cfg(test)] +mod test_util; +#[cfg(all( + feature = "v3", + any( + not(target_arch = "wasm32"), + all( + target_arch = "wasm32", + any(feature = "stdweb", feature = "wasm-bindgen") + ) + ) +))] +mod v3; +#[cfg(all( + feature = "v4", + any( + not(target_arch = "wasm32"), + all( + target_arch = "wasm32", + any(feature = "stdweb", feature = "wasm-bindgen") + ) + ) +))] +mod v4; +#[cfg(all( + feature = "v5", + any( + not(target_arch = "wasm32"), + all( + target_arch = "wasm32", + any(feature = "stdweb", feature = "wasm-bindgen") + ) + ) +))] +mod v5; +#[cfg(all(windows, feature = "winapi"))] +mod winapi_support; + +use crate::std::{fmt, str}; + +pub use crate::{builder::Builder, error::Error}; + +/// A 128-bit (16 byte) buffer containing the ID. +pub type Bytes = [u8; 16]; + +/// The version of the UUID, denoting the generating algorithm. +#[derive(Clone, Copy, Debug, PartialEq)] +pub enum Version { + /// Special case for `nil` UUID. + Nil = 0, + /// Version 1: MAC address. + Mac, + /// Version 2: DCE Security. + Dce, + /// Version 3: MD5 hash. + Md5, + /// Version 4: Random. + Random, + /// Version 5: SHA-1 hash. + Sha1, +} + +/// The reserved variants of UUIDs. +#[derive(Clone, Copy, Debug, PartialEq)] +pub enum Variant { + /// Reserved by the NCS for backward compatibility. + NCS = 0, + /// As described in the RFC4122 Specification (default). + RFC4122, + /// Reserved by Microsoft for backward compatibility. + Microsoft, + /// Reserved for future expansion. + Future, +} + +/// A Universally Unique Identifier (UUID). +#[derive(Clone, Copy, Eq, Hash, Ord, PartialEq, PartialOrd)] +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. + /// Currently only the RFC4122 variant is generated by this module. + /// + /// * [Variant Reference](http://tools.ietf.org/html/rfc4122#section-4.1.1) + pub fn get_variant(&self) -> Option<Variant> { + match self.as_bytes()[8] { + x if x & 0x80 == 0x00 => Some(Variant::NCS), + x if x & 0xc0 == 0x80 => Some(Variant::RFC4122), + x if x & 0xe0 == 0xc0 => Some(Variant::Microsoft), + x if x & 0xe0 == 0xe0 => Some(Variant::Future), + _ => None, + } + } + + /// Returns the version number of the UUID. + /// + /// This represents the algorithm used to generate the contents. + /// + /// Currently only the Random (V4) algorithm is supported by this + /// module. There are security and privacy implications for using + /// older versions - see [Wikipedia: Universally Unique Identifier]( + /// http://en.wikipedia.org/wiki/Universally_unique_identifier) for + /// details. + /// + /// * [Version Reference](http://tools.ietf.org/html/rfc4122#section-4.1.3) + 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 contents + pub fn get_version(&self) -> Option<Version> { + let v = self.as_bytes()[6] >> 4; + match v { + 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), + _ => None, + } + } + + /// Returns the four field values of the UUID in big-endian order. + /// + /// These values can be passed to the `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; + /// + /// let uuid = Uuid::nil(); + /// assert_eq!(uuid.as_fields(), (0, 0, 0, &[0u8; 8])); + /// + /// let uuid = Uuid::parse_str("936DA01F-9ABD-4D9D-80C7-02AF85C822A8").unwrap(); + /// assert_eq!( + /// uuid.as_fields(), + /// ( + /// 0x936DA01F, + /// 0x9ABD, + /// 0x4D9D, + /// b"\x80\xC7\x02\xAF\x85\xC8\x22\xA8" + /// ) + /// ); + /// ``` + pub fn as_fields(&self) -> (u32, u16, u16, &[u8; 8]) { + let d1 = u32::from(self.as_bytes()[0]) << 24 + | u32::from(self.as_bytes()[1]) << 16 + | u32::from(self.as_bytes()[2]) << 8 + | u32::from(self.as_bytes()[3]); + + let d2 = + u16::from(self.as_bytes()[4]) << 8 | u16::from(self.as_bytes()[5]); + + let d3 = + u16::from(self.as_bytes()[6]) << 8 | u16::from(self.as_bytes()[7]); + + let d4: &[u8; 8] = + unsafe { &*(self.as_bytes()[8..16].as_ptr() as *const [u8; 8]) }; + (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. + /// + /// # Examples + /// + /// ``` + /// use uuid::Uuid; + /// + /// let uuid = Uuid::parse_str("936DA01F-9ABD-4D9D-80C7-02AF85C822A8").unwrap(); + /// assert_eq!( + /// uuid.to_fields_le(), + /// ( + /// 0x1FA06D93, + /// 0xBD9A, + /// 0x9D4D, + /// b"\x80\xC7\x02\xAF\x85\xC8\x22\xA8" + /// ) + /// ); + /// ``` + pub fn to_fields_le(&self) -> (u32, u16, u16, &[u8; 8]) { + let d1 = u32::from(self.as_bytes()[0]) + | u32::from(self.as_bytes()[1]) << 8 + | u32::from(self.as_bytes()[2]) << 16 + | u32::from(self.as_bytes()[3]) << 24; + + let d2 = + u16::from(self.as_bytes()[4]) | u16::from(self.as_bytes()[5]) << 8; + + let d3 = + u16::from(self.as_bytes()[6]) | u16::from(self.as_bytes()[7]) << 8; + + let d4: &[u8; 8] = + unsafe { &*(self.as_bytes()[8..16].as_ptr() as *const [u8; 8]) }; + (d1, d2, d3, d4) + } + + /// Returns a 128bit value containing the UUID data. + /// + /// The bytes in the UUID will be packed into a `u128`, like the + /// [`Uuid::as_bytes`] method. + /// + /// # Examples + /// + /// ``` + /// use uuid::Uuid; + /// + /// let uuid = Uuid::parse_str("936DA01F-9ABD-4D9D-80C7-02AF85C822A8").unwrap(); + /// assert_eq!( + /// uuid.as_u128(), + /// 0x936DA01F9ABD4D9D80C702AF85C822A8, + /// ) + /// ``` + pub fn as_u128(&self) -> u128 { + u128::from(self.as_bytes()[0]) << 120 + | u128::from(self.as_bytes()[1]) << 112 + | u128::from(self.as_bytes()[2]) << 104 + | u128::from(self.as_bytes()[3]) << 96 + | u128::from(self.as_bytes()[4]) << 88 + | u128::from(self.as_bytes()[5]) << 80 + | u128::from(self.as_bytes()[6]) << 72 + | u128::from(self.as_bytes()[7]) << 64 + | u128::from(self.as_bytes()[8]) << 56 + | u128::from(self.as_bytes()[9]) << 48 + | u128::from(self.as_bytes()[10]) << 40 + | u128::from(self.as_bytes()[11]) << 32 + | u128::from(self.as_bytes()[12]) << 24 + | u128::from(self.as_bytes()[13]) << 16 + | u128::from(self.as_bytes()[14]) << 8 + | u128::from(self.as_bytes()[15]) + } + + /// Returns a 128bit little-endian value containing the UUID data. + /// + /// The bytes in the UUID will be reversed and packed into a `u128`. + /// 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; + /// + /// let uuid = Uuid::parse_str("936DA01F-9ABD-4D9D-80C7-02AF85C822A8").unwrap(); + /// + /// assert_eq!( + /// uuid.to_u128_le(), + /// 0xA822C885AF02C7809D4DBD9A1FA06D93, + /// ) + /// ``` + pub fn to_u128_le(&self) -> u128 { + u128::from(self.as_bytes()[0]) + | u128::from(self.as_bytes()[1]) << 8 + | u128::from(self.as_bytes()[2]) << 16 + | u128::from(self.as_bytes()[3]) << 24 + | u128::from(self.as_bytes()[4]) << 32 + | u128::from(self.as_bytes()[5]) << 40 + | u128::from(self.as_bytes()[6]) << 48 + | u128::from(self.as_bytes()[7]) << 56 + | u128::from(self.as_bytes()[8]) << 64 + | u128::from(self.as_bytes()[9]) << 72 + | u128::from(self.as_bytes()[10]) << 80 + | u128::from(self.as_bytes()[11]) << 88 + | u128::from(self.as_bytes()[12]) << 96 + | u128::from(self.as_bytes()[13]) << 104 + | u128::from(self.as_bytes()[14]) << 112 + | u128::from(self.as_bytes()[15]) << 120 + } + + /// Returns an array of 16 octets containing the UUID data. + pub const fn as_bytes(&self) -> &Bytes { + &self.0 + } + + /// Tests if the UUID is nil. + pub fn is_nil(&self) -> bool { + self.as_bytes().iter().all(|&b| b == 0) + } + + /// A buffer that can be used for `encode_...` calls, that is + /// guaranteed to be long enough for any of the adapters. + /// + /// # Examples + /// + /// ```rust + /// use uuid::Uuid; + /// + /// let uuid = Uuid::nil(); + /// + /// assert_eq!( + /// uuid.to_simple().encode_lower(&mut Uuid::encode_buffer()), + /// "00000000000000000000000000000000" + /// ); + /// + /// assert_eq!( + /// uuid.to_hyphenated() + /// .encode_lower(&mut Uuid::encode_buffer()), + /// "00000000-0000-0000-0000-000000000000" + /// ); + /// + /// assert_eq!( + /// uuid.to_urn().encode_lower(&mut Uuid::encode_buffer()), + /// "urn:uuid:00000000-0000-0000-0000-000000000000" + /// ); + /// ``` + pub const fn encode_buffer() -> [u8; adapter::Urn::LENGTH] { + [0; adapter::Urn::LENGTH] + } +} + +impl 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) + } +} + +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.to_hyphenated_ref(), f) + } +} + +impl fmt::UpperHex for Uuid { + #[inline] + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::UpperHex::fmt(&self.to_hyphenated_ref(), f) + } +} + +impl str::FromStr for Uuid { + type Err = Error; + + fn from_str(uuid_str: &str) -> Result<Self, Self::Err> { + Uuid::parse_str(uuid_str) + } +} + +impl Default for Uuid { + #[inline] + fn default() -> Self { + Uuid::nil() + } +} + +#[cfg(test)] +mod tests { + use crate::{ + prelude::*, + std::string::{String, ToString}, + test_util, + }; + + 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); + }; + } + + #[test] + fn test_uuid_compare() { + let uuid1 = test_util::new(); + let uuid2 = test_util::new2(); + + assert_eq!(uuid1, uuid1); + assert_eq!(uuid2, uuid2); + + assert_ne!(uuid1, uuid2); + assert_ne!(uuid2, uuid1); + } + + #[test] + fn test_uuid_default() { + let default_uuid = Uuid::default(); + let nil_uuid = Uuid::nil(); + + assert_eq!(default_uuid, nil_uuid); + } + + #[test] + fn test_uuid_display() { + use super::fmt::Write; + + let uuid = test_util::new(); + let s = uuid.to_string(); + let mut buffer = String::new(); + + assert_eq!(s, uuid.to_hyphenated().to_string()); + + check!(buffer, "{}", uuid, 36, |c| c.is_lowercase() + || c.is_digit(10) + || c == '-'); + } + + #[test] + fn test_uuid_lowerhex() { + use super::fmt::Write; + + let mut buffer = String::new(); + let uuid = test_util::new(); + + check!(buffer, "{:x}", uuid, 36, |c| c.is_lowercase() + || c.is_digit(10) + || c == '-'); + } + + // noinspection RsAssertEqual + #[test] + fn test_uuid_operator_eq() { + let uuid1 = test_util::new(); + let uuid1_dup = uuid1.clone(); + let uuid2 = test_util::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] + fn test_uuid_to_string() { + use super::fmt::Write; + + let uuid = test_util::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] + fn test_uuid_upperhex() { + use super::fmt::Write; + + let mut buffer = String::new(); + let uuid = test_util::new(); + + check!(buffer, "{:X}", uuid, 36, |c| c.is_uppercase() + || c.is_digit(10) + || c == '-'); + } + + #[test] + fn test_nil() { + let nil = Uuid::nil(); + let not_nil = test_util::new(); + 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); + + 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)) + } + + #[test] + fn test_predefined_namespaces() { + assert_eq!( + Uuid::NAMESPACE_DNS.to_hyphenated().to_string(), + "6ba7b810-9dad-11d1-80b4-00c04fd430c8" + ); + assert_eq!( + Uuid::NAMESPACE_URL.to_hyphenated().to_string(), + "6ba7b811-9dad-11d1-80b4-00c04fd430c8" + ); + assert_eq!( + Uuid::NAMESPACE_OID.to_hyphenated().to_string(), + "6ba7b812-9dad-11d1-80b4-00c04fd430c8" + ); + assert_eq!( + Uuid::NAMESPACE_X500.to_hyphenated().to_string(), + "6ba7b814-9dad-11d1-80b4-00c04fd430c8" + ); + } + + #[cfg(feature = "v3")] + #[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] + fn test_get_variant() { + let uuid1 = test_util::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().unwrap(), Variant::RFC4122); + assert_eq!(uuid2.get_variant().unwrap(), Variant::RFC4122); + assert_eq!(uuid3.get_variant().unwrap(), Variant::RFC4122); + assert_eq!(uuid4.get_variant().unwrap(), Variant::Microsoft); + assert_eq!(uuid5.get_variant().unwrap(), Variant::Microsoft); + assert_eq!(uuid6.get_variant().unwrap(), Variant::NCS); + } + + #[test] + fn test_to_simple_string() { + let uuid1 = test_util::new(); + let s = uuid1.to_simple().to_string(); + + assert_eq!(s.len(), 32); + assert!(s.chars().all(|c| c.is_digit(16))); + } + + #[test] + fn test_to_hyphenated_string() { + let uuid1 = test_util::new(); + let s = uuid1.to_hyphenated().to_string(); + + assert!(s.len() == 36); + assert!(s.chars().all(|c| c.is_digit(16) || c == '-')); + } + + #[test] + fn test_upper_lower_hex() { + use std::fmt::Write; + + let mut buf = String::new(); + let u = test_util::new(); + + 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); + }; + } + + check!(buf, "{:X}", u, 36, |c| c.is_uppercase() + || c.is_digit(10) + || c == '-'); + check!(buf, "{:X}", u.to_hyphenated(), 36, |c| c.is_uppercase() + || c.is_digit(10) + || c == '-'); + check!(buf, "{:X}", u.to_simple(), 32, |c| c.is_uppercase() + || c.is_digit(10)); + + check!(buf, "{:x}", u.to_hyphenated(), 36, |c| c.is_lowercase() + || c.is_digit(10) + || c == '-'); + check!(buf, "{:x}", u.to_simple(), 32, |c| c.is_lowercase() + || c.is_digit(10)); + } + + #[test] + fn test_to_urn_string() { + let uuid1 = test_util::new(); + let ss = uuid1.to_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] + fn test_to_simple_string_matching() { + let uuid1 = test_util::new(); + + let hs = uuid1.to_hyphenated().to_string(); + let ss = uuid1.to_simple().to_string(); + + let hsn = hs.chars().filter(|&c| c != '-').collect::<String>(); + + assert_eq!(hsn, ss); + } + + #[test] + fn test_string_roundtrip() { + let uuid = test_util::new(); + + let hs = uuid.to_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] + 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).unwrap(); + + let expected = "a1a2a3a4b1b2c1c2d1d2d3d4d5d6d7d8"; + let result = u.to_simple().to_string(); + assert_eq!(result, expected); + } + + #[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).unwrap(); + + let expected = "a1a2a3a4b1b2c1c2d1d2d3d4d5d6d7d8"; + let result = u.to_simple().to_string(); + assert_eq!(result, expected); + } + + #[test] + fn test_as_fields() { + let u = test_util::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] + 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).unwrap(); + 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] + 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).unwrap(); + 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] + 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).unwrap(); + 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] + fn test_from_u128() { + let v_in: u128 = 0xa1a2a3a4b1b2c1c2d1d2d3d4d5d6d7d8; + + let u = Uuid::from_u128(v_in); + + let expected = "a1a2a3a4b1b2c1c2d1d2d3d4d5d6d7d8"; + let result = u.to_simple().to_string(); + assert_eq!(result, expected); + } + + #[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.to_simple().to_string(); + assert_eq!(result, expected); + } + + #[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] + 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] + 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] + 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.to_simple().to_string(), expected); + } + + #[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.to_simple().to_string(), expected); + } + + #[test] + fn test_as_bytes() { + let u = test_util::new(); + let ub = u.as_bytes(); + + assert_eq!(ub.len(), 16); + assert!(!ub.iter().all(|&b| b == 0)); + } + + #[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] + fn test_iterbytes_impl_for_uuid() { + let mut set = std::collections::HashSet::new(); + let id1 = test_util::new(); + let id2 = test_util::new2(); + set.insert(id1.clone()); + + assert!(set.contains(&id1)); + assert!(!set.contains(&id2)); + } +} diff --git a/third_party/rust/uuid/src/parser/error.rs b/third_party/rust/uuid/src/parser/error.rs new file mode 100644 index 0000000000..39d502f3be --- /dev/null +++ b/third_party/rust/uuid/src/parser/error.rs @@ -0,0 +1,148 @@ +use crate::std::fmt; + +/// An error that can occur while parsing a [`Uuid`] string. +/// +/// [`Uuid`]: ../struct.Uuid.html +#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] +pub(crate) enum Error { + /// Invalid character in the [`Uuid`] string. + /// + /// [`Uuid`]: ../struct.Uuid.html + InvalidCharacter { + /// The expected characters. + expected: &'static str, + /// The invalid character found. + found: char, + /// The invalid character position. + index: usize, + /// Indicates the [`Uuid`] starts with `urn:uuid:`. + /// + /// This is a special case for [`Urn`] adapter parsing. + /// + /// [`Uuid`]: ../Uuid.html + urn: UrnPrefix, + }, + /// Invalid number of segments in the [`Uuid`] string. + /// + /// [`Uuid`]: ../struct.Uuid.html + InvalidGroupCount { + /// The expected number of segments. + // TODO: explain multiple segment count. + // BODY: Parsers can expect a range of Uuid segment count. + // This needs to be expanded on. + expected: ExpectedLength, + /// The number of segments found. + found: usize, + }, + /// Invalid length of a segment in a [`Uuid`] string. + /// + /// [`Uuid`]: ../struct.Uuid.html + InvalidGroupLength { + /// The expected length of the segment. + expected: ExpectedLength, + /// The length of segment found. + found: usize, + /// The segment with invalid length. + group: usize, + }, + /// Invalid length of the [`Uuid`] string. + /// + /// [`Uuid`]: ../struct.Uuid.html + InvalidLength { + /// The expected length(s). + // TODO: explain multiple lengths. + // BODY: Parsers can expect a range of Uuid lenghts. + // This needs to be expanded on. + expected: ExpectedLength, + /// The invalid length found. + found: usize, + }, +} + +/// The expected length. +#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] +pub(crate) enum ExpectedLength { + /// Expected any one of the given values. + Any(&'static [usize]), + /// Expected the given value. + Exact(usize), +} + +/// Urn prefix value. +#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] +pub(crate) enum UrnPrefix { + /// The `urn:uuid:` prefix should optionally provided. + Optional, +} + +impl Error { + fn _description(&self) -> &str { + match *self { + Error::InvalidCharacter { .. } => "invalid character", + Error::InvalidGroupCount { .. } => "invalid number of groups", + Error::InvalidGroupLength { .. } => "invalid group length", + Error::InvalidLength { .. } => "invalid length", + } + } +} + +impl fmt::Display for ExpectedLength { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match *self { + ExpectedLength::Any(crits) => write!(f, "one of {:?}", crits), + ExpectedLength::Exact(crit) => write!(f, "{}", crit), + } + } +} + +impl fmt::Display for Error { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}: ", self._description())?; + + match *self { + Error::InvalidCharacter { + expected, + found, + index, + urn, + } => { + let urn_str = match urn { + UrnPrefix::Optional => { + " an optional prefix of `urn:uuid:` followed by" + } + }; + + write!( + f, + "expected{} {}, found {} at {}", + urn_str, expected, found, index + ) + } + Error::InvalidGroupCount { + ref expected, + found, + } => write!(f, "expected {}, found {}", expected, found), + Error::InvalidGroupLength { + ref expected, + found, + group, + } => write!( + f, + "expected {}, found {} in group {}", + expected, found, group, + ), + Error::InvalidLength { + ref expected, + found, + } => write!(f, "expected {}, found {}", expected, found), + } + } +} + +#[cfg(feature = "std")] +mod std_support { + use super::*; + use crate::std::error; + + impl error::Error for Error {} +} diff --git a/third_party/rust/uuid/src/parser/mod.rs b/third_party/rust/uuid/src/parser/mod.rs new file mode 100644 index 0000000000..f5a2e436b4 --- /dev/null +++ b/third_party/rust/uuid/src/parser/mod.rs @@ -0,0 +1,447 @@ +// 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 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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 + +pub(crate) mod error; +pub(crate) use self::error::Error; + +use crate::{adapter, Uuid}; + +/// Check if the length matches any of the given criteria lengths. +fn len_matches_any(len: usize, crits: &[usize]) -> bool { + for crit in crits { + if len == *crit { + return true; + } + } + + false +} + +/// Check if the length matches any criteria lengths in the given range +/// (inclusive). +#[allow(dead_code)] +fn len_matches_range(len: usize, min: usize, max: usize) -> bool { + for crit in min..(max + 1) { + if len == crit { + return true; + } + } + + false +} + +// Accumulated length of each hyphenated group in hex digits. +const ACC_GROUP_LENS: [usize; 5] = [8, 12, 16, 20, 32]; + +// Length of each hyphenated group in hex digits. +const GROUP_LENS: [usize; 5] = [8, 4, 4, 4, 12]; + +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) + /// are supported by this parsing function. + pub fn parse_str(mut input: &str) -> Result<Uuid, crate::Error> { + // Ensure length is valid for any of the supported formats + let len = input.len(); + + if len == adapter::Urn::LENGTH && input.starts_with("urn:uuid:") { + input = &input[9..]; + } else if !len_matches_any( + len, + &[adapter::Hyphenated::LENGTH, adapter::Simple::LENGTH], + ) { + Err(Error::InvalidLength { + expected: error::ExpectedLength::Any(&[ + adapter::Hyphenated::LENGTH, + adapter::Simple::LENGTH, + ]), + found: len, + })?; + } + + // `digit` counts only hexadecimal digits, `i_char` counts all chars. + let mut digit = 0; + let mut group = 0; + let mut acc = 0; + let mut buffer = [0u8; 16]; + + for (i_char, chr) in input.bytes().enumerate() { + if digit as usize >= adapter::Simple::LENGTH && group != 4 { + if group == 0 { + Err(Error::InvalidLength { + expected: error::ExpectedLength::Any(&[ + adapter::Hyphenated::LENGTH, + adapter::Simple::LENGTH, + ]), + found: len, + })?; + } + + Err(Error::InvalidGroupCount { + expected: error::ExpectedLength::Any(&[1, 5]), + found: group + 1, + })?; + } + + if digit % 2 == 0 { + // First digit of the byte. + match chr { + // Calulate upper half. + b'0'..=b'9' => acc = chr - b'0', + b'a'..=b'f' => acc = chr - b'a' + 10, + b'A'..=b'F' => acc = chr - b'A' + 10, + // Found a group delimiter + b'-' => { + // TODO: remove the u8 cast + // BODY: this only needed until we switch to + // ParseError + if ACC_GROUP_LENS[group] as u8 != digit { + // Calculate how many digits this group consists of + // in the input. + let found = if group > 0 { + // TODO: remove the u8 cast + // BODY: this only needed until we switch to + // ParseError + digit - ACC_GROUP_LENS[group - 1] as u8 + } else { + digit + }; + + Err(Error::InvalidGroupLength { + expected: error::ExpectedLength::Exact( + GROUP_LENS[group], + ), + found: found as usize, + group, + })?; + } + // Next group, decrement digit, it is incremented again + // at the bottom. + group += 1; + digit -= 1; + } + _ => { + Err(Error::InvalidCharacter { + expected: "0123456789abcdefABCDEF-", + found: input[i_char..].chars().next().unwrap(), + index: i_char, + urn: error::UrnPrefix::Optional, + })?; + } + } + } else { + // Second digit of the byte, shift the upper half. + acc *= 16; + match chr { + b'0'..=b'9' => acc += chr - b'0', + b'a'..=b'f' => acc += chr - b'a' + 10, + b'A'..=b'F' => acc += chr - b'A' + 10, + b'-' => { + // The byte isn't complete yet. + let found = if group > 0 { + // TODO: remove the u8 cast + // BODY: this only needed until we switch to + // ParseError + digit - ACC_GROUP_LENS[group - 1] as u8 + } else { + digit + }; + + Err(Error::InvalidGroupLength { + expected: error::ExpectedLength::Exact( + GROUP_LENS[group], + ), + found: found as usize, + group, + })?; + } + _ => { + Err(Error::InvalidCharacter { + expected: "0123456789abcdefABCDEF-", + found: input[i_char..].chars().next().unwrap(), + index: i_char, + urn: error::UrnPrefix::Optional, + })?; + } + } + buffer[(digit / 2) as usize] = acc; + } + digit += 1; + } + + // Now check the last group. + // TODO: remove the u8 cast + // BODY: this only needed until we switch to + // ParseError + if ACC_GROUP_LENS[4] as u8 != digit { + Err(Error::InvalidGroupLength { + expected: error::ExpectedLength::Exact(GROUP_LENS[4]), + found: (digit as usize - ACC_GROUP_LENS[3]), + group, + })?; + } + + Ok(Uuid::from_bytes(buffer)) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::{adapter, std::string::ToString, test_util}; + + #[test] + fn test_parse_uuid_v4() { + const EXPECTED_UUID_LENGTHS: error::ExpectedLength = + error::ExpectedLength::Any(&[ + adapter::Hyphenated::LENGTH, + adapter::Simple::LENGTH, + ]); + + const EXPECTED_GROUP_COUNTS: error::ExpectedLength = + error::ExpectedLength::Any(&[1, 5]); + + const EXPECTED_CHARS: &'static str = "0123456789abcdefABCDEF-"; + + // Invalid + assert_eq!( + Uuid::parse_str("").map_err(crate::Error::expect_parser), + Err(Error::InvalidLength { + expected: EXPECTED_UUID_LENGTHS, + found: 0, + }) + ); + + assert_eq!( + Uuid::parse_str("!").map_err(crate::Error::expect_parser), + Err(Error::InvalidLength { + expected: EXPECTED_UUID_LENGTHS, + found: 1 + }) + ); + + assert_eq!( + Uuid::parse_str("F9168C5E-CEB2-4faa-B6BF-329BF39FA1E45") + .map_err(crate::Error::expect_parser), + Err(Error::InvalidLength { + expected: EXPECTED_UUID_LENGTHS, + found: 37, + }) + ); + + assert_eq!( + Uuid::parse_str("F9168C5E-CEB2-4faa-BBF-329BF39FA1E4") + .map_err(crate::Error::expect_parser), + Err(Error::InvalidLength { + expected: EXPECTED_UUID_LENGTHS, + found: 35 + }) + ); + + assert_eq!( + Uuid::parse_str("F9168C5E-CEB2-4faa-BGBF-329BF39FA1E4") + .map_err(crate::Error::expect_parser), + Err(Error::InvalidCharacter { + expected: EXPECTED_CHARS, + found: 'G', + index: 20, + urn: error::UrnPrefix::Optional, + }) + ); + + assert_eq!( + Uuid::parse_str("F9168C5E-CEB2F4faaFB6BFF329BF39FA1E4") + .map_err(crate::Error::expect_parser), + Err(Error::InvalidGroupCount { + expected: EXPECTED_GROUP_COUNTS, + found: 2 + }) + ); + + assert_eq!( + Uuid::parse_str("F9168C5E-CEB2-4faaFB6BFF329BF39FA1E4") + .map_err(crate::Error::expect_parser), + Err(Error::InvalidGroupCount { + expected: EXPECTED_GROUP_COUNTS, + found: 3, + }) + ); + + assert_eq!( + Uuid::parse_str("F9168C5E-CEB2-4faa-B6BFF329BF39FA1E4") + .map_err(crate::Error::expect_parser), + Err(Error::InvalidGroupCount { + expected: EXPECTED_GROUP_COUNTS, + found: 4, + }) + ); + + assert_eq!( + Uuid::parse_str("F9168C5E-CEB2-4faa") + .map_err(crate::Error::expect_parser), + Err(Error::InvalidLength { + expected: EXPECTED_UUID_LENGTHS, + found: 18, + }) + ); + + assert_eq!( + Uuid::parse_str("F9168C5E-CEB2-4faaXB6BFF329BF39FA1E4") + .map_err(crate::Error::expect_parser), + Err(Error::InvalidCharacter { + expected: EXPECTED_CHARS, + found: 'X', + index: 18, + urn: error::UrnPrefix::Optional, + }) + ); + + assert_eq!( + Uuid::parse_str("F9168C5E-CEB-24fa-eB6BFF32-BF39FA1E4") + .map_err(crate::Error::expect_parser), + Err(Error::InvalidGroupLength { + expected: error::ExpectedLength::Exact(4), + found: 3, + group: 1, + }) + ); + // (group, found, expecting) + // + assert_eq!( + Uuid::parse_str("01020304-1112-2122-3132-41424344") + .map_err(crate::Error::expect_parser), + Err(Error::InvalidGroupLength { + expected: error::ExpectedLength::Exact(12), + found: 8, + group: 4, + }) + ); + + assert_eq!( + Uuid::parse_str("67e5504410b1426f9247bb680e5fe0c") + .map_err(crate::Error::expect_parser), + Err(Error::InvalidLength { + expected: EXPECTED_UUID_LENGTHS, + found: 31, + }) + ); + + assert_eq!( + Uuid::parse_str("67e5504410b1426f9247bb680e5fe0c88") + .map_err(crate::Error::expect_parser), + Err(Error::InvalidLength { + expected: EXPECTED_UUID_LENGTHS, + found: 33, + }) + ); + + assert_eq!( + Uuid::parse_str("67e5504410b1426f9247bb680e5fe0cg8") + .map_err(crate::Error::expect_parser), + Err(Error::InvalidLength { + expected: EXPECTED_UUID_LENGTHS, + found: 33, + }) + ); + + assert_eq!( + Uuid::parse_str("67e5504410b1426%9247bb680e5fe0c8") + .map_err(crate::Error::expect_parser), + Err(Error::InvalidCharacter { + expected: EXPECTED_CHARS, + found: '%', + index: 15, + urn: error::UrnPrefix::Optional, + }) + ); + + assert_eq!( + Uuid::parse_str("231231212212423424324323477343246663") + .map_err(crate::Error::expect_parser), + Err(Error::InvalidLength { + expected: EXPECTED_UUID_LENGTHS, + found: 36, + }) + ); + + // Valid + 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()); + + // 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 + ); + + // Round-trip + let uuid_orig = test_util::new(); + let orig_str = uuid_orig.to_string(); + let uuid_out = Uuid::parse_str(&orig_str).unwrap(); + assert_eq!(uuid_orig, uuid_out); + + // Test error reporting + assert_eq!( + Uuid::parse_str("67e5504410b1426f9247bb680e5fe0c") + .map_err(crate::Error::expect_parser), + Err(Error::InvalidLength { + expected: EXPECTED_UUID_LENGTHS, + found: 31, + }) + ); + assert_eq!( + Uuid::parse_str("67e550X410b1426f9247bb680e5fe0cd") + .map_err(crate::Error::expect_parser), + Err(Error::InvalidCharacter { + expected: EXPECTED_CHARS, + found: 'X', + index: 6, + urn: error::UrnPrefix::Optional, + }) + ); + assert_eq!( + Uuid::parse_str("67e550-4105b1426f9247bb680e5fe0c") + .map_err(crate::Error::expect_parser), + Err(Error::InvalidGroupLength { + expected: error::ExpectedLength::Exact(8), + found: 6, + group: 0, + }) + ); + assert_eq!( + Uuid::parse_str("F9168C5E-CEB2-4faa-B6BF1-02BF39FA1E4") + .map_err(crate::Error::expect_parser), + Err(Error::InvalidGroupLength { + expected: error::ExpectedLength::Exact(4), + found: 5, + group: 3, + }) + ); + } +} diff --git a/third_party/rust/uuid/src/prelude.rs b/third_party/rust/uuid/src/prelude.rs new file mode 100644 index 0000000000..ebacc1b30c --- /dev/null +++ b/third_party/rust/uuid/src/prelude.rs @@ -0,0 +1,47 @@ +// 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 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! The [`uuid`] prelude. +//! +//! This module contains the most important items of the [`uuid`] crate. +//! +//! To use the prelude, include the following in your crate root: +//! +//! ```rust +//! extern crate uuid; +//! ``` +//! +//! # Prelude Contents +//! +//! Currently the prelude reexports the following: +//! +//! [`uuid`]`::{`[`Error`], [`Uuid`], [`Variant`], [`Version`], +//! builder::[`Builder`]`}`: The fundamental types used in [`uuid`] crate. +//! +//! [`uuid`]: ../index.html +//! [`Error`]: ../enum.Error.html +//! [`Uuid`]: ../struct.Uuid.html +//! [`Variant`]: ../enum.Variant.html +//! [`Version`]: ../enum.Version.html +//! [`Builder`]: ../builder/struct.Builder.html +//! +#![cfg_attr(feature = "v1", +doc = " +[`uuid::v1`]`::{`[`ClockSequence`],[`Context`]`}`: The types useful for +handling uuid version 1. Requires feature `v1`. + +[`uuid::v1`]: ../v1/index.html +[`Context`]: ../v1/struct.Context.html +[`ClockSequence`]: ../v1/trait.ClockSequence.html")] + +pub use super::{Builder, Bytes, Error, Uuid, Variant, Version}; +#[cfg(feature = "v1")] +pub use crate::v1::{ClockSequence, Context}; diff --git a/third_party/rust/uuid/src/serde_support.rs b/third_party/rust/uuid/src/serde_support.rs new file mode 100644 index 0000000000..d0baf67123 --- /dev/null +++ b/third_party/rust/uuid/src/serde_support.rs @@ -0,0 +1,120 @@ +// 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 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use crate::prelude::*; +use core::fmt; +use serde::{de, Deserialize, Deserializer, Serialize, Serializer}; + +#[cfg(feature = "serde")] +impl Serialize for Uuid { + fn serialize<S: Serializer>( + &self, + serializer: S, + ) -> Result<S::Ok, S::Error> { + if serializer.is_human_readable() { + serializer + .serialize_str(&self.to_hyphenated().encode_lower(&mut [0; 36])) + } else { + serializer.serialize_bytes(self.as_bytes()) + } + } +} + +#[cfg(feature = "serde")] +impl<'de> Deserialize<'de> for Uuid { + fn deserialize<D: Deserializer<'de>>( + deserializer: D, + ) -> Result<Self, D::Error> { + if deserializer.is_human_readable() { + struct UuidStringVisitor; + + impl<'vi> de::Visitor<'vi> for UuidStringVisitor { + type Value = Uuid; + + fn expecting( + &self, + formatter: &mut fmt::Formatter<'_>, + ) -> fmt::Result { + write!(formatter, "a UUID string") + } + + fn visit_str<E: de::Error>( + self, + value: &str, + ) -> Result<Uuid, E> { + value.parse::<Uuid>().map_err(E::custom) + } + + fn visit_bytes<E: de::Error>( + self, + value: &[u8], + ) -> Result<Uuid, E> { + Uuid::from_slice(value).map_err(E::custom) + } + } + + deserializer.deserialize_str(UuidStringVisitor) + } 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<E: de::Error>( + self, + value: &[u8], + ) -> Result<Uuid, E> { + Uuid::from_slice(value).map_err(E::custom) + } + } + + deserializer.deserialize_bytes(UuidBytesVisitor) + } + } +} + +#[cfg(all(test, feature = "serde"))] +mod serde_tests { + use serde_test; + + use crate::prelude::*; + + #[test] + fn test_serialize_readable() { + use serde_test::Configure; + + let uuid_str = "f9168c5e-ceb2-4faa-b6bf-329bf39fa1e4"; + let u = Uuid::parse_str(uuid_str).unwrap(); + serde_test::assert_tokens( + &u.readable(), + &[serde_test::Token::Str(uuid_str)], + ); + } + + #[test] + fn test_serialize_compact() { + use serde_test::Configure; + + 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(uuid_bytes)], + ); + } +} diff --git a/third_party/rust/uuid/src/slog_support.rs b/third_party/rust/uuid/src/slog_support.rs new file mode 100644 index 0000000000..4046ae9040 --- /dev/null +++ b/third_party/rust/uuid/src/slog_support.rs @@ -0,0 +1,39 @@ +// 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 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use crate::prelude::*; +use slog; + +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 { + + #[test] + fn test_slog_kv() { + use crate::test_util; + use slog; + use slog::{crit, Drain}; + + let root = slog::Logger::root(slog::Discard.fuse(), slog::o!()); + let u1 = test_util::new(); + crit!(root, "test"; "u1" => u1); + } +} diff --git a/third_party/rust/uuid/src/test_util.rs b/third_party/rust/uuid/src/test_util.rs new file mode 100644 index 0000000000..9eec117507 --- /dev/null +++ b/third_party/rust/uuid/src/test_util.rs @@ -0,0 +1,26 @@ +// 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 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use crate::prelude::*; + +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, + ]) +} diff --git a/third_party/rust/uuid/src/v1.rs b/third_party/rust/uuid/src/v1.rs new file mode 100644 index 0000000000..8bd98a4773 --- /dev/null +++ b/third_party/rust/uuid/src/v1.rs @@ -0,0 +1,325 @@ +//! The implementation for Version 1 UUIDs. +//! +//! Note that you need feature `v1` in order to use these features. + +use crate::prelude::*; +use core::sync::atomic; + +/// The number of 100 ns ticks between the UUID epoch +/// `1582-10-15 00:00:00` and the Unix epoch `1970-01-01 00:00:00`. +const UUID_TICKS_BETWEEN_EPOCHS: u64 = 0x01B2_1DD2_1381_4000; + +/// A thread-safe, stateful context for the v1 generator to help ensure +/// process-wide uniqueness. +#[derive(Debug)] +pub struct Context { + count: atomic::AtomicUsize, +} + +/// Stores the number of nanoseconds from an epoch and a counter for ensuring +/// V1 ids generated on the same host are unique. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub struct Timestamp { + ticks: u64, + counter: u16, +} + +impl Timestamp { + /// Construct a `Timestamp` from its raw component values: an RFC4122 + /// timestamp and counter. + /// + /// RFC4122, which defines the V1 UUID, specifies a 60-byte timestamp format + /// as the number of 100-nanosecond intervals elapsed since 00:00:00.00, + /// 15 Oct 1582, "the date of the Gregorian reform of the Christian + /// calendar." + /// + /// The counter value is used to differentiate between ids generated by + /// the same host computer in rapid succession (i.e. with the same observed + /// time). See the [`ClockSequence`] trait for a generic interface to any + /// counter generators that might be used. + /// + /// Internally, the timestamp is stored as a `u64`. For this reason, dates + /// prior to October 1582 are not supported. + /// + /// [`ClockSequence`]: trait.ClockSequence.html + pub const fn from_rfc4122(ticks: u64, counter: u16) -> Self { + Timestamp { ticks, counter } + } + + /// Construct a `Timestamp` from a unix timestamp and sequence-generating + /// `context`. + /// + /// A unix timestamp represents the elapsed time since Jan 1 1970. Libc's + /// `clock_gettime` and other popular implementations traditionally + /// represent this duration as a `timespec`: a struct with `u64` and + /// `u32` fields representing the seconds, and "subsecond" or fractional + /// nanoseconds elapsed since the timestamp's second began, + /// respectively. + /// + /// This constructs a `Timestamp` from the seconds and fractional + /// nanoseconds of a unix timestamp, converting the duration since 1970 + /// into the number of 100-nanosecond intervals since 00:00:00.00, 15 + /// Oct 1982 specified by RFC4122 and used internally by `Timestamp`. + /// + /// The function is not guaranteed to produce monotonically increasing + /// values however. There is a slight possibility that two successive + /// equal time values could be supplied and the sequence counter wraps back + /// over to 0. + /// + /// If uniqueness and monotonicity is required, the user is responsible for + /// ensuring that the time value always increases between calls (including + /// between restarts of the process and device). + pub fn from_unix( + context: impl ClockSequence, + seconds: u64, + subsec_nanos: u32, + ) -> Self { + let counter = context.generate_sequence(seconds, subsec_nanos); + let ticks = UUID_TICKS_BETWEEN_EPOCHS + + seconds * 10_000_000 + + (subsec_nanos as u64 / 100); + Timestamp { ticks, counter } + } + + /// Returns the raw RFC4122 timestamp and counter values stored by the + /// `Timestamp`. + /// + /// The timestamp (the first, `u64` element in the tuple) represents the + /// number of 100-nanosecond intervals since 00:00:00.00, 15 Oct 1582. + /// The counter is used to differentiate between ids generated on the + /// same host computer with the same observed time. + pub const fn to_rfc4122(&self) -> (u64, u16) { + (self.ticks, self.counter) + } + + /// Returns the timestamp converted to the seconds and fractional + /// nanoseconds since Jan 1 1970. + /// + /// Internally, the time is stored in 100-nanosecond intervals, + /// thus the maximum precision represented by the fractional nanoseconds + /// value is less than its unit size (100 ns vs. 1 ns). + pub const fn to_unix(&self) -> (u64, u32) { + let unix_ticks = self.ticks - UUID_TICKS_BETWEEN_EPOCHS; + ( + unix_ticks / 10_000_000, + (unix_ticks % 10_000_000) as u32 * 100, + ) + } + + /// Returns the timestamp converted into nanoseconds elapsed since Jan 1 + /// 1970. Internally, the time is stored in 100-nanosecond intervals, + /// thus the maximum precision represented is less than the units it is + /// measured in (100 ns vs. 1 ns). The value returned represents the + /// same duration as [`Timestamp::to_unix`]; this provides it in nanosecond + /// units for convenience. + pub const fn to_unix_nanos(&self) -> u64 { + (self.ticks - UUID_TICKS_BETWEEN_EPOCHS) * 100 + } +} + +/// A trait that abstracts over generation of UUID v1 "Clock Sequence" values. +pub trait ClockSequence { + /// Return a 16-bit number that will be used as the "clock sequence" in + /// the UUID. The number must be different if the time has changed since + /// the last time a clock sequence was requested. + fn generate_sequence(&self, seconds: u64, subsec_nanos: u32) -> u16; +} + +impl<'a, T: ClockSequence + ?Sized> ClockSequence for &'a T { + fn generate_sequence(&self, seconds: u64, subsec_nanos: u32) -> u16 { + (**self).generate_sequence(seconds, subsec_nanos) + } +} + +impl Uuid { + /// Create a new UUID (version 1) using a time value + sequence + + /// *NodeId*. + /// + /// When generating [`Timestamp`]s using a [`ClockSequence`], this function + /// is only guaranteed to produce unique values if the following conditions + /// hold: + /// + /// 1. The *NodeId* is unique for this process, + /// 2. The *Context* is shared across all threads which are generating v1 + /// 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 `v1` feature of this crate + /// to be enabled. + /// + /// # Examples + /// + /// A UUID can be created from a unix [`Timestamp`] with a + /// [`ClockSequence`]: + /// + /// ```rust + /// use uuid::v1::{Timestamp, Context}; + /// use uuid::Uuid; + /// + /// let context = Context::new(42); + /// let ts = Timestamp::from_unix(&context, 1497624119, 1234); + /// let uuid = Uuid::new_v1(ts, &[1, 2, 3, 4, 5, 6]).expect("failed to generate UUID"); + /// + /// assert_eq!( + /// uuid.to_hyphenated().to_string(), + /// "f3b4958c-52a1-11e7-802a-010203040506" + /// ); + /// ``` + /// + /// The timestamp can also be created manually as per RFC4122: + /// + /// ``` + /// use uuid::v1::{Timestamp, Context}; + /// use uuid::Uuid; + /// + /// let context = Context::new(42); + /// let ts = Timestamp::from_rfc4122(1497624119, 0); + /// let uuid = Uuid::new_v1(ts, &[1, 2, 3, 4, 5, 6]).expect("failed to generate UUID"); + /// + /// assert_eq!( + /// uuid.to_hyphenated().to_string(), + /// "5943ee37-0000-1000-8000-010203040506" + /// ); + /// ``` + /// + /// [`Timestamp`]: v1/struct.Timestamp.html + /// [`ClockSequence`]: v1/struct.ClockSequence.html + /// [`Context`]: v1/struct.Context.html + pub fn new_v1(ts: Timestamp, node_id: &[u8]) -> Result<Self, crate::Error> { + const NODE_ID_LEN: usize = 6; + + let len = node_id.len(); + if len != NODE_ID_LEN { + Err(crate::builder::Error::new(NODE_ID_LEN, len))?; + } + + let time_low = (ts.ticks & 0xFFFF_FFFF) as u32; + let time_mid = ((ts.ticks >> 32) & 0xFFFF) as u16; + let time_high_and_version = + (((ts.ticks >> 48) & 0x0FFF) as u16) | (1 << 12); + + let mut d4 = [0; 8]; + + { + d4[0] = (((ts.counter & 0x3F00) >> 8) as u8) | 0x80; + d4[1] = (ts.counter & 0xFF) as u8; + } + + d4[2..].copy_from_slice(node_id); + + Uuid::from_fields(time_low, time_mid, time_high_and_version, &d4) + } + + /// Returns an optional [`Timestamp`] storing the timestamp and + /// counter portion parsed from a V1 UUID. + /// + /// Returns `None` if the supplied UUID is not V1. + /// + /// The V1 timestamp format defined in RFC4122 specifies a 60-bit + /// integer representing the number of 100-nanosecond intervals + /// since 00:00:00.00, 15 Oct 1582. + /// + /// [`Timestamp`] offers several options for converting the raw RFC4122 + /// value into more commonly-used formats, such as a unix timestamp. + /// + /// [`Timestamp`]: v1/struct.Timestamp.html + pub fn to_timestamp(&self) -> Option<Timestamp> { + if self + .get_version() + .map(|v| v != Version::Mac) + .unwrap_or(true) + { + return None; + } + + let ticks: u64 = u64::from(self.as_bytes()[6] & 0x0F) << 56 + | u64::from(self.as_bytes()[7]) << 48 + | u64::from(self.as_bytes()[4]) << 40 + | u64::from(self.as_bytes()[5]) << 32 + | u64::from(self.as_bytes()[0]) << 24 + | u64::from(self.as_bytes()[1]) << 16 + | u64::from(self.as_bytes()[2]) << 8 + | u64::from(self.as_bytes()[3]); + + let counter: u16 = u16::from(self.as_bytes()[8] & 0x3F) << 8 + | u16::from(self.as_bytes()[9]); + + Some(Timestamp::from_rfc4122(ticks, counter)) + } +} + +impl Context { + /// Creates a thread-safe, internally mutable context to help ensure + /// uniqueness. + /// + /// This is a context which can be shared across threads. It maintains an + /// internal counter that is incremented at every request, the value ends + /// up in the clock_seq portion of the UUID (the fourth group). This + /// will improve the probability that the UUID is unique across the + /// process. + pub const fn new(count: u16) -> Self { + Self { + count: atomic::AtomicUsize::new(count as usize), + } + } +} + +impl ClockSequence for Context { + fn generate_sequence(&self, _: u64, _: u32) -> u16 { + (self.count.fetch_add(1, atomic::Ordering::SeqCst) & 0xffff) as u16 + } +} + +#[cfg(test)] +mod tests { + use super::*; + + use crate::std::string::ToString; + + #[test] + fn test_new_v1() { + 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, + ) + .unwrap(); + + assert_eq!(uuid.get_version(), Some(Version::Mac)); + assert_eq!(uuid.get_variant(), Some(Variant::RFC4122)); + assert_eq!( + uuid.to_hyphenated().to_string(), + "20616934-4ba2-11e7-8000-010203040506" + ); + + let ts = uuid.to_timestamp().unwrap().to_rfc4122(); + + assert_eq!(ts.0 - 0x01B2_1DD2_1381_4000, 14_968_545_358_129_460); + assert_eq!(ts.1, 0); + }; + + { + let uuid2 = Uuid::new_v1( + Timestamp::from_unix(&context, time, time_fraction), + &node, + ) + .unwrap(); + + assert_eq!( + uuid2.to_hyphenated().to_string(), + "20616934-4ba2-11e7-8001-010203040506" + ); + assert_eq!(uuid2.to_timestamp().unwrap().to_rfc4122().1, 1) + }; + } +} diff --git a/third_party/rust/uuid/src/v3.rs b/third_party/rust/uuid/src/v3.rs new file mode 100644 index 0000000000..c598239e76 --- /dev/null +++ b/third_party/rust/uuid/src/v3.rs @@ -0,0 +1,146 @@ +use crate::prelude::*; +use md5; + +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. + /// + /// [`NAMESPACE_DNS`]: ns/const.NAMESPACE_DNS.html + /// [`NAMESPACE_OID`]: ns/const.NAMESPACE_OID.html + /// [`NAMESPACE_URL`]: ns/const.NAMESPACE_URL.html + /// [`NAMESPACE_X500`]: ns/const.NAMESPACE_X500.html + pub fn new_v3(namespace: &Uuid, name: &[u8]) -> Uuid { + let mut context = md5::Context::new(); + + context.consume(namespace.as_bytes()); + context.consume(name); + + let computed = context.compute(); + let bytes = computed.into(); + + let mut builder = crate::builder::Builder::from_bytes(bytes); + + builder + .set_variant(Variant::RFC4122) + .set_version(Version::Md5); + + builder.build() + } +} + +#[cfg(test)] +mod tests { + use super::*; + + use crate::std::string::ToString; + + 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] + fn test_new() { + for &(ref ns, ref name, _) in FIXTURE { + let uuid = Uuid::new_v3(*ns, name.as_bytes()); + assert_eq!(uuid.get_version().unwrap(), Version::Md5); + assert_eq!(uuid.get_variant().unwrap(), Variant::RFC4122); + } + } + + #[test] + fn test_to_hyphenated_string() { + for &(ref ns, ref name, ref expected) in FIXTURE { + let uuid = Uuid::new_v3(*ns, name.as_bytes()); + assert_eq!(uuid.to_hyphenated().to_string(), *expected); + } + } +} diff --git a/third_party/rust/uuid/src/v4.rs b/third_party/rust/uuid/src/v4.rs new file mode 100644 index 0000000000..fe1af0f633 --- /dev/null +++ b/third_party/rust/uuid/src/v4.rs @@ -0,0 +1,59 @@ +use crate::prelude::*; +use rand; + +impl Uuid { + /// Creates a random UUID. + /// + /// This uses the [`rand`] crate's default task RNG as the source of random + /// numbers. If you'd like to use a custom generator, don't use this + /// method: use the `rand::Rand trait`'s `rand()` method instead. + /// + /// Note that usage of this method requires the `v4` feature of this crate + /// to be enabled. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use uuid::Uuid; + /// + /// let uuid = Uuid::new_v4(); + /// ``` + /// + /// [`rand`]: https://crates.io/crates/rand + pub fn new_v4() -> Self { + use rand::RngCore; + + let mut rng = rand::thread_rng(); + let mut bytes = [0; 16]; + + rng.fill_bytes(&mut bytes); + + Builder::from_bytes(bytes) + .set_variant(Variant::RFC4122) + .set_version(Version::Random) + .build() + } +} + +#[cfg(test)] +mod tests { + use crate::prelude::*; + + #[test] + fn test_new() { + let uuid = Uuid::new_v4(); + + assert_eq!(uuid.get_version(), Some(Version::Random)); + assert_eq!(uuid.get_variant(), Some(Variant::RFC4122)); + } + + #[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) + } +} diff --git a/third_party/rust/uuid/src/v5.rs b/third_party/rust/uuid/src/v5.rs new file mode 100644 index 0000000000..b71d6d433e --- /dev/null +++ b/third_party/rust/uuid/src/v5.rs @@ -0,0 +1,158 @@ +use crate::prelude::*; +use sha1; + +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. + /// + /// [`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 { + let mut hash = sha1::Sha1::new(); + + hash.update(namespace.as_bytes()); + hash.update(name); + + let buffer = hash.digest().bytes(); + + let mut bytes = crate::Bytes::default(); + bytes.copy_from_slice(&buffer[..16]); + + let mut builder = crate::builder::Builder::from_bytes(bytes); + builder + .set_variant(Variant::RFC4122) + .set_version(Version::Sha1); + + builder.build() + } +} + +#[cfg(test)] +mod tests { + use super::*; + + use crate::std::string::ToString; + + 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] + 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] + fn test_hyphenated() { + for &(ref ns, ref name, ref expected) in FIXTURE { + let uuid = Uuid::new_v5(*ns, name.as_bytes()); + + assert_eq!(uuid.to_hyphenated().to_string(), *expected) + } + } + + #[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_variant(), Some(Variant::RFC4122)); + assert_eq!(uuid.get_version(), Some(Version::Sha1)); + assert_eq!(Ok(uuid), u.parse()); + } + } +} diff --git a/third_party/rust/uuid/src/winapi_support.rs b/third_party/rust/uuid/src/winapi_support.rs new file mode 100644 index 0000000000..e11ccde6e0 --- /dev/null +++ b/third_party/rust/uuid/src/winapi_support.rs @@ -0,0 +1,79 @@ +use crate::prelude::*; +use winapi::shared::guiddef; + +#[cfg(feature = "guid")] +impl Uuid { + /// Attempts to create a [`Uuid`] from a little endian winapi `GUID` + /// + /// [`Uuid`]: ../struct.Uuid.html + pub fn from_guid(guid: guiddef::GUID) -> Result<Uuid, crate::Error> { + Uuid::from_fields_le( + guid.Data1 as u32, + guid.Data2 as u16, + guid.Data3 as u16, + &(guid.Data4 as [u8; 8]), + ) + } + + /// Converts a [`Uuid`] into a little endian winapi `GUID` + /// + /// [`Uuid`]: ../struct.Uuid.html + pub fn to_guid(&self) -> guiddef::GUID { + let (data1, data2, data3, data4) = self.to_fields_le(); + + guiddef::GUID { + Data1: data1, + Data2: data2, + Data3: data3, + Data4: *data4, + } + } +} + +#[cfg(feature = "guid")] +#[cfg(test)] +mod tests { + use super::*; + + use crate::std::string::ToString; + use winapi::shared::guiddef; + + #[test] + fn test_from_guid() { + let guid = guiddef::GUID { + Data1: 0x4a35229d, + Data2: 0x5527, + Data3: 0x4f30, + Data4: [0x86, 0x47, 0x9d, 0xc5, 0x4e, 0x1e, 0xe1, 0xe8], + }; + + let uuid = Uuid::from_guid(guid).unwrap(); + assert_eq!( + "9d22354a-2755-304f-8647-9dc54e1ee1e8", + uuid.to_hyphenated().to_string() + ); + } + + #[test] + fn test_guid_roundtrip() { + let guid_in = guiddef::GUID { + Data1: 0x4a35229d, + Data2: 0x5527, + Data3: 0x4f30, + Data4: [0x86, 0x47, 0x9d, 0xc5, 0x4e, 0x1e, 0xe1, 0xe8], + }; + + let uuid = Uuid::from_guid(guid_in).unwrap(); + let guid_out = uuid.to_guid(); + + assert_eq!( + (guid_in.Data1, guid_in.Data2, guid_in.Data3, guid_in.Data4), + ( + guid_out.Data1, + guid_out.Data2, + guid_out.Data3, + guid_out.Data4 + ) + ); + } +} |