Skip to content

Instantly share code, notes, and snippets.

@metasim
Last active October 17, 2023 20:27
Show Gist options
  • Save metasim/3539e492f0cfa2c50ac0fe4e3d0ca9a5 to your computer and use it in GitHub Desktop.
Save metasim/3539e492f0cfa2c50ac0fe4e3d0ca9a5 to your computer and use it in GitHub Desktop.
Safe Band Indexing for GDAL.
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