valence_server/layer/chunk/
paletted_container.rs
1use std::array;
2use std::io::Write;
3
4use arrayvec::ArrayVec;
5use valence_protocol::{Encode, VarInt};
6
7use super::chunk::bit_width;
8
9#[derive(Clone, Debug)]
11pub(super) enum PalettedContainer<T, const LEN: usize, const HALF_LEN: usize> {
12 Single(T),
13 Indirect(Box<Indirect<T, LEN, HALF_LEN>>),
14 Direct(Box<[T; LEN]>),
15}
16
17#[derive(Clone, Debug)]
18pub(super) struct Indirect<T, const LEN: usize, const HALF_LEN: usize> {
19 palette: ArrayVec<T, 16>,
22 indices: [u8; HALF_LEN],
24}
25
26impl<T: Copy + Eq + Default, const LEN: usize, const HALF_LEN: usize>
27 PalettedContainer<T, LEN, HALF_LEN>
28{
29 pub(super) fn new() -> Self {
30 assert_eq!(LEN.div_ceil(2), HALF_LEN);
31 assert_ne!(LEN, 0);
32
33 Self::Single(T::default())
34 }
35
36 pub(super) fn fill(&mut self, val: T) {
37 *self = Self::Single(val)
38 }
39
40 #[track_caller]
41 pub(super) fn get(&self, idx: usize) -> T {
42 debug_assert!(idx < LEN);
43
44 match self {
45 Self::Single(elem) => *elem,
46 Self::Indirect(ind) => ind.get(idx),
47 Self::Direct(elems) => elems[idx],
48 }
49 }
50
51 #[track_caller]
52 pub(super) fn set(&mut self, idx: usize, val: T) -> T {
53 debug_assert!(idx < LEN);
54
55 match self {
56 Self::Single(old_val) => {
57 if *old_val == val {
58 *old_val
59 } else {
60 let old = *old_val;
62 let mut ind = Box::new(Indirect {
63 palette: ArrayVec::from_iter([old, val]),
64 indices: [0; HALF_LEN],
66 });
67
68 ind.indices[idx / 2] = 1 << (idx % 2 * 4);
69 *self = Self::Indirect(ind);
70 old
71 }
72 }
73 Self::Indirect(ind) => {
74 if let Some(old) = ind.set(idx, val) {
75 old
76 } else {
77 *self = Self::Direct(Box::new(array::from_fn(|i| ind.get(i))));
79 self.set(idx, val)
80 }
81 }
82 Self::Direct(vals) => {
83 let old = vals[idx];
84 vals[idx] = val;
85 old
86 }
87 }
88 }
89
90 pub(super) fn shrink_to_fit(&mut self) {
91 match self {
92 Self::Single(_) => {}
93 Self::Indirect(ind) => {
94 let mut new_ind = Indirect {
95 palette: ArrayVec::new(),
96 indices: [0; HALF_LEN],
97 };
98
99 for i in 0..LEN {
100 new_ind.set(i, ind.get(i));
101 }
102
103 if new_ind.palette.len() == 1 {
104 *self = Self::Single(new_ind.palette[0]);
105 } else {
106 **ind = new_ind;
107 }
108 }
109 Self::Direct(dir) => {
110 let mut ind = Indirect {
111 palette: ArrayVec::new(),
112 indices: [0; HALF_LEN],
113 };
114
115 for (i, val) in dir.iter().copied().enumerate() {
116 if ind.set(i, val).is_none() {
117 return;
118 }
119 }
120
121 *self = if ind.palette.len() == 1 {
122 Self::Single(ind.palette[0])
123 } else {
124 Self::Indirect(Box::new(ind))
125 };
126 }
127 }
128 }
129
130 pub(super) fn encode_mc_format<W, F>(
146 &self,
147 mut writer: W,
148 mut to_bits: F,
149 min_indirect_bits: usize,
150 max_indirect_bits: usize,
151 direct_bits: usize,
152 ) -> anyhow::Result<()>
153 where
154 W: Write,
155 F: FnMut(T) -> u64,
156 {
157 debug_assert!(min_indirect_bits <= 4);
158 debug_assert!(min_indirect_bits <= max_indirect_bits);
159 debug_assert!(max_indirect_bits <= 64);
160 debug_assert!(direct_bits <= 64);
161
162 match self {
163 Self::Single(val) => {
164 0_u8.encode(&mut writer)?;
166
167 VarInt(to_bits(*val) as i32).encode(&mut writer)?;
169
170 VarInt(0).encode(writer)?;
172 }
173 Self::Indirect(ind) => {
174 let bits_per_entry = min_indirect_bits.max(bit_width(ind.palette.len() - 1));
175
176 if bits_per_entry > max_indirect_bits {
178 (direct_bits as u8).encode(&mut writer)?;
180
181 VarInt(compact_u64s_len(LEN, direct_bits) as i32).encode(&mut writer)?;
183 encode_compact_u64s(
185 writer,
186 (0..LEN).map(|i| to_bits(ind.get(i))),
187 direct_bits,
188 )?;
189 } else {
190 (bits_per_entry as u8).encode(&mut writer)?;
192
193 VarInt(ind.palette.len() as i32).encode(&mut writer)?;
195 for val in &ind.palette {
197 VarInt(to_bits(*val) as i32).encode(&mut writer)?;
198 }
199
200 VarInt(compact_u64s_len(LEN, bits_per_entry) as i32).encode(&mut writer)?;
202 encode_compact_u64s(
204 writer,
205 ind.indices
206 .iter()
207 .copied()
208 .flat_map(|byte| [byte & 0b1111, byte >> 4])
209 .map(u64::from)
210 .take(LEN),
211 bits_per_entry,
212 )?;
213 }
214 }
215 Self::Direct(dir) => {
216 (direct_bits as u8).encode(&mut writer)?;
218
219 VarInt(compact_u64s_len(LEN, direct_bits) as i32).encode(&mut writer)?;
221 encode_compact_u64s(writer, dir.iter().copied().map(to_bits), direct_bits)?;
223 }
224 }
225
226 Ok(())
227 }
228}
229
230impl<T: Copy + Eq + Default, const LEN: usize, const HALF_LEN: usize> Default
231 for PalettedContainer<T, LEN, HALF_LEN>
232{
233 fn default() -> Self {
234 Self::new()
235 }
236}
237
238impl<T: Copy + Eq + Default, const LEN: usize, const HALF_LEN: usize> Indirect<T, LEN, HALF_LEN> {
239 pub(super) fn get(&self, idx: usize) -> T {
240 let palette_idx = (self.indices[idx / 2] >> (idx % 2 * 4)) & 0b1111;
241 self.palette[palette_idx as usize]
242 }
243
244 pub(super) fn set(&mut self, idx: usize, val: T) -> Option<T> {
245 let palette_idx = if let Some(i) = self.palette.iter().position(|v| *v == val) {
246 i
247 } else {
248 self.palette.try_push(val).ok()?;
249 self.palette.len() - 1
250 };
251
252 let old_val = self.get(idx);
253 let u8 = &mut self.indices[idx / 2];
254 let shift = idx % 2 * 4;
255 *u8 = (*u8 & !(0b1111 << shift)) | ((palette_idx as u8) << shift);
256 Some(old_val)
257 }
258}
259
260#[inline]
261fn compact_u64s_len(vals_count: usize, bits_per_val: usize) -> usize {
262 let vals_per_u64 = 64 / bits_per_val;
263 vals_count.div_ceil(vals_per_u64)
264}
265
266#[inline]
267fn encode_compact_u64s(
268 mut w: impl Write,
269 mut vals: impl Iterator<Item = u64>,
270 bits_per_val: usize,
271) -> anyhow::Result<()> {
272 debug_assert!(bits_per_val <= 64);
273
274 let vals_per_u64 = 64 / bits_per_val;
275
276 loop {
277 let mut n = 0;
278 for i in 0..vals_per_u64 {
279 match vals.next() {
280 Some(val) => {
281 debug_assert!(val < 2_u128.pow(bits_per_val as u32) as u64);
282 n |= val << (i * bits_per_val);
283 }
284 None if i > 0 => return n.encode(&mut w),
285 None => return Ok(()),
286 }
287 }
288 n.encode(&mut w)?;
289 }
290}
291
292#[cfg(test)]
293mod tests {
294 use rand::Rng;
295
296 use super::*;
297
298 fn check<T: Copy + Eq + Default, const LEN: usize, const HALF_LEN: usize>(
299 p: &PalettedContainer<T, LEN, HALF_LEN>,
300 s: &[T],
301 ) -> bool {
302 assert_eq!(s.len(), LEN);
303 (0..LEN).all(|i| p.get(i) == s[i])
304 }
305
306 #[test]
307 fn random_assignments() {
308 const LEN: usize = 100;
309 let range = 0..64;
310
311 let mut rng = rand::thread_rng();
312
313 for _ in 0..20 {
314 let mut p = PalettedContainer::<u32, LEN, { LEN / 2 }>::new();
315
316 let init = rng.gen_range(range.clone());
317
318 p.fill(init);
319 let mut a = [init; LEN];
320
321 assert!(check(&p, &a));
322
323 let mut rng = rand::thread_rng();
324
325 for _ in 0..LEN * 10 {
326 let idx = rng.gen_range(0..LEN);
327 let val = rng.gen_range(range.clone());
328
329 assert_eq!(p.get(idx), p.set(idx, val));
330 assert_eq!(val, p.get(idx));
331 a[idx] = val;
332
333 p.shrink_to_fit();
334
335 assert!(check(&p, &a));
336 }
337 }
338 }
339}