noise/
permutationtable.rs1use core::fmt;
2use rand::{
3 distributions::{Distribution, Standard},
4 seq::SliceRandom,
5 Rng, SeedableRng,
6};
7use rand_xorshift::XorShiftRng;
8
9const TABLE_SIZE: usize = 256;
10
11pub trait NoiseHasher: Send + Sync {
12 fn hash(&self, to_hash: &[isize]) -> usize;
13}
14
15#[derive(Copy, Clone)]
20pub struct PermutationTable {
21 values: [u8; TABLE_SIZE],
22}
23
24impl Distribution<PermutationTable> for Standard {
25 fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> PermutationTable {
27 let mut perm_table = PermutationTable {
28 values: [0; TABLE_SIZE],
29 };
30
31 perm_table
32 .values
33 .iter_mut()
34 .enumerate()
35 .for_each(|(i, b)| *b = i as u8);
36 perm_table.values.shuffle(rng);
37
38 perm_table
39 }
40}
41
42impl PermutationTable {
43 pub fn new(seed: u32) -> Self {
48 let mut real = [0; 16];
49 real[0] = 1;
50 for i in 1..4 {
51 real[i * 4] = seed as u8;
52 real[(i * 4) + 1] = (seed >> 8) as u8;
53 real[(i * 4) + 2] = (seed >> 16) as u8;
54 real[(i * 4) + 3] = (seed >> 24) as u8;
55 }
56 let mut rng: XorShiftRng = SeedableRng::from_seed(real);
57 rng.gen()
58 }
59}
60
61impl NoiseHasher for PermutationTable {
62 fn hash(&self, to_hash: &[isize]) -> usize {
63 let index = to_hash
64 .iter()
65 .map(|&a| (a & 0xff) as usize)
66 .reduce(|a, b| self.values[a] as usize ^ b)
67 .unwrap();
68 self.values[index] as usize
69 }
70}
71
72impl fmt::Debug for PermutationTable {
73 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
74 write!(f, "PermutationTable {{ .. }}")
75 }
76}
77
78#[cfg(test)]
79mod tests {
80 use crate::{NoiseFn, Perlin, Seedable};
81 use rand::random;
82
83 #[test]
84 fn test_random_seed() {
85 let perlin = Perlin::default().set_seed(random());
86 let _ = perlin.get([1.0, 2.0, 3.0]);
87 }
88
89 #[test]
90 fn test_negative_params() {
91 let perlin = Perlin::default();
92 let _ = perlin.get([-1.0, 2.0, 3.0]);
93 }
94}