use std::{borrow::Cow, io::Write, slice::from_ref};
use crate::{
bytecast,
error::{TiffError, TiffFormatError, TiffResult},
structs::tags::TagType,
};
pub trait TiffValue {
const BYTE_LEN: u8;
fn is_type(&self) -> TagType;
fn count(&self) -> usize;
fn n_bytes(&self) -> usize {
self.count() * usize::from(Self::BYTE_LEN)
}
fn data(&self) -> Cow<[u8]>;
}
impl TiffValue for [u8] {
const BYTE_LEN: u8 = 1;
fn is_type(&self) -> TagType {
TagType::BYTE
}
fn count(&self) -> usize {
self.len()
}
fn data(&self) -> Cow<[u8]> {
Cow::Borrowed(self)
}
}
impl TiffValue for [i8] {
const BYTE_LEN: u8 = 1;
fn is_type(&self) -> TagType {
TagType::SBYTE
}
fn count(&self) -> usize {
self.len()
}
fn data(&self) -> Cow<[u8]> {
Cow::Borrowed(bytecast::i8_as_ne_bytes(self))
}
}
impl TiffValue for [u16] {
const BYTE_LEN: u8 = 2;
fn is_type(&self) -> TagType {
TagType::SHORT
}
fn count(&self) -> usize {
self.len()
}
fn data(&self) -> Cow<[u8]> {
Cow::Borrowed(bytecast::u16_as_ne_bytes(self))
}
}
impl TiffValue for [i16] {
const BYTE_LEN: u8 = 2;
fn is_type(&self) -> TagType {
TagType::SSHORT
}
fn count(&self) -> usize {
self.len()
}
fn data(&self) -> Cow<[u8]> {
Cow::Borrowed(bytecast::i16_as_ne_bytes(self))
}
}
impl TiffValue for [u32] {
const BYTE_LEN: u8 = 4;
fn is_type(&self) -> TagType {
TagType::LONG
}
fn count(&self) -> usize {
self.len()
}
fn data(&self) -> Cow<[u8]> {
Cow::Borrowed(bytecast::u32_as_ne_bytes(self))
}
}
impl TiffValue for [i32] {
const BYTE_LEN: u8 = 4;
fn is_type(&self) -> TagType {
TagType::SLONG
}
fn count(&self) -> usize {
self.len()
}
fn data(&self) -> Cow<[u8]> {
Cow::Borrowed(bytecast::i32_as_ne_bytes(self))
}
}
impl TiffValue for [u64] {
const BYTE_LEN: u8 = 8;
fn is_type(&self) -> TagType {
TagType::LONG8
}
fn count(&self) -> usize {
self.len()
}
fn data(&self) -> Cow<[u8]> {
Cow::Borrowed(bytecast::u64_as_ne_bytes(self))
}
}
impl TiffValue for [i64] {
const BYTE_LEN: u8 = 8;
fn is_type(&self) -> TagType {
TagType::SLONG8
}
fn count(&self) -> usize {
self.len()
}
fn data(&self) -> Cow<[u8]> {
Cow::Borrowed(bytecast::i64_as_ne_bytes(self))
}
}
impl TiffValue for [f32] {
const BYTE_LEN: u8 = 4;
fn is_type(&self) -> TagType {
TagType::FLOAT
}
fn count(&self) -> usize {
self.len()
}
fn data(&self) -> Cow<[u8]> {
Cow::Borrowed(bytecast::f32_as_ne_bytes(self))
}
}
impl TiffValue for [f64] {
const BYTE_LEN: u8 = 8;
fn is_type(&self) -> TagType {
TagType::DOUBLE
}
fn count(&self) -> usize {
self.len()
}
fn data(&self) -> Cow<[u8]> {
Cow::Borrowed(bytecast::f64_as_ne_bytes(self))
}
}
impl TiffValue for u8 {
const BYTE_LEN: u8 = 1;
fn is_type(&self) -> TagType {
TagType::BYTE
}
fn count(&self) -> usize {
1
}
fn data(&self) -> Cow<[u8]> {
Cow::Borrowed(from_ref(self))
}
}
impl TiffValue for i8 {
const BYTE_LEN: u8 = 1;
fn is_type(&self) -> TagType {
TagType::SBYTE
}
fn count(&self) -> usize {
1
}
fn data(&self) -> Cow<[u8]> {
Cow::Borrowed(bytecast::i8_as_ne_bytes(from_ref(self)))
}
}
impl TiffValue for u16 {
const BYTE_LEN: u8 = 2;
fn is_type(&self) -> TagType {
TagType::SHORT
}
fn count(&self) -> usize {
1
}
fn data(&self) -> Cow<[u8]> {
Cow::Borrowed(bytecast::u16_as_ne_bytes(from_ref(self)))
}
}
impl TiffValue for i16 {
const BYTE_LEN: u8 = 2;
fn is_type(&self) -> TagType {
TagType::SSHORT
}
fn count(&self) -> usize {
1
}
fn data(&self) -> Cow<[u8]> {
Cow::Borrowed(bytecast::i16_as_ne_bytes(from_ref(self)))
}
}
impl TiffValue for u32 {
const BYTE_LEN: u8 = 4;
fn is_type(&self) -> TagType {
TagType::LONG
}
fn count(&self) -> usize {
1
}
fn data(&self) -> Cow<[u8]> {
Cow::Borrowed(bytecast::u32_as_ne_bytes(from_ref(self)))
}
}
impl TiffValue for i32 {
const BYTE_LEN: u8 = 4;
fn is_type(&self) -> TagType {
TagType::SLONG
}
fn count(&self) -> usize {
1
}
fn data(&self) -> Cow<[u8]> {
Cow::Borrowed(bytecast::i32_as_ne_bytes(from_ref(self)))
}
}
impl TiffValue for u64 {
const BYTE_LEN: u8 = 8;
fn is_type(&self) -> TagType {
TagType::LONG8
}
fn count(&self) -> usize {
1
}
fn data(&self) -> Cow<[u8]> {
Cow::Borrowed(bytecast::u64_as_ne_bytes(from_ref(self)))
}
}
impl TiffValue for i64 {
const BYTE_LEN: u8 = 8;
fn is_type(&self) -> TagType {
TagType::SLONG8
}
fn count(&self) -> usize {
1
}
fn data(&self) -> Cow<[u8]> {
Cow::Borrowed(bytecast::i64_as_ne_bytes(from_ref(self)))
}
}
impl TiffValue for f32 {
const BYTE_LEN: u8 = 4;
fn is_type(&self) -> TagType {
TagType::FLOAT
}
fn count(&self) -> usize {
1
}
fn data(&self) -> Cow<[u8]> {
Cow::Borrowed(bytecast::f32_as_ne_bytes(from_ref(self)))
}
}
impl TiffValue for f64 {
const BYTE_LEN: u8 = 8;
fn is_type(&self) -> TagType {
TagType::DOUBLE
}
fn count(&self) -> usize {
1
}
fn data(&self) -> Cow<[u8]> {
Cow::Borrowed(bytecast::f64_as_ne_bytes(from_ref(self)))
}
}
impl TiffValue for Ifd {
const BYTE_LEN: u8 = 4;
fn is_type(&self) -> TagType {
TagType::IFD
}
fn count(&self) -> usize {
1
}
fn data(&self) -> Cow<[u8]> {
Cow::Borrowed(bytecast::u32_as_ne_bytes(from_ref(&self.0)))
}
}
impl TiffValue for Ifd8 {
const BYTE_LEN: u8 = 8;
fn is_type(&self) -> TagType {
TagType::IFD8
}
fn count(&self) -> usize {
1
}
fn data(&self) -> Cow<[u8]> {
Cow::Borrowed(bytecast::u64_as_ne_bytes(from_ref(&self.0)))
}
}
impl TiffValue for Rational {
const BYTE_LEN: u8 = 8;
fn is_type(&self) -> TagType {
TagType::RATIONAL
}
fn count(&self) -> usize {
1
}
fn data(&self) -> Cow<[u8]> {
Cow::Owned({
let first_dword = bytecast::u32_as_ne_bytes(from_ref(&self.n));
let second_dword = bytecast::u32_as_ne_bytes(from_ref(&self.d));
[first_dword, second_dword].concat()
})
}
}
impl TiffValue for SRational {
const BYTE_LEN: u8 = 8;
fn is_type(&self) -> TagType {
TagType::SRATIONAL
}
fn count(&self) -> usize {
1
}
fn data(&self) -> Cow<[u8]> {
Cow::Owned({
let first_dword = bytecast::i32_as_ne_bytes(from_ref(&self.n));
let second_dword = bytecast::i32_as_ne_bytes(from_ref(&self.d));
[first_dword, second_dword].concat()
})
}
}
impl TiffValue for str {
const BYTE_LEN: u8 = 1;
fn is_type(&self) -> TagType {
TagType::ASCII
}
fn count(&self) -> usize {
self.len() + 1
}
fn data(&self) -> Cow<[u8]> {
Cow::Owned({
if self.is_ascii() && !self.bytes().any(|b| b == 0) {
let bytes: &[u8] = self.as_bytes();
[bytes, &[0]].concat()
} else {
vec![]
}
})
}
}
impl<'a, T: TiffValue + ?Sized> TiffValue for &'a T {
const BYTE_LEN: u8 = T::BYTE_LEN;
fn is_type(&self) -> TagType {
(*self).is_type()
}
fn count(&self) -> usize {
(*self).count()
}
fn data(&self) -> Cow<[u8]> {
T::data(self)
}
}
macro_rules! impl_tiff_value_for_contiguous_sequence {
($inner_type:ty; $bytes:expr; $field_type:expr) => {
impl $crate::encoder::tiff_value::TiffValue for [$inner_type] {
const BYTE_LEN: u8 = $bytes;
fn is_type(&self) -> TagType {
$field_type
}
fn count(&self) -> usize {
self.len()
}
fn data(&self) -> Cow<[u8]> {
let mut buf: Vec<u8> = Vec::with_capacity(Self::BYTE_LEN as usize * self.len());
for x in self {
buf.extend_from_slice(&x.data());
}
Cow::Owned(buf)
}
}
};
}
impl_tiff_value_for_contiguous_sequence!(Ifd; 4; TagType::IFD);
impl_tiff_value_for_contiguous_sequence!(Ifd8; 8; TagType::IFD8);
impl_tiff_value_for_contiguous_sequence!(Rational; 8; TagType::RATIONAL);
impl_tiff_value_for_contiguous_sequence!(SRational; 8; TagType::SRATIONAL);
#[derive(Clone)]
pub struct Ifd(pub u32);
#[derive(Clone)]
pub struct Ifd8(pub u64);
#[derive(Clone)]
pub struct Rational {
pub n: u32,
pub d: u32,
}
#[derive(Clone)]
pub struct SRational {
pub n: i32,
pub d: i32,
}