use std::fmt::Debug;
use std::io::Read;
use byteorder::BigEndian;
use serde::Serialize;
use byteorder::ReadBytesExt;
use crate::hdu::Error;
pub trait Value: Sized {
fn read_be<R: ReadBytesExt>(reader: &mut R) -> Result<Self, Error>;
}
impl Value for u8 {
fn read_be<R: ReadBytesExt>(reader: &mut R) -> Result<Self, Error> {
Ok(reader.read_u8()?)
}
}
impl Value for i16 {
fn read_be<R: ReadBytesExt>(reader: &mut R) -> Result<Self, Error> {
Ok(reader.read_i16::<BigEndian>()?)
}
}
impl Value for i32 {
fn read_be<R: ReadBytesExt>(reader: &mut R) -> Result<Self, Error> {
Ok(reader.read_i32::<BigEndian>()?)
}
}
impl Value for i64 {
fn read_be<R: ReadBytesExt>(reader: &mut R) -> Result<Self, Error> {
Ok(reader.read_i64::<BigEndian>()?)
}
}
impl Value for f32 {
fn read_be<R: ReadBytesExt>(reader: &mut R) -> Result<Self, Error> {
Ok(reader.read_f32::<BigEndian>()?)
}
}
impl Value for f64 {
fn read_be<R: ReadBytesExt>(reader: &mut R) -> Result<Self, Error> {
Ok(reader.read_f64::<BigEndian>()?)
}
}
#[derive(Debug, Serialize)]
pub struct It<R, T> {
pub(crate) reader: R,
num_items: usize,
cur_idx: usize,
_t: std::marker::PhantomData<T>,
}
use std::io::Cursor;
impl<R, T> It<Cursor<R>, T>
where
R: AsRef<[u8]>,
{
pub fn bytes(&self) -> &[u8] {
let inner = self.reader.get_ref();
inner.as_ref()
}
}
impl<R, T> It<&'_ Cursor<R>, T>
where
R: AsRef<[u8]>,
{
pub fn bytes(&self) -> &[u8] {
let inner = self.reader.get_ref();
inner.as_ref()
}
}
impl<R, T> It<&'_ mut Cursor<R>, T>
where
R: AsRef<[u8]>,
{
pub fn bytes(&self) -> &[u8] {
let inner = self.reader.get_ref();
inner.as_ref()
}
}
impl<R, T> It<R, T>
where
R: Read,
{
pub fn new(reader: R, limit: u64) -> Self {
let num_items = limit as usize / std::mem::size_of::<T>();
Self {
reader,
cur_idx: 0,
num_items,
_t: std::marker::PhantomData,
}
}
}
impl<R, T> Iterator for It<R, T>
where
R: Read,
T: Value,
{
type Item = T;
fn next(&mut self) -> Option<Self::Item> {
if self.cur_idx == self.num_items {
None
} else {
let byte = T::read_be(&mut self.reader);
self.cur_idx += 1;
byte.ok()
}
}
}
use std::io::Seek;
impl<R, T> It<R, T>
where
R: Read + Seek,
T: Value,
{
pub fn read_value(&mut self, idx: usize) -> Result<T, Error> {
if idx >= self.num_items {
Err(Error::StaticError("Value to retrieve is out of bounds"))
} else {
let t_bytes = std::mem::size_of::<T>() as i64;
let off = (idx as i64 - self.cur_idx as i64) * t_bytes;
self.reader.seek_relative(off)?;
self.cur_idx = idx;
self.next()
.ok_or(Error::StaticError("Value to retrieve is out of bounds"))
}
}
}