use crate::errors::{ParquetError, Result};
use crate::file::{FOOTER_SIZE, PARQUET_MAGIC, PARQUET_MAGIC_ENCR_FOOTER};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct FooterTail {
metadata_length: usize,
encrypted_footer: bool,
}
impl FooterTail {
pub fn try_new(slice: &[u8; FOOTER_SIZE]) -> Result<FooterTail> {
let magic = &slice[4..];
let encrypted_footer = if magic == PARQUET_MAGIC_ENCR_FOOTER {
true
} else if magic == PARQUET_MAGIC {
false
} else {
return Err(general_err!("Invalid Parquet file. Corrupt footer"));
};
let metadata_len = u32::from_le_bytes(slice[..4].try_into().unwrap());
Ok(FooterTail {
metadata_length: metadata_len.try_into()?,
encrypted_footer,
})
}
pub fn metadata_length(&self) -> usize {
self.metadata_length
}
pub fn is_encrypted_footer(&self) -> bool {
self.encrypted_footer
}
}
impl TryFrom<[u8; FOOTER_SIZE]> for FooterTail {
type Error = ParquetError;
fn try_from(value: [u8; FOOTER_SIZE]) -> Result<Self> {
Self::try_new(&value)
}
}
impl TryFrom<&[u8]> for FooterTail {
type Error = ParquetError;
fn try_from(value: &[u8]) -> Result<Self> {
if value.len() != FOOTER_SIZE {
return Err(general_err!(
"Invalid footer length {}, expected {FOOTER_SIZE}",
value.len()
));
}
let slice: &[u8; FOOTER_SIZE] = value.try_into().unwrap();
Self::try_new(slice)
}
}