steel_core/chunk/light/
data_layer.rs1use super::{DATA_LAYER_EDGE, DATA_LAYER_SIZE, MAX_LIGHT_LEVEL};
2
3#[derive(Debug, Clone, Copy, PartialEq, Eq)]
5pub struct DataLayerLengthError {
6 pub actual: usize,
8}
9
10#[derive(Debug, Clone, PartialEq, Eq)]
16pub struct DataLayer {
17 data: Option<Box<[u8; DATA_LAYER_SIZE]>>,
18 default_value: u8,
19}
20
21impl DataLayer {
22 #[must_use]
24 pub const fn new() -> Self {
25 Self {
26 data: None,
27 default_value: 0,
28 }
29 }
30
31 #[must_use]
33 pub const fn filled(value: u8) -> Self {
34 Self {
35 data: None,
36 default_value: value & MAX_LIGHT_LEVEL,
37 }
38 }
39
40 pub fn from_bytes(bytes: Box<[u8]>) -> Result<Self, DataLayerLengthError> {
42 let actual = bytes.len();
43 let Ok(data) = bytes.try_into() else {
44 return Err(DataLayerLengthError { actual });
45 };
46
47 Ok(Self::from_packed_data(data))
48 }
49
50 #[must_use]
52 pub(crate) const fn from_packed_data(data: Box<[u8; DATA_LAYER_SIZE]>) -> Self {
53 Self {
54 data: Some(data),
55 default_value: 0,
56 }
57 }
58
59 #[must_use]
61 pub fn get(&self, x: usize, y: usize, z: usize) -> u8 {
62 debug_assert!(x < DATA_LAYER_EDGE);
63 debug_assert!(y < DATA_LAYER_EDGE);
64 debug_assert!(z < DATA_LAYER_EDGE);
65
66 self.get_at_index(Self::index(x, y, z))
67 }
68
69 pub fn set(&mut self, x: usize, y: usize, z: usize, value: u8) {
71 debug_assert!(x < DATA_LAYER_EDGE);
72 debug_assert!(y < DATA_LAYER_EDGE);
73 debug_assert!(z < DATA_LAYER_EDGE);
74
75 self.set_at_index(Self::index(x, y, z), value);
76 }
77
78 pub fn fill(&mut self, value: u8) {
80 self.default_value = value & MAX_LIGHT_LEVEL;
81 self.data = None;
82 }
83
84 #[must_use]
86 pub const fn is_homogeneous(&self) -> bool {
87 self.data.is_none()
88 }
89
90 #[must_use]
92 pub const fn homogeneous_value(&self) -> Option<u8> {
93 if self.data.is_none() {
94 Some(self.default_value)
95 } else {
96 None
97 }
98 }
99
100 #[must_use]
102 pub const fn is_filled_with(&self, value: u8) -> bool {
103 self.data.is_none() && self.default_value == (value & MAX_LIGHT_LEVEL)
104 }
105
106 #[must_use]
108 pub const fn is_empty(&self) -> bool {
109 self.data.is_none() && self.default_value == 0
110 }
111
112 #[must_use]
114 pub fn is_all_zero(&self) -> bool {
115 match &self.data {
116 Some(data) => data.iter().all(|value| *value == 0),
117 None => self.default_value == 0,
118 }
119 }
120
121 #[must_use]
123 pub fn copy(&self) -> Self {
124 self.clone()
125 }
126
127 #[must_use]
129 pub fn to_bytes(&self) -> Box<[u8; DATA_LAYER_SIZE]> {
130 if let Some(data) = &self.data {
131 Box::new(**data)
132 } else {
133 Box::new([Self::pack_filled(self.default_value); DATA_LAYER_SIZE])
134 }
135 }
136
137 fn get_at_index(&self, index: usize) -> u8 {
138 if let Some(data) = &self.data {
139 let packed = data[Self::byte_index(index)];
140 packed >> (4 * Self::nibble_index(index)) & MAX_LIGHT_LEVEL
141 } else {
142 self.default_value
143 }
144 }
145
146 fn set_at_index(&mut self, index: usize, value: u8) {
147 let data = self.data.get_or_insert_with(|| {
148 Box::new([Self::pack_filled(self.default_value); DATA_LAYER_SIZE])
149 });
150 let byte_index = Self::byte_index(index);
151 let shift = 4 * Self::nibble_index(index);
152 let mask = !(MAX_LIGHT_LEVEL << shift);
153 let value_to_set = (value & MAX_LIGHT_LEVEL) << shift;
154 data[byte_index] = data[byte_index] & mask | value_to_set;
155 }
156
157 const fn index(x: usize, y: usize, z: usize) -> usize {
158 y << 8 | z << 4 | x
159 }
160
161 const fn byte_index(index: usize) -> usize {
162 index >> 1
163 }
164
165 const fn nibble_index(index: usize) -> usize {
166 index & 1
167 }
168
169 const fn pack_filled(value: u8) -> u8 {
170 let value = value & MAX_LIGHT_LEVEL;
171 value | value << 4
172 }
173}
174
175impl Default for DataLayer {
176 fn default() -> Self {
177 Self::new()
178 }
179}