use super::lowlevel::*;
use super::types::*;
use std::cell::RefCell;
use std::fmt;
use std::fmt::Display;
pub(crate) struct NumArray<I>(RefCell<Option<I>>);
impl<I> NumArray<I> {
pub fn new(i: I) -> Self {
Self(RefCell::new(Some(i)))
}
}
impl<T: Display, I: IntoIterator<Item = T>> Display for NumArray<I> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let mut first = true;
let iter = self.0.borrow_mut().take().unwrap();
for number in iter {
if !first {
write!(f, ", {number}")?;
first = false;
} else {
write!(f, "{number}")?;
}
}
Ok(())
}
}
pub(crate) fn tag_value_new(f: &IfdEntry) -> Option<TagValue> {
Some(match f.format {
IfdFormat::Ascii => {
let mut data = &f.data[..];
while let Some((&val, rest)) = data.split_last() {
if val != 0 {
break;
}
data = rest;
}
let s = String::from_utf8_lossy(data);
let s = s.into_owned();
TagValue::Ascii(s)
},
IfdFormat::U16 => {
let a = read_u16_array(f.le, f.count, &f.data)?;
TagValue::U16(a)
},
IfdFormat::I16 => {
let a = read_i16_array(f.le, f.count, &f.data)?;
TagValue::I16(a)
},
IfdFormat::U8 => {
if f.data.len() < f.count as usize {
return None;
}
TagValue::U8(f.data.clone())
},
IfdFormat::I8 => {
let a = read_i8_array(f.count, &f.data)?;
TagValue::I8(a)
},
IfdFormat::U32 => {
let a = read_u32_array(f.le, f.count, &f.data)?;
TagValue::U32(a)
},
IfdFormat::I32 => {
let a = read_i32_array(f.le, f.count, &f.data)?;
TagValue::I32(a)
},
IfdFormat::F32 => {
let a = read_f32_array(f.count, &f.data)?;
TagValue::F32(a)
},
IfdFormat::F64 => {
let a = read_f64_array(f.count, &f.data)?;
TagValue::F64(a)
},
IfdFormat::URational => {
let a = read_urational_array(f.le, f.count, &f.data)?;
TagValue::URational(a)
},
IfdFormat::IRational => {
let a = read_irational_array(f.le, f.count, &f.data)?;
TagValue::IRational(a)
},
IfdFormat::Undefined => {
let a = f.data.clone();
TagValue::Undefined(a, f.le)
},
_ => TagValue::Unknown(f.data.clone(), f.le),
})
}
fn vec_cmp_f32(va: &[f32], vb: &[f32]) -> bool {
(va.len() == vb.len()) && va.iter().zip(vb)
.all(|(a, b)| (a == b) || (a.is_nan() && b.is_nan()))
}
fn vec_cmp_f64(va: &[f64], vb: &[f64]) -> bool {
(va.len() == vb.len()) && va.iter().zip(vb)
.all(|(a, b)| (a == b) || (a.is_nan() && b.is_nan()))
}
pub(crate) fn tag_value_eq(left: &TagValue, right: &TagValue) -> bool {
match (left, right) {
(TagValue::F32(x), TagValue::F32(y)) => vec_cmp_f32(x, y),
(TagValue::F64(x), TagValue::F64(y)) => vec_cmp_f64(x, y),
(x, y) => x == y,
}
}