1mod allocation;
19mod bitstuff;
20mod huffman;
21mod io;
22mod lerc1;
23mod lerc2;
24mod pixel;
25mod types;
26
27#[cfg(test)]
28mod tests;
29
30use lerc_band_materialize::{BandLayout as MaterializeLayout, BandMaterializer, BandSink};
31use lerc_core::{BandLayout, BandSetInfo, BlobInfo, Error, Result};
32use ndarray::ArrayD;
33
34use crate::pixel::Sample;
35pub use crate::types::{
36 into_band_mask_ndarray, BandElement, BandElementKind, Decoded, DecodedBandSet, DecodedF64,
37 NdArrayElement,
38};
39
40macro_rules! dispatch_band_element {
41 ($target:ty, |$concrete:ident| $body:block) => {
42 match <$target as BandElement>::KIND {
43 BandElementKind::I8 => {
44 type $concrete = i8;
45 $body
46 }
47 BandElementKind::U8 => {
48 type $concrete = u8;
49 $body
50 }
51 BandElementKind::I16 => {
52 type $concrete = i16;
53 $body
54 }
55 BandElementKind::U16 => {
56 type $concrete = u16;
57 $body
58 }
59 BandElementKind::I32 => {
60 type $concrete = i32;
61 $body
62 }
63 BandElementKind::U32 => {
64 type $concrete = u32;
65 $body
66 }
67 BandElementKind::F32 => {
68 type $concrete = f32;
69 $body
70 }
71 BandElementKind::F64 => {
72 type $concrete = f64;
73 $body
74 }
75 }
76 };
77}
78
79pub fn inspect_first(blob: &[u8]) -> Result<BlobInfo> {
80 if lerc1::is_lerc1(blob) {
81 return lerc1::inspect(blob, None);
82 }
83 if lerc2::is_lerc2(blob) {
84 return lerc2::inspect(blob, None);
85 }
86 Err(Error::InvalidMagic)
87}
88
89pub fn inspect_first_with_mask(blob: &[u8], mask: &[u8]) -> Result<BlobInfo> {
90 let (info, _) = inspect_first_mask_with_info(blob, Some(mask), Some(mask))?;
91 Ok(info)
92}
93
94pub fn get_blob_info(blob: &[u8]) -> Result<BlobInfo> {
95 let info = inspect_first(blob)?;
96 ensure_single_blob_consumed(blob.len(), info.blob_size, "get_blob_info", "inspect_first")?;
97 Ok(info)
98}
99
100pub fn get_blob_info_with_mask(blob: &[u8], mask: &[u8]) -> Result<BlobInfo> {
101 let info = inspect_first_with_mask(blob, mask)?;
102 ensure_single_blob_consumed(
103 blob.len(),
104 info.blob_size,
105 "get_blob_info_with_mask",
106 "inspect_first_with_mask",
107 )?;
108 Ok(info)
109}
110
111pub fn get_band_count(blob: &[u8]) -> Result<usize> {
112 let mut offset = 0usize;
113 let mut count = 0usize;
114 let mut lerc1_mask: Option<Vec<u8>> = None;
115
116 while offset < blob.len() {
117 let slice = &blob[offset..];
118 let next_len = if lerc1::is_lerc1(slice) {
119 let parsed = lerc1::parse(slice, lerc1_mask.as_deref())?;
120 let next_len = parsed.info.blob_size;
121 lerc1_mask = parsed.mask;
122 next_len
123 } else if lerc2::is_lerc2(slice) {
124 let (parsed, _) = lerc2::parse(slice)?;
125 parsed.info.blob_size
126 } else {
127 return Err(Error::InvalidMagic);
128 };
129
130 offset = checked_next_offset(offset, next_len, blob.len())?;
131 count += 1;
132 }
133
134 Ok(count)
135}
136
137pub fn decode_first(blob: &[u8]) -> Result<Decoded> {
138 decode_first_with_masks(blob, None, None)
139}
140
141pub fn decode_first_with_mask(blob: &[u8], mask: &[u8]) -> Result<Decoded> {
142 decode_first_with_masks(blob, Some(mask), Some(mask))
143}
144
145pub fn decode(blob: &[u8]) -> Result<Decoded> {
146 let decoded = decode_first(blob)?;
147 ensure_single_blob_consumed(blob.len(), decoded.info.blob_size, "decode", "decode_first")?;
148 Ok(decoded)
149}
150
151pub fn decode_with_mask(blob: &[u8], mask: &[u8]) -> Result<Decoded> {
152 let decoded = decode_first_with_mask(blob, mask)?;
153 ensure_single_blob_consumed(
154 blob.len(),
155 decoded.info.blob_size,
156 "decode_with_mask",
157 "decode_first_with_mask",
158 )?;
159 Ok(decoded)
160}
161
162pub fn decode_band_set(blob: &[u8]) -> Result<DecodedBandSet> {
163 decode_band_set_with_lerc2_mask(blob, None)
164}
165
166pub fn decode_band_set_with_mask(blob: &[u8], mask: &[u8]) -> Result<DecodedBandSet> {
167 decode_band_set_with_lerc2_mask(blob, Some(mask))
168}
169
170pub fn decode_band_set_vec<T: BandElement>(
171 blob: &[u8],
172 layout: BandLayout,
173) -> Result<(BandSetInfo, Vec<T>)> {
174 decode_band_set_owned(blob, layout, None)
175}
176
177pub fn decode_band_set_vec_with_mask<T: BandElement>(
178 blob: &[u8],
179 mask: &[u8],
180 layout: BandLayout,
181) -> Result<(BandSetInfo, Vec<T>)> {
182 decode_band_set_owned(blob, layout, Some(mask))
183}
184
185pub fn decode_band_set_into<T: BandElement>(
186 blob: &[u8],
187 layout: BandLayout,
188 out: &mut [T],
189) -> Result<BandSetInfo> {
190 decode_band_set_into_direct(blob, layout, None, out)
191}
192
193pub fn decode_band_set_into_with_mask<T: BandElement>(
194 blob: &[u8],
195 mask: &[u8],
196 layout: BandLayout,
197 out: &mut [T],
198) -> Result<BandSetInfo> {
199 decode_band_set_into_direct(blob, layout, Some(mask), out)
200}
201
202pub fn decode_band_set_ndarray<T: BandElement>(blob: &[u8]) -> Result<ArrayD<T>> {
203 decode_band_set_ndarray_with_layout(blob, BandLayout::Interleaved)
204}
205
206pub fn decode_band_set_ndarray_with_mask<T: BandElement>(
207 blob: &[u8],
208 mask: &[u8],
209) -> Result<ArrayD<T>> {
210 decode_band_set_ndarray_with_layout_and_mask(blob, BandLayout::Interleaved, mask)
211}
212
213pub fn decode_band_set_ndarray_with_layout<T: BandElement>(
214 blob: &[u8],
215 layout: BandLayout,
216) -> Result<ArrayD<T>> {
217 decode_band_set_ndarray_with_layout_impl(blob, layout, None)
218}
219
220pub fn decode_band_set_ndarray_with_layout_and_mask<T: BandElement>(
221 blob: &[u8],
222 layout: BandLayout,
223 mask: &[u8],
224) -> Result<ArrayD<T>> {
225 decode_band_set_ndarray_with_layout_impl(blob, layout, Some(mask))
226}
227
228pub fn decode_band_set_ndarray_f64(blob: &[u8]) -> Result<ArrayD<f64>> {
229 decode_band_set_ndarray_f64_with_optional_mask(blob, None)
230}
231
232pub fn decode_band_set_ndarray_f64_with_mask(blob: &[u8], mask: &[u8]) -> Result<ArrayD<f64>> {
233 decode_band_set_ndarray_f64_with_optional_mask(blob, Some(mask))
234}
235
236pub fn decode_band_mask_ndarray(blob: &[u8]) -> Result<Option<ArrayD<u8>>> {
237 let (info, band_masks) = inspect_band_masks(blob, None)?;
238 into_band_mask_ndarray(info, band_masks)
239}
240
241pub fn decode_band_mask_ndarray_with_mask(blob: &[u8], mask: &[u8]) -> Result<Option<ArrayD<u8>>> {
242 let (info, band_masks) = inspect_band_masks(blob, Some(mask))?;
243 into_band_mask_ndarray(info, band_masks)
244}
245
246fn decode_band_set_with_lerc2_mask(
247 blob: &[u8],
248 initial_lerc2_mask: Option<&[u8]>,
249) -> Result<DecodedBandSet> {
250 let mut offset = 0usize;
251 let mut bands = Vec::new();
252 let mut infos = Vec::new();
253 let mut band_masks = Vec::new();
254 let mut lerc1_mask: Option<Vec<u8>> = None;
255 let mut lerc2_mask = initial_lerc2_mask.map(|mask| mask.to_vec());
256
257 while offset < blob.len() {
258 let decoded = decode_first_with_masks(
259 &blob[offset..],
260 lerc1_mask.as_deref(),
261 lerc2_mask.as_deref(),
262 )?;
263
264 if lerc1::is_lerc1(&blob[offset..]) {
265 lerc1_mask = decoded.mask.clone();
266 lerc2_mask = None;
267 } else {
268 lerc2_mask = decoded.mask.clone();
269 lerc1_mask = None;
270 }
271
272 offset = checked_next_offset(offset, decoded.info.blob_size, blob.len())?;
273 infos.push(decoded.info);
274 bands.push(decoded.pixels);
275 band_masks.push(decoded.mask);
276 }
277
278 Ok(DecodedBandSet {
279 info: BandSetInfo::new(infos)?,
280 bands,
281 band_masks,
282 })
283}
284
285fn decode_band_set_ndarray_with_layout_impl<T: BandElement>(
286 blob: &[u8],
287 layout: BandLayout,
288 initial_lerc2_mask: Option<&[u8]>,
289) -> Result<ArrayD<T>> {
290 let (info, values) = decode_band_set_owned(blob, layout, initial_lerc2_mask)?;
291 let shape = info.ndarray_shape_for_layout(layout);
292 ArrayD::from_shape_vec(ndarray::IxDyn(&shape), values).map_err(|e| {
293 Error::InvalidBlob(format!(
294 "failed to build ndarray from decoded band set: {e}"
295 ))
296 })
297}
298
299fn decode_band_set_ndarray_f64_with_optional_mask(
300 blob: &[u8],
301 initial_lerc2_mask: Option<&[u8]>,
302) -> Result<ArrayD<f64>> {
303 let band_info = decode_band_set_to_f64_info(blob, BandLayout::Interleaved, initial_lerc2_mask)?;
304 let shape = band_info
305 .0
306 .ndarray_shape_for_layout(BandLayout::Interleaved);
307 ArrayD::from_shape_vec(ndarray::IxDyn(&shape), band_info.1).map_err(|e| {
308 Error::InvalidBlob(format!(
309 "failed to build ndarray from decoded band set: {e}"
310 ))
311 })
312}
313
314pub fn decode_to_f64(blob: &[u8]) -> Result<DecodedF64> {
315 let decoded = decode_first_to_f64(blob)?;
316 ensure_single_blob_consumed(
317 blob.len(),
318 decoded.info.blob_size,
319 "decode_to_f64",
320 "decode_first_to_f64",
321 )?;
322 Ok(decoded)
323}
324
325pub fn decode_to_f64_with_mask(blob: &[u8], mask: &[u8]) -> Result<DecodedF64> {
326 let decoded = decode_first_to_f64_with_mask(blob, mask)?;
327 ensure_single_blob_consumed(
328 blob.len(),
329 decoded.info.blob_size,
330 "decode_to_f64_with_mask",
331 "decode_first_to_f64_with_mask",
332 )?;
333 Ok(decoded)
334}
335
336pub fn decode_first_to_f64(blob: &[u8]) -> Result<DecodedF64> {
337 decode_first_f64(blob)
338}
339
340pub fn decode_first_to_f64_with_mask(blob: &[u8], mask: &[u8]) -> Result<DecodedF64> {
341 decode_first_f64_with_masks(blob, Some(mask), Some(mask))
342}
343
344pub fn decode_ndarray<T: NdArrayElement>(blob: &[u8]) -> Result<ArrayD<T>> {
345 decode(blob)?.into_ndarray()
346}
347
348pub fn decode_ndarray_with_mask<T: NdArrayElement>(blob: &[u8], mask: &[u8]) -> Result<ArrayD<T>> {
349 decode_with_mask(blob, mask)?.into_ndarray()
350}
351
352pub fn decode_ndarray_f64(blob: &[u8]) -> Result<ArrayD<f64>> {
353 decode_to_f64(blob)?.into_ndarray()
354}
355
356pub fn decode_ndarray_f64_with_mask(blob: &[u8], mask: &[u8]) -> Result<ArrayD<f64>> {
357 decode_to_f64_with_mask(blob, mask)?.into_ndarray()
358}
359
360pub fn decode_mask_ndarray(blob: &[u8]) -> Result<Option<ArrayD<u8>>> {
361 let (info, mask) = inspect_first_mask_with_info(blob, None, None)?;
362 ensure_single_blob_consumed(
363 blob.len(),
364 info.blob_size,
365 "decode_mask_ndarray",
366 "inspect_first",
367 )?;
368 mask_to_ndarray(&info, mask)
369}
370
371pub fn decode_mask_ndarray_with_mask(blob: &[u8], mask: &[u8]) -> Result<Option<ArrayD<u8>>> {
372 let (info, decoded_mask) = inspect_first_mask_with_info(blob, Some(mask), Some(mask))?;
373 ensure_single_blob_consumed(
374 blob.len(),
375 info.blob_size,
376 "decode_mask_ndarray_with_mask",
377 "inspect_first_with_mask",
378 )?;
379 mask_to_ndarray(&info, decoded_mask)
380}
381
382fn decode_first_with_masks(
383 blob: &[u8],
384 lerc1_shared_mask: Option<&[u8]>,
385 lerc2_shared_mask: Option<&[u8]>,
386) -> Result<Decoded> {
387 if lerc1::is_lerc1(blob) {
388 return lerc1::decode(blob, lerc1_shared_mask);
389 }
390 if lerc2::is_lerc2(blob) {
391 return lerc2::decode(blob, lerc2_shared_mask);
392 }
393 Err(Error::InvalidMagic)
394}
395
396fn inspect_first_mask_with_info(
397 blob: &[u8],
398 lerc1_shared_mask: Option<&[u8]>,
399 lerc2_shared_mask: Option<&[u8]>,
400) -> Result<(BlobInfo, Option<Vec<u8>>)> {
401 if lerc1::is_lerc1(blob) {
402 return lerc1::inspect_mask(blob, lerc1_shared_mask);
403 }
404 if lerc2::is_lerc2(blob) {
405 return lerc2::inspect_with_mask(blob, lerc2_shared_mask);
406 }
407 Err(Error::InvalidMagic)
408}
409
410fn decode_first_f64(blob: &[u8]) -> Result<DecodedF64> {
411 decode_first_f64_with_masks(blob, None, None)
412}
413
414fn decode_first_f64_with_masks(
415 blob: &[u8],
416 lerc1_shared_mask: Option<&[u8]>,
417 lerc2_shared_mask: Option<&[u8]>,
418) -> Result<DecodedF64> {
419 if lerc1::is_lerc1(blob) {
420 return lerc1::decode_f64(blob, lerc1_shared_mask);
421 }
422 if lerc2::is_lerc2(blob) {
423 return lerc2::decode_f64(blob, lerc2_shared_mask);
424 }
425 Err(Error::InvalidMagic)
426}
427
428fn decode_band_set_owned<T: BandElement>(
429 blob: &[u8],
430 layout: BandLayout,
431 initial_lerc2_mask: Option<&[u8]>,
432) -> Result<(BandSetInfo, Vec<T>)> {
433 let band_info = scan_band_infos(blob)?;
434 decode_band_set_owned_direct(blob, layout, band_info, initial_lerc2_mask)
435}
436
437fn decode_band_set_into_direct<T: BandElement>(
438 blob: &[u8],
439 layout: BandLayout,
440 initial_lerc2_mask: Option<&[u8]>,
441 out: &mut [T],
442) -> Result<BandSetInfo> {
443 dispatch_band_element!(T, |Concrete| {
444 decode_band_set_into_impl::<Concrete>(
445 blob,
446 layout,
447 initial_lerc2_mask,
448 cast_slice_mut::<T, Concrete>(out),
449 )
450 })
451}
452
453fn decode_band_set_owned_direct<T: BandElement>(
454 blob: &[u8],
455 layout: BandLayout,
456 band_info: BandSetInfo,
457 initial_lerc2_mask: Option<&[u8]>,
458) -> Result<(BandSetInfo, Vec<T>)> {
459 dispatch_band_element!(T, |Concrete| {
460 decode_band_set_owned_direct_impl::<Concrete>(blob, layout, band_info, initial_lerc2_mask)
461 .map(|(info, values)| (info, cast_vec::<T, Concrete>(values)))
462 })
463}
464
465fn decode_band_set_into_impl<T: Sample + NdArrayElement>(
466 blob: &[u8],
467 layout: BandLayout,
468 initial_lerc2_mask: Option<&[u8]>,
469 out: &mut [T],
470) -> Result<BandSetInfo> {
471 let band_info = scan_band_infos(blob)?;
472 decode_band_set_into_impl_with_info(blob, layout, initial_lerc2_mask, &band_info, out)?;
473 Ok(band_info)
474}
475
476fn decode_band_set_into_impl_with_info<T: Sample + NdArrayElement>(
477 blob: &[u8],
478 layout: BandLayout,
479 initial_lerc2_mask: Option<&[u8]>,
480 band_info: &BandSetInfo,
481 out: &mut [T],
482) -> Result<()> {
483 let band_count = band_info.band_count();
484 let expected_len = band_info.value_count()?;
485 if out.len() != expected_len {
486 return Err(Error::InvalidBlob(format!(
487 "output slice length {} does not match decoded band set length {}",
488 out.len(),
489 expected_len
490 )));
491 }
492
493 let pixel_count = band_info.bands[0].pixel_count()?;
494 let depth = band_info.depth() as usize;
495 let mut offset = 0usize;
496 let mut band_index = 0usize;
497 let mut lerc1_mask: Option<Vec<u8>> = None;
498 let mut lerc2_mask = initial_lerc2_mask.map(|mask| mask.to_vec());
499
500 while offset < blob.len() {
501 let slice = &blob[offset..];
502 let is_lerc1 = lerc1::is_lerc1(slice);
503 let mut sink = BandSink::new(
504 out,
505 pixel_count,
506 depth,
507 band_index,
508 band_count,
509 materialize_layout(layout),
510 );
511 let (info, mask) = if is_lerc1 {
512 lerc1::decode_into(slice, lerc1_mask.as_deref(), &mut sink)?
513 } else if lerc2::is_lerc2(slice) {
514 lerc2::decode_into(slice, lerc2_mask.as_deref(), &mut sink)?
515 } else {
516 return Err(Error::InvalidMagic);
517 };
518
519 if is_lerc1 {
520 lerc1_mask = mask;
521 lerc2_mask = None;
522 } else {
523 lerc2_mask = mask;
524 lerc1_mask = None;
525 }
526
527 offset = checked_next_offset(offset, info.blob_size, blob.len())?;
528 band_index += 1;
529 }
530
531 Ok(())
532}
533
534fn decode_band_set_to_f64_info(
535 blob: &[u8],
536 layout: BandLayout,
537 initial_lerc2_mask: Option<&[u8]>,
538) -> Result<(BandSetInfo, Vec<f64>)> {
539 let band_info = scan_band_infos(blob)?;
540 decode_band_set_owned_direct_impl::<f64>(blob, layout, band_info, initial_lerc2_mask)
541}
542
543fn inspect_band_masks(
544 blob: &[u8],
545 initial_lerc2_mask: Option<&[u8]>,
546) -> Result<(BandSetInfo, Vec<Option<Vec<u8>>>)> {
547 let mut offset = 0usize;
548 let mut infos = Vec::new();
549 let mut band_masks = Vec::new();
550 let mut lerc1_mask: Option<Vec<u8>> = None;
551 let mut lerc2_mask = initial_lerc2_mask.map(|mask| mask.to_vec());
552
553 while offset < blob.len() {
554 let slice = &blob[offset..];
555 let is_lerc1 = lerc1::is_lerc1(slice);
556 let (info, mask) =
557 inspect_first_mask_with_info(slice, lerc1_mask.as_deref(), lerc2_mask.as_deref())?;
558
559 if is_lerc1 {
560 lerc1_mask = mask.clone();
561 lerc2_mask = None;
562 } else {
563 lerc2_mask = mask.clone();
564 lerc1_mask = None;
565 }
566
567 offset = checked_next_offset(offset, info.blob_size, blob.len())?;
568 infos.push(info);
569 band_masks.push(mask);
570 }
571
572 Ok((BandSetInfo::new(infos)?, band_masks))
573}
574
575fn scan_band_infos(blob: &[u8]) -> Result<BandSetInfo> {
576 let mut offset = 0usize;
577 let mut infos = Vec::new();
578 let mut lerc1_mask: Option<Vec<u8>> = None;
579
580 while offset < blob.len() {
581 let slice = &blob[offset..];
582 let (info, next_lerc1_mask) = if lerc1::is_lerc1(slice) {
583 let parsed = lerc1::parse(slice, lerc1_mask.as_deref())?;
584 let info = parsed.info;
585 let next_mask = parsed.mask;
586 (info, next_mask)
587 } else if lerc2::is_lerc2(slice) {
588 let (parsed, _) = lerc2::parse(slice)?;
589 (parsed.info, None)
590 } else {
591 return Err(Error::InvalidMagic);
592 };
593
594 offset = checked_next_offset(offset, info.blob_size, blob.len())?;
595 lerc1_mask = next_lerc1_mask;
596 infos.push(info);
597 }
598
599 BandSetInfo::new(infos)
600}
601
602fn ensure_single_blob_consumed(
603 blob_len: usize,
604 decoded_len: usize,
605 strict_api: &str,
606 permissive_api: &str,
607) -> Result<()> {
608 if blob_len == decoded_len {
609 return Ok(());
610 }
611 Err(Error::InvalidBlob(format!(
612 "{strict_api} only accepts a single LERC blob; found {} trailing bytes, use {permissive_api} for first-blob decoding or decode_band_set for concatenated rasters",
613 blob_len - decoded_len
614 )))
615}
616
617fn checked_next_offset(offset: usize, next_len: usize, total_len: usize) -> Result<usize> {
618 let next = offset
619 .checked_add(next_len)
620 .ok_or_else(|| Error::InvalidBlob("band offset overflow".into()))?;
621 if next <= offset || next > total_len {
622 return Err(Error::InvalidBlob(
623 "invalid concatenated band blob size".into(),
624 ));
625 }
626 Ok(next)
627}
628
629fn materialize_layout(layout: BandLayout) -> MaterializeLayout {
630 match layout {
631 BandLayout::Interleaved => MaterializeLayout::Interleaved,
632 BandLayout::Bsq => MaterializeLayout::Bsq,
633 }
634}
635
636fn materialize_error(err: lerc_band_materialize::MaterializeError) -> Error {
637 Error::InvalidBlob(err.to_string())
638}
639
640fn mask_to_ndarray(info: &BlobInfo, mask: Option<Vec<u8>>) -> Result<Option<ArrayD<u8>>> {
641 let shape = info.mask_ndarray_shape();
642 mask.map(|mask| {
643 ArrayD::from_shape_vec(ndarray::IxDyn(&shape), mask).map_err(|e| {
644 Error::InvalidBlob(format!("failed to build ndarray from decoded mask: {e}"))
645 })
646 })
647 .transpose()
648}
649
650fn decode_band_set_owned_direct_impl<T: Sample + NdArrayElement + Copy + Default>(
651 blob: &[u8],
652 layout: BandLayout,
653 band_info: BandSetInfo,
654 initial_lerc2_mask: Option<&[u8]>,
655) -> Result<(BandSetInfo, Vec<T>)> {
656 let expected_len = band_info.value_count()?;
657 if expected_len == 0 {
658 return Ok((band_info, Vec::new()));
659 }
660
661 let pixel_count = band_info.bands[0].pixel_count()?;
662 let depth = band_info.depth() as usize;
663 let band_count = band_info.band_count();
664 let mut materializer =
665 BandMaterializer::new(pixel_count, depth, band_count, materialize_layout(layout))
666 .map_err(materialize_error)?;
667 let mut offset = 0usize;
668 let mut band_index = 0usize;
669 let mut lerc1_mask: Option<Vec<u8>> = None;
670 let mut lerc2_mask = initial_lerc2_mask.map(|mask| mask.to_vec());
671
672 while offset < blob.len() {
673 let slice = &blob[offset..];
674 let is_lerc1 = lerc1::is_lerc1(slice);
675 let (info, mask) = {
676 let mut writer = materializer
677 .band_writer(band_index)
678 .map_err(materialize_error)?;
679 let decoded = if is_lerc1 {
680 lerc1::decode_into(slice, lerc1_mask.as_deref(), &mut writer)?
681 } else if lerc2::is_lerc2(slice) {
682 lerc2::decode_into(slice, lerc2_mask.as_deref(), &mut writer)?
683 } else {
684 return Err(Error::InvalidMagic);
685 };
686 writer.finish().map_err(materialize_error)?;
687 decoded
688 };
689
690 if is_lerc1 {
691 lerc1_mask = mask;
692 lerc2_mask = None;
693 } else {
694 lerc2_mask = mask;
695 lerc1_mask = None;
696 }
697
698 offset = checked_next_offset(offset, info.blob_size, blob.len())?;
699 band_index += 1;
700 }
701
702 Ok((band_info, materializer.finish().map_err(materialize_error)?))
703}
704
705fn cast_slice_mut<T, U>(slice: &mut [T]) -> &mut [U] {
706 unsafe { &mut *(slice as *mut [T] as *mut [U]) }
707}
708
709fn cast_vec<T, U>(values: Vec<U>) -> Vec<T> {
710 let len = values.len();
711 let cap = values.capacity();
712 let ptr = values.as_ptr() as *mut T;
713 std::mem::forget(values);
714 unsafe { Vec::from_raw_parts(ptr, len, cap) }
715}