Last active
October 17, 2023 20:27
-
-
Save metasim/3539e492f0cfa2c50ac0fe4e3d0ca9a5 to your computer and use it in GitHub Desktop.
Safe Band Indexing for GDAL.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
use std::fmt::{Display, Formatter}; | |
use serde::{Deserialize, Serialize}; | |
use std::num::NonZeroUsize; | |
/// Represents a band index, which may be either one-based (Fortran-style, as used by GDAL) | |
/// or zero-based (C-style, as used by collection libraries). | |
#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)] | |
#[repr(u8)] | |
pub enum BIdx { | |
/// Zero-based indexing (i.e. C-style) | |
C(usize), | |
/// One-based indexing (i.e. Fortran-style). This is what GDAL uses. | |
F(NonZeroUsize) | |
} | |
impl BIdx { | |
pub fn c(index: usize) -> Self { | |
BIdx::C(index) | |
} | |
/// Create a one-based band index. Will panic if `index` is zero. | |
pub fn f(index: usize) -> Self { | |
assert!(index > 0, "Index value must be greater than zero"); | |
BIdx::F(NonZeroUsize::new(index).unwrap()) | |
} | |
/// If index is `C` style, return stored value | |
/// If index is `F` style, return stored value minus one. | |
pub fn as_c(&self) -> usize { | |
match self { | |
BIdx::C(i) => *i, | |
BIdx::F(i) => i.get() - 1 | |
} | |
} | |
/// If index is `C` style, return stored value plus one. | |
/// If index is `F` style, return stored value. | |
pub fn as_f(&self) -> usize { | |
match self { | |
BIdx::C(i) => *i + 1, | |
BIdx::F(i) => i.get() | |
} | |
} | |
pub fn b1() -> Self { BIdx::f(1) } | |
pub fn b2() -> Self { BIdx::f(2) } | |
pub fn b3() -> Self { BIdx::f(3) } | |
pub fn b4() -> Self { BIdx::f(4) } | |
pub fn b5() -> Self { BIdx::f(5) } | |
pub fn b6() -> Self { BIdx::f(6) } | |
pub fn b7() -> Self { BIdx::f(7) } | |
pub fn b8() -> Self { BIdx::f(8) } | |
} | |
impl Display for BIdx { | |
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { | |
let (s, i) = match self { | |
BIdx::C(i) => ('c', *i), | |
BIdx::F(i) => ('f', i.get()) | |
}; | |
write!(f, "{}{}", i, s) | |
} | |
} | |
pub trait IntoIdx { | |
fn c(self) -> BIdx; | |
fn f(self) -> BIdx; | |
} | |
impl IntoIdx for usize { | |
fn c(self) -> BIdx { | |
BIdx::c(self) | |
} | |
fn f(self) -> BIdx { | |
BIdx::f(self) | |
} | |
} | |
/// Convenience conversion from [i32] into [BIdx]. | |
/// Note: Will panic if invalid values are used. | |
impl IntoIdx for i32 { | |
fn c(self) -> BIdx { | |
assert!(self >= 0, "Index value must be non-negative"); | |
BIdx::c(self as usize) | |
} | |
fn f(self) -> BIdx { | |
assert!(self > 0, "Index value must be greater than zero"); | |
BIdx::f(self as usize) | |
} | |
} | |
/// Convenience conversion from [isize] into [BIdx]. | |
/// Note: Will panic if invalid values are used. | |
impl IntoIdx for isize { | |
fn c(self) -> BIdx { | |
assert!(self >= 0, "Index value must be non-negative"); | |
BIdx::c(self as usize) | |
} | |
fn f(self) -> BIdx { | |
assert!(self > 0, "Index value must be greater than zero"); | |
BIdx::f(self as usize) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment