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