bevy_utils: Export generate_composite_uuid utility function (#10496)

# Objective

The `generate_composite_uuid` utility function hidden in
`bevy_reflect::__macro_exports` could be generally useful to users.

For example, I previously relied on `Hash` to generate a `u64` to create
a deterministic `HandleId`. In v0.12, `HandleId` has been replaced by
`AssetId` which now requires a `Uuid`, which I could generate with this
function.

## Solution

Relocate `generate_composite_uuid` from `bevy_reflect::__macro_exports`
to `bevy_utils::uuid`.

It is still re-exported under `bevy_reflect::__macro_exports` so there
should not be any breaking changes (although, users should generally not
rely on pseudo-private/hidden modules like `__macro_exports`).

I chose to keep it in `bevy_reflect::__macro_exports` so as to not
clutter up our public API and to reduce the number of changes in this
PR. We could have also marked the export as `#[doc(hidden)]`, but
personally I like that we have a dedicated module for this (makes it
clear what is public and what isn't when just looking at the macro
code).

---

## Changelog

- Moved `generate_composite_uuid` to `bevy_utils::uuid` and made it
public
  - Note: it was technically already public, just hidden
This commit is contained in:
Gino Valente 2023-11-25 16:21:35 -07:00 committed by GitHub
parent 91b64df96b
commit 13f2749021
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 40 additions and 28 deletions

View file

@ -542,32 +542,7 @@ extern crate alloc;
#[doc(hidden)]
pub mod __macro_exports {
use crate::Uuid;
/// Generates a new UUID from the given UUIDs `a` and `b`,
/// where the bytes are generated by a bitwise `a ^ b.rotate_right(1)`.
/// The generated UUID will be a `UUIDv4` (meaning that the bytes should be random, not e.g. derived from the system time).
#[allow(clippy::unusual_byte_groupings)] // unusual byte grouping is meant to signal the relevant bits
pub const fn generate_composite_uuid(a: Uuid, b: Uuid) -> Uuid {
let mut new = [0; 16];
let mut i = 0;
while i < new.len() {
// rotating ensures different uuids for A<B<C>> and B<A<C>> because: A ^ (B ^ C) = B ^ (A ^ C)
// notice that you have to rotate the second parameter: A.rr ^ (B.rr ^ C) = B.rr ^ (A.rr ^ C)
// Solution: A ^ (B ^ C.rr).rr != B ^ (A ^ C.rr).rr
new[i] = a.as_bytes()[i] ^ b.as_bytes()[i].rotate_right(1);
i += 1;
}
// Version: the most significant 4 bits in the 6th byte: 11110000
new[6] = new[6] & 0b0000_1111 | 0b0100_0000; // set version to v4
// Variant: the most significant 3 bits in the 8th byte: 11100000
new[8] = new[8] & 0b000_11111 | 0b100_00000; // set variant to rfc4122
Uuid::from_bytes(new)
}
pub use bevy_utils::uuid::generate_composite_uuid;
}
#[cfg(test)]

View file

@ -1,5 +1,5 @@
pub use bevy_reflect_derive::TypeUuid;
pub use bevy_utils::Uuid;
pub use bevy_utils::uuid::Uuid;
/// A trait for types with a statically associated UUID.
pub trait TypeUuid {

View file

@ -17,11 +17,14 @@ pub use short_names::get_short_name;
pub mod synccell;
pub mod syncunsafecell;
pub mod uuid;
mod cow_arc;
mod default;
mod float_ord;
pub mod intern;
pub use crate::uuid::Uuid;
pub use ahash::{AHasher, RandomState};
pub use bevy_utils_proc_macros::*;
pub use cow_arc::*;
@ -32,7 +35,6 @@ pub use instant::{Duration, Instant};
pub use petgraph;
pub use thiserror;
pub use tracing;
pub use uuid::Uuid;
#[allow(missing_docs)]
pub mod nonmax {

View file

@ -0,0 +1,35 @@
//! UUID utilities.
//!
//! This module re-exports the [`Uuid`] type from the [`uuid`] crate,
//! and provides additional utility functions.
//!
//! [`uuid`]: ::uuid
pub use ::uuid::Uuid;
/// Generates a new UUID from the given UUIDs `a` and `b`,
/// where the bytes are generated by a bitwise `a ^ b.rotate_right(1)`.
///
/// The generated UUID will be a `UUIDv4`
/// (meaning that the bytes should be random, not e.g. derived from the system time).
#[allow(clippy::unusual_byte_groupings)] // unusual byte grouping is meant to signal the relevant bits
pub const fn generate_composite_uuid(a: Uuid, b: Uuid) -> Uuid {
let mut new = [0; 16];
let mut i = 0;
while i < new.len() {
// rotating ensures different uuids for A<B<C>> and B<A<C>> because: A ^ (B ^ C) = B ^ (A ^ C)
// notice that you have to rotate the second parameter: A.rr ^ (B.rr ^ C) = B.rr ^ (A.rr ^ C)
// Solution: A ^ (B ^ C.rr).rr != B ^ (A ^ C.rr).rr
new[i] = a.as_bytes()[i] ^ b.as_bytes()[i].rotate_right(1);
i += 1;
}
// Version: the most significant 4 bits in the 6th byte: 11110000
new[6] = new[6] & 0b0000_1111 | 0b0100_0000; // set version to v4
// Variant: the most significant 3 bits in the 8th byte: 11100000
new[8] = new[8] & 0b000_11111 | 0b100_00000; // set variant to rfc4122
Uuid::from_bytes(new)
}