use crate::refs::{RefName, Target};
use crate::{ObjectFormat, ObjectId};
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct RefRecord {
pub name: RecordName,
pub update_index: u64,
pub target: Option<Target>,
pub peeled: Option<ObjectId>,
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct LogValue {
pub old: ObjectId,
pub new: ObjectId,
pub name: Vec<u8>,
pub email: Vec<u8>,
pub seconds: u64,
pub offset_minutes: i16,
pub message: Vec<u8>,
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct LogRecord {
pub name: RecordName,
pub update_index: u64,
pub value: Option<LogValue>,
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct Table {
pub format: ObjectFormat,
pub min_update_index: u64,
pub max_update_index: u64,
pub references: Vec<RefRecord>,
pub logs: Vec<LogRecord>,
}
#[derive(Clone, Copy, Debug)]
pub struct Limits {
pub bytes: usize,
pub block_bytes: usize,
pub records: usize,
pub string_bytes: usize,
pub decoded_bytes: usize,
}
impl Default for Limits {
fn default() -> Self {
Self {
bytes: 64 * 1024 * 1024,
block_bytes: 0xff_ffff,
records: 1_000_000,
string_bytes: 1024 * 1024,
decoded_bytes: 128 * 1024 * 1024,
}
}
}
impl Limits {
pub const fn trusted() -> Self {
Self {
bytes: usize::MAX / 4,
block_bytes: 0xff_ffff,
records: usize::MAX / 4,
string_bytes: usize::MAX / 4,
decoded_bytes: usize::MAX / 4,
}
}
}
#[derive(Debug, thiserror::Error)]
pub enum Error {
#[error("malformed reftable: {0}")]
Malformed(&'static str),
#[error("unsupported reftable: {0}")]
Unsupported(&'static str),
#[error("reftable resource limit: {0}")]
Limit(&'static str),
}
#[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd)]
pub struct RecordName(Vec<u8>);
impl RecordName {
pub fn new(bytes: impl AsRef<[u8]>) -> Result<Self, Error> {
let bytes = bytes.as_ref();
if RefName::new(bytes).is_err()
&& (bytes.is_empty() || !bytes.iter().all(|b| b.is_ascii_uppercase() || *b == b'_'))
{
return Err(Error::Malformed("table record name"));
}
Ok(Self(bytes.to_vec()))
}
pub fn as_bytes(&self) -> &[u8] {
&self.0
}
pub fn reference_name(&self) -> Option<RefName> {
RefName::new(&self.0).ok()
}
}
impl From<RefName> for RecordName {
fn from(name: RefName) -> Self {
Self(name.as_bytes().to_vec())
}
}
impl PartialEq<RefName> for RecordName {
fn eq(&self, other: &RefName) -> bool {
self.as_bytes() == other.as_bytes()
}
}