use std::marker::PhantomData;
#[derive(Debug, Clone, PartialEq)]
pub(crate) enum Tiling {
Default,
Rows(usize),
Dims(Vec<usize>),
}
#[derive(Debug, Clone, Copy, Default)]
pub struct AutoTile;
#[derive(Debug, Clone, Copy, Default)]
pub struct FixedTile;
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct Quantize {
pub(crate) level: f64,
pub(crate) seed: DitherSeed,
}
impl Default for Quantize {
fn default() -> Self {
Self {
level: 4.0,
seed: DitherSeed::Auto,
}
}
}
impl Quantize {
pub fn new() -> Self {
Self::default()
}
pub fn level(mut self, q: f64) -> Self {
self.level = q;
self
}
pub fn seed(mut self, seed: DitherSeed) -> Self {
self.seed = seed;
self
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[non_exhaustive]
pub enum DitherSeed {
Auto,
Fixed(u32),
}
macro_rules! tile_selectors {
($name:ident $(, $extra:ident : $ety:ty)*) => {
impl $name<AutoTile> {
pub fn tile_rows(self, rows: usize) -> $name<FixedTile> {
$name {
tiling: Tiling::Rows(rows),
$($extra: self.$extra,)*
_tile: PhantomData,
}
}
pub fn tile_dims<const N: usize>(self, dims: [usize; N]) -> $name<FixedTile> {
$name {
tiling: Tiling::Dims(dims.to_vec()),
$($extra: self.$extra,)*
_tile: PhantomData,
}
}
}
};
}
const GZIP_DEFAULT_LEVEL: u8 = 6;
#[derive(Debug, Clone)]
pub struct Gzip<Tile = AutoTile> {
tiling: Tiling,
level: u8,
_tile: PhantomData<Tile>,
}
impl Default for Gzip<AutoTile> {
fn default() -> Self {
Self {
tiling: Tiling::Default,
level: GZIP_DEFAULT_LEVEL,
_tile: PhantomData,
}
}
}
impl Gzip<AutoTile> {
pub fn new() -> Self {
Self::default()
}
}
tile_selectors!(Gzip, level: u8);
impl<Tile> Gzip<Tile> {
pub fn level(mut self, level: u8) -> Self {
self.level = level.min(9);
self
}
}
impl<Tile> From<Gzip<Tile>> for FitsCompression {
fn from(g: Gzip<Tile>) -> Self {
FitsCompression(Method::Gzip {
tiling: g.tiling,
level: g.level,
})
}
}
#[derive(Debug, Clone)]
pub struct Rice<Tile = AutoTile> {
tiling: Tiling,
quantize: Quantize,
_tile: PhantomData<Tile>,
}
impl Default for Rice<AutoTile> {
fn default() -> Self {
Self {
tiling: Tiling::Default,
quantize: Quantize::default(),
_tile: PhantomData,
}
}
}
impl Rice<AutoTile> {
pub fn new() -> Self {
Self::default()
}
}
tile_selectors!(Rice, quantize: Quantize);
impl<Tile> Rice<Tile> {
pub fn quantize(mut self, quantize: Quantize) -> Self {
self.quantize = quantize;
self
}
}
impl<Tile> From<Rice<Tile>> for FitsCompression {
fn from(r: Rice<Tile>) -> Self {
FitsCompression(Method::Rice {
tiling: r.tiling,
quantize: r.quantize,
})
}
}
#[derive(Debug, Clone)]
pub struct Hcompress<Tile = AutoTile> {
tiling: Tiling,
scale: i32,
smooth: bool,
quantize: Quantize,
_tile: PhantomData<Tile>,
}
impl Default for Hcompress<AutoTile> {
fn default() -> Self {
Self {
tiling: Tiling::Default,
scale: 0,
smooth: false,
quantize: Quantize::default(),
_tile: PhantomData,
}
}
}
impl Hcompress<AutoTile> {
pub fn new() -> Self {
Self::default()
}
}
tile_selectors!(Hcompress, scale: i32, smooth: bool, quantize: Quantize);
impl<Tile> Hcompress<Tile> {
pub fn scale(mut self, scale: i32) -> Self {
self.scale = scale;
self
}
pub fn smooth(mut self, smooth: bool) -> Self {
self.smooth = smooth;
self
}
pub fn quantize(mut self, quantize: Quantize) -> Self {
self.quantize = quantize;
self
}
}
impl<Tile> From<Hcompress<Tile>> for FitsCompression {
fn from(hc: Hcompress<Tile>) -> Self {
FitsCompression(Method::Hcompress {
tiling: hc.tiling,
scale: hc.scale,
smooth: hc.smooth,
quantize: hc.quantize,
})
}
}
#[derive(Debug, Clone, PartialEq)]
pub(crate) enum Method {
None,
Gzip {
tiling: Tiling,
level: u8,
},
Rice {
tiling: Tiling,
quantize: Quantize,
},
Hcompress {
tiling: Tiling,
scale: i32,
smooth: bool,
quantize: Quantize,
},
}
#[derive(Clone, PartialEq)]
pub struct FitsCompression(pub(crate) Method);
impl FitsCompression {
pub const NONE: FitsCompression = FitsCompression(Method::None);
pub fn kind(&self) -> FitsCompressionKind {
match self.0 {
Method::None => FitsCompressionKind::None,
Method::Gzip { .. } => FitsCompressionKind::Gzip,
Method::Rice { .. } => FitsCompressionKind::Rice,
Method::Hcompress { .. } => FitsCompressionKind::Hcompress,
}
}
}
impl Default for FitsCompression {
fn default() -> Self {
Self::NONE
}
}
impl std::fmt::Debug for FitsCompression {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{:?}", self.kind())
}
}
impl From<&FitsCompression> for FitsCompression {
fn from(c: &FitsCompression) -> Self {
c.clone()
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[non_exhaustive]
pub enum FitsCompressionKind {
None,
Gzip,
Rice,
Hcompress,
}