Write voxel bytes for a mesh hash. Best-effort; an `Err` return means the cache wasn't updated but rendering can continue.
(hash: MeshHash, voxel_bytes: &[u8])
| 165 | /// Write voxel bytes for a mesh hash. Best-effort; an `Err` return |
| 166 | /// means the cache wasn't updated but rendering can continue. |
| 167 | pub fn store(hash: MeshHash, voxel_bytes: &[u8]) -> std::io::Result<()> { |
| 168 | if voxel_bytes.len() != VOXEL_BYTES { |
| 169 | return Err(std::io::Error::new( |
| 170 | std::io::ErrorKind::InvalidInput, |
| 171 | "voxel payload size mismatch", |
| 172 | )); |
| 173 | } |
| 174 | let path = cache_path(hash).ok_or_else(|| { |
| 175 | std::io::Error::new(std::io::ErrorKind::Other, "cache directory unavailable") |
| 176 | })?; |
| 177 | |
| 178 | // Write to a temp file and rename so a crash mid-write can never |
| 179 | // leave a partial entry that survives validation. |
| 180 | let tmp = path.with_extension("sdf.tmp"); |
| 181 | { |
| 182 | let mut f = fs::File::create(&tmp)?; |
| 183 | let mut header = [0u8; 16]; |
| 184 | header[..6].copy_from_slice(&FILE_MAGIC); |
| 185 | header[6] = FILE_VERSION; |
| 186 | // header[7] reserved. |
| 187 | header[8..12].copy_from_slice(&VOXEL_RES.to_le_bytes()); |
| 188 | // header[12..16] reserved. |
| 189 | f.write_all(&header)?; |
| 190 | f.write_all(voxel_bytes)?; |
| 191 | f.sync_data()?; |
| 192 | } |
| 193 | fs::rename(&tmp, &path)?; |
| 194 | Ok(()) |
| 195 | } |
| 196 | |
| 197 | #[cfg(test)] |
| 198 | mod tests { |