use sigstore_merkle::hash_leaf;
use sigstore_types::Sha256Hash;
use std::fmt;
#[derive(Debug, Clone)]
pub struct Entry {
data: EntryData,
leaf_hash: Sha256Hash,
}
impl Entry {
pub fn new(data: impl Into<EntryData>) -> Self {
let data = data.into();
let leaf_hash = hash_leaf(data.as_bytes());
Self { data, leaf_hash }
}
pub fn data(&self) -> &EntryData {
&self.data
}
pub fn leaf_hash(&self) -> &Sha256Hash {
&self.leaf_hash
}
pub fn into_data(self) -> EntryData {
self.data
}
}
#[derive(Clone)]
pub struct EntryData(Vec<u8>);
impl EntryData {
pub fn new(data: Vec<u8>) -> Self {
Self(data)
}
pub fn as_bytes(&self) -> &[u8] {
&self.0
}
pub fn len(&self) -> usize {
self.0.len()
}
pub fn is_empty(&self) -> bool {
self.0.is_empty()
}
pub fn into_bytes(self) -> Vec<u8> {
self.0
}
}
impl From<Vec<u8>> for EntryData {
fn from(data: Vec<u8>) -> Self {
Self::new(data)
}
}
impl From<&[u8]> for EntryData {
fn from(data: &[u8]) -> Self {
Self::new(data.to_vec())
}
}
impl From<&str> for EntryData {
fn from(s: &str) -> Self {
Self::new(s.as_bytes().to_vec())
}
}
impl From<String> for EntryData {
fn from(s: String) -> Self {
Self::new(s.into_bytes())
}
}
impl AsRef<[u8]> for EntryData {
fn as_ref(&self) -> &[u8] {
&self.0
}
}
impl fmt::Debug for EntryData {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if self.0.len() <= 64 {
write!(f, "EntryData({} bytes)", self.0.len())
} else {
write!(f, "EntryData({} bytes, truncated)", self.0.len())
}
}
}
#[derive(Debug, Clone)]
pub struct SequencedEntry {
index: LogIndex,
entry: Entry,
}
impl SequencedEntry {
pub fn new(index: LogIndex, entry: Entry) -> Self {
Self { index, entry }
}
pub fn index(&self) -> LogIndex {
self.index
}
pub fn entry(&self) -> &Entry {
&self.entry
}
pub fn leaf_hash(&self) -> &Sha256Hash {
self.entry.leaf_hash()
}
pub fn into_entry(self) -> Entry {
self.entry
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct LogIndex(u64);
impl LogIndex {
pub fn new(index: u64) -> Self {
Self(index)
}
pub fn value(&self) -> u64 {
self.0
}
pub fn bundle_index(&self) -> u64 {
self.0 / 256
}
pub fn bundle_offset(&self) -> u8 {
(self.0 % 256) as u8
}
}
impl From<u64> for LogIndex {
fn from(index: u64) -> Self {
Self::new(index)
}
}
impl From<LogIndex> for u64 {
fn from(index: LogIndex) -> Self {
index.0
}
}
impl fmt::Display for LogIndex {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.0)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
pub struct TreeSize(u64);
impl TreeSize {
pub fn new(size: u64) -> Self {
Self(size)
}
pub fn value(&self) -> u64 {
self.0
}
pub fn is_empty(&self) -> bool {
self.0 == 0
}
}
impl From<u64> for TreeSize {
fn from(size: u64) -> Self {
Self::new(size)
}
}
impl From<TreeSize> for u64 {
fn from(size: TreeSize) -> Self {
size.0
}
}
impl fmt::Display for TreeSize {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.0)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct TileLevel(u64);
impl TileLevel {
pub fn new(level: u64) -> Self {
assert!(level <= 63, "tile level must be 0-63");
Self(level)
}
pub fn value(&self) -> u64 {
self.0
}
}
impl From<u64> for TileLevel {
fn from(level: u64) -> Self {
Self::new(level)
}
}
impl fmt::Display for TileLevel {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.0)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct TileIndex(u64);
impl TileIndex {
pub fn new(index: u64) -> Self {
Self(index)
}
pub fn value(&self) -> u64 {
self.0
}
}
impl From<u64> for TileIndex {
fn from(index: u64) -> Self {
Self::new(index)
}
}
impl fmt::Display for TileIndex {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.0)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct TileId {
pub level: TileLevel,
pub index: TileIndex,
}
impl TileId {
pub fn new(level: impl Into<TileLevel>, index: impl Into<TileIndex>) -> Self {
Self {
level: level.into(),
index: index.into(),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
pub struct PartialSize(u8);
impl PartialSize {
pub fn new(size: u8) -> Self {
Self(size)
}
pub fn full() -> Self {
Self(0)
}
pub fn value(&self) -> u8 {
self.0
}
pub fn is_full(&self) -> bool {
self.0 == 0
}
}
impl From<u8> for PartialSize {
fn from(size: u8) -> Self {
Self::new(size)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_entry_creation() {
let entry = Entry::new("hello world");
assert!(!entry.data().is_empty());
assert_ne!(entry.leaf_hash().as_bytes(), &[0u8; 32]);
}
#[test]
fn test_log_index() {
let idx = LogIndex::new(512);
assert_eq!(idx.value(), 512);
assert_eq!(idx.bundle_index(), 2);
assert_eq!(idx.bundle_offset(), 0);
let idx = LogIndex::new(257);
assert_eq!(idx.bundle_index(), 1);
assert_eq!(idx.bundle_offset(), 1);
}
#[test]
fn test_tree_size() {
let size = TreeSize::new(0);
assert!(size.is_empty());
let size = TreeSize::new(100);
assert!(!size.is_empty());
assert_eq!(size.value(), 100);
}
}