summaryrefslogtreecommitdiff
path: root/rust/crates/animation/src/id.rs
diff options
context:
space:
mode:
authorcashmere <cashmere@autistici.org>2026-07-28 19:41:16 +0200
committercashmere <cashmere@autistici.org>2026-07-28 19:41:16 +0200
commitf5a82152394fde4d8f740f664ab7737b82861618 (patch)
tree5a51b181abead1ce03d2dbfc12b77918d3be0e1b /rust/crates/animation/src/id.rs
parente837e7504379e100ff3b56282577ec67bb88bec9 (diff)
downloadopencut-f5a82152394fde4d8f740f664ab7737b82861618.tar.gz
feat: GPUI desktop port foundation
- scene crate: full project/scene/element model, serde round-trip proven against the web SerializedProject shape - transfer crate: .ocp zip container, cross-compat with web fflate archives proven in both directions - storage crate: filesystem project store replacing IndexedDB, .ocp import/export - media crate: ffmpeg-next 8 decoder (frames, audio, thumbnails, waveform summaries) - playback crate: wall-clock anchored, frame-rounded playback clock - gpu crate: native texture readback; compositor renders headless offscreen on Vulkan (spike test) - flake devshell: rust toolchain, GPUI native deps, ffmpeg dev, bindgen clang args; GPUI hello-world builds - port plan in notes/gpui-port.md
Diffstat (limited to 'rust/crates/animation/src/id.rs')
-rw-r--r--rust/crates/animation/src/id.rs61
1 files changed, 61 insertions, 0 deletions
diff --git a/rust/crates/animation/src/id.rs b/rust/crates/animation/src/id.rs
new file mode 100644
index 00000000..95288660
--- /dev/null
+++ b/rust/crates/animation/src/id.rs
@@ -0,0 +1,61 @@
+use std::cell::Cell;
+use std::time::{SystemTime, UNIX_EPOCH};
+
+thread_local! {
+ static RNG_STATE: Cell<u64> = const { Cell::new(0) };
+}
+
+fn next_u64() -> u64 {
+ RNG_STATE.with(|state| {
+ let mut value = state.get();
+ if value == 0 {
+ let nanos = SystemTime::now()
+ .duration_since(UNIX_EPOCH)
+ .map(|duration| duration.as_nanos() as u64)
+ .unwrap_or(0x9e37_79b9_7f4a_7c15);
+ value = nanos
+ ^ (std::process::id() as u64).rotate_left(32)
+ ^ 0x9e37_79b9_7f4a_7c15;
+ }
+ value ^= value << 13;
+ value ^= value >> 7;
+ value ^= value << 17;
+ state.set(value);
+ value
+ })
+}
+
+pub fn generate_uuid() -> String {
+ let mut bytes = [0u8; 16];
+ for chunk in bytes.chunks_mut(8) {
+ let random = next_u64().to_le_bytes();
+ chunk.copy_from_slice(&random[..chunk.len()]);
+ }
+ bytes[6] = (bytes[6] & 0x0f) | 0x40;
+ bytes[8] = (bytes[8] & 0x3f) | 0x80;
+ let hex: Vec<String> = bytes.iter().map(|byte| format!("{byte:02x}")).collect();
+ format!(
+ "{}-{}-{}-{}-{}",
+ hex[0..4].join(""),
+ hex[4..6].join(""),
+ hex[6..8].join(""),
+ hex[8..10].join(""),
+ hex[10..16].join("")
+ )
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ #[test]
+ fn generates_uuid_shaped_unique_ids() {
+ let id = generate_uuid();
+ let parts: Vec<&str> = id.split('-').collect();
+ assert_eq!(parts.len(), 5);
+ assert_eq!(parts[0].len(), 8);
+ assert_eq!(parts[1].len(), 4);
+ assert_eq!(parts[4].len(), 12);
+ assert_ne!(generate_uuid(), generate_uuid());
+ }
+}