use arkhe_kernel::abi::{EntityId, Tick};
use serde::{Deserialize, Serialize};
use crate::actor::ActorId;
use crate::brand::ShellId;
use crate::component::BoundedString;
use crate::pii::{AeadKind, DekId};
use crate::space::SpaceId;
use crate::ArkheComponent;
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Serialize, Deserialize)]
#[serde(transparent)]
pub struct EntryId(EntityId);
impl EntryId {
#[inline]
#[must_use]
pub fn new(id: EntityId) -> Self {
Self(id)
}
#[inline]
#[must_use]
pub fn get(self) -> EntityId {
self.0
}
}
#[non_exhaustive]
#[repr(u8)]
#[derive(Debug, Clone, Copy, Eq, PartialEq, Serialize, Deserialize)]
pub enum RelayKind {
Plain = 0,
Quote = 1,
}
#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize, ArkheComponent)]
#[arkhe(type_code = 0x0003_0301, schema_version = 1)]
pub struct EntryCore {
pub schema_version: u16,
pub shell_id: ShellId,
pub space_id: SpaceId,
pub author_id: ActorId,
pub parent_entry: Option<EntryId>,
pub relay_of: Option<EntryId>,
pub relay_kind: Option<RelayKind>,
pub created_tick: Tick,
}
#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize, ArkheComponent)]
#[arkhe(type_code = 0x0003_0302, schema_version = 1)]
pub struct EntryBody {
pub schema_version: u16,
pub title: Option<BoundedString<256>>,
pub body_hash: [u8; 32],
pub body_cipher_meta: Option<BodyCipherMeta>,
pub edit_seq: u32,
}
#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)]
pub struct BodyCipherMeta {
pub dek_id: DekId,
pub aead_kind: AeadKind,
pub nonce: [u8; 24],
}
#[derive(Debug, Clone, Copy, Eq, PartialEq, Serialize, Deserialize, ArkheComponent)]
#[arkhe(type_code = 0x0003_0303, schema_version = 1)]
pub struct EntryParentDepth {
pub schema_version: u16,
pub depth: u8,
}
pub const MAX_ENTRY_DEPTH: u8 = 64;
#[cfg(test)]
#[allow(clippy::unwrap_used, clippy::expect_used)]
mod tests {
use super::*;
use crate::component::ArkheComponent;
fn ent(v: u64) -> EntityId {
EntityId::new(v).unwrap()
}
#[test]
fn entry_core_serde_roundtrip_postcard() {
let ec = EntryCore {
schema_version: 1,
shell_id: ShellId([0u8; 16]),
space_id: SpaceId::new(ent(1)),
author_id: ActorId::new(ent(2)),
parent_entry: None,
relay_of: None,
relay_kind: None,
created_tick: Tick(10),
};
let bytes = postcard::to_stdvec(&ec).unwrap();
let back: EntryCore = postcard::from_bytes(&bytes).unwrap();
assert_eq!(ec, back);
}
#[test]
fn entry_body_serde_roundtrip_with_cipher_meta() {
let body = EntryBody {
schema_version: 1,
title: Some(BoundedString::<256>::new("hello").unwrap()),
body_hash: [0xABu8; 32],
body_cipher_meta: Some(BodyCipherMeta {
dek_id: DekId([0x11u8; 16]),
aead_kind: AeadKind::XChaCha20Poly1305,
nonce: [0x22u8; 24],
}),
edit_seq: 1,
};
let bytes = postcard::to_stdvec(&body).unwrap();
let back: EntryBody = postcard::from_bytes(&bytes).unwrap();
assert_eq!(body, back);
}
#[test]
fn entry_component_type_codes() {
assert_eq!(EntryCore::TYPE_CODE, 0x0003_0301);
assert_eq!(EntryBody::TYPE_CODE, 0x0003_0302);
assert_eq!(EntryParentDepth::TYPE_CODE, 0x0003_0303);
}
#[test]
fn max_entry_depth_is_sixty_four() {
assert_eq!(MAX_ENTRY_DEPTH, 64);
}
}