rust_motion_animation/
random.rs1use std::fmt;
7
8#[derive(Clone, Debug, PartialEq)]
12pub enum RandomSeed {
13 Str(String),
15 Num(f64),
17}
18
19impl fmt::Display for RandomSeed {
20 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
21 match self {
22 RandomSeed::Str(s) => write!(f, "{}", s),
23 RandomSeed::Num(n) => write!(f, "{}", n),
24 }
25 }
26}
27
28impl From<&str> for RandomSeed {
29 fn from(s: &str) -> Self {
30 RandomSeed::Str(s.to_string())
31 }
32}
33
34impl From<String> for RandomSeed {
35 fn from(s: String) -> Self {
36 RandomSeed::Str(s)
37 }
38}
39
40impl From<&String> for RandomSeed {
41 fn from(s: &String) -> Self {
42 RandomSeed::Str(s.clone())
43 }
44}
45
46impl From<f64> for RandomSeed {
47 fn from(n: f64) -> Self {
48 RandomSeed::Num(n)
49 }
50}
51
52impl From<f32> for RandomSeed {
53 fn from(n: f32) -> Self {
54 RandomSeed::Num(n as f64)
55 }
56}
57
58impl From<i32> for RandomSeed {
59 fn from(n: i32) -> Self {
60 RandomSeed::Num(n as f64)
61 }
62}
63
64impl From<i64> for RandomSeed {
65 fn from(n: i64) -> Self {
66 RandomSeed::Num(n as f64)
67 }
68}
69
70impl From<u32> for RandomSeed {
71 fn from(n: u32) -> Self {
72 RandomSeed::Num(n as f64)
73 }
74}
75
76impl From<u64> for RandomSeed {
77 fn from(n: u64) -> Self {
78 RandomSeed::Num(n as f64)
79 }
80}
81
82impl From<usize> for RandomSeed {
83 fn from(n: usize) -> Self {
84 RandomSeed::Num(n as f64)
85 }
86}
87
88pub fn hash_code(s: &str) -> i32 {
93 let mut hash: i32 = 0;
94 for code_unit in s.encode_utf16() {
95 hash = hash.wrapping_mul(31).wrapping_add(code_unit as i32);
96 }
97 hash
98}
99
100#[inline]
104pub fn mulberry32(a: i64) -> f64 {
105 let a_u32 = a as u32;
106 let t0 = a_u32.wrapping_add(0x6D2B79F5);
107 let t1 = (t0 ^ (t0 >> 15)).wrapping_mul(t0 | 1);
108 let t2 = t1 ^ t1.wrapping_add((t1 ^ (t1 >> 7)).wrapping_mul(t1 | 61));
109 let result = t2 ^ (t2 >> 14);
110 (result as f64) / 4294967296.0
111}
112
113#[inline]
128pub fn random(seed: impl Into<RandomSeed>) -> f64 {
129 match seed.into() {
130 RandomSeed::Str(s) => mulberry32(hash_code(&s) as i64),
131 RandomSeed::Num(n) => mulberry32((n * 10_000_000_000.0) as i64),
132 }
133}
134
135#[cfg(test)]
136mod tests {
137 use super::*;
138
139 #[test]
140 fn test_random_deterministic() {
141 let r1 = random("remotion-seed");
142 let r2 = random("remotion-seed");
143 assert_eq!(r1, r2);
144 assert!((0.0..1.0).contains(&r1));
145
146 let n1 = random(42);
147 let n2 = random(42);
148 assert_eq!(n1, n2);
149 assert!((0.0..1.0).contains(&n1));
150 assert_ne!(r1, n1);
151 }
152
153 #[test]
154 fn test_hash_code_known_values() {
155 assert_eq!(hash_code(""), 0);
156 assert_eq!(hash_code("a"), 97);
157 assert_eq!(hash_code("hello"), 99162322);
158 }
159}