use std::{fmt, io::Read, sync::Arc};
use super::{error::*, flags::Flags};
#[cfg(feature = "crypto")]
use crate::crypto;
#[derive(Debug, Clone)]
pub struct RegistryEntry {
pub id: Arc<str>,
pub flags: Flags,
pub content_version: u8,
pub location: u64,
pub offset: u64,
#[cfg(feature = "crypto")]
#[cfg_attr(docsrs, doc(cfg(feature = "crypto")))]
pub signature: Option<crypto::Signature>,
}
impl RegistryEntry {
pub(crate) const MIN_SIZE: usize = Flags::BYTES + 19;
#[inline(always)]
pub(crate) fn empty() -> RegistryEntry {
RegistryEntry {
id: Arc::from("None"),
flags: Flags::new(),
content_version: 0,
location: 0,
offset: 0,
#[cfg(feature = "crypto")]
signature: None,
}
}
pub(crate) fn from_handle<T: Read>(mut handle: T) -> InternalResult<RegistryEntry> {
let mut buffer: [u8; RegistryEntry::MIN_SIZE] = [0u8; RegistryEntry::MIN_SIZE];
handle.read_exact(&mut buffer)?;
let flags = Flags::from_bits(u32::from_le_bytes(buffer[0..4].try_into().unwrap()));
let content_version = buffer[4];
let location = u64::from_le_bytes(buffer[5..13].try_into().unwrap());
let offset = u64::from_le_bytes(buffer[13..21].try_into().unwrap());
let id_length = u16::from_le_bytes([buffer[21], buffer[22]]);
#[cfg(feature = "crypto")]
let mut signature = None;
if flags.contains(Flags::SIGNED_FLAG) {
let mut sig_bytes: [u8; crate::SIGNATURE_LENGTH] = [0u8; crate::SIGNATURE_LENGTH];
handle.read_exact(&mut sig_bytes)?;
#[cfg(feature = "crypto")]
{
signature = Some(crypto::Signature::from(sig_bytes));
}
};
let mut id = String::with_capacity(id_length as usize);
handle.take(id_length as u64).read_to_string(&mut id)?;
let entry = RegistryEntry {
id: id.into(),
flags,
content_version,
location,
offset,
#[cfg(feature = "crypto")]
signature,
};
Ok(entry)
}
pub(crate) fn to_bytes(&self, _skip_signature: bool) -> InternalResult<Vec<u8>> {
let id = self.id.as_ref();
if id.len() >= crate::MAX_ID_LENGTH {
let copy = id.to_string();
return Err(InternalError::IDSizeOverflowError(copy));
};
let mut buffer = Vec::with_capacity(RegistryEntry::MIN_SIZE + id.len());
let len = id.len() as u16;
buffer.extend_from_slice(&self.flags.bits().to_le_bytes());
buffer.extend_from_slice(&self.content_version.to_le_bytes());
buffer.extend_from_slice(&self.location.to_le_bytes());
buffer.extend_from_slice(&self.offset.to_le_bytes());
buffer.extend_from_slice(&len.to_le_bytes());
#[cfg(feature = "crypto")]
if let Some(signature) = self.signature {
if !_skip_signature {
buffer.extend_from_slice(&signature.to_bytes())
}
};
buffer.extend_from_slice(id.as_bytes());
Ok(buffer)
}
}
impl Default for RegistryEntry {
#[inline(always)]
fn default() -> RegistryEntry {
RegistryEntry::empty()
}
}
impl fmt::Display for RegistryEntry {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"[RegistryEntry] location: {}, length: {}, content_version: {}, flags: {}",
self.location,
self.offset,
self.content_version,
self.flags.bits()
)
}
}