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