harmos_domain/model/storage/
keys.rs1use std::fmt;
20use std::num::{NonZeroU32, NonZeroUsize};
21use serde::{Deserialize, Serialize};
23use crate::{Error, Identifier, MemorySize, Result};
25
26#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
35#[serde(deny_unknown_fields)]
36pub struct SchemaKey {
37 pub id: Identifier,
38 pub version: NonZeroU32,
39
40 pub payload_encoding: PayloadEncoding,
41}
42
43#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
44#[serde(deny_unknown_fields)]
45pub struct ObjectValue {
46 pub schema: SchemaKey,
47 pub item: ObjectKey,
48 pub payload: Vec<u8>,
49}
50
51#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize)]
52#[serde(transparent)]
53pub struct ObjectKey(String);
54
55struct KeyWriter {
56 value: String,
57 limit: usize,
58}
59
60#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
63#[serde(rename_all = "snake_case")]
64pub enum PayloadEncoding {
65 #[default]
66 PostcardV1 = 1,
67}
68
69#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
70pub enum ObjectRetention {
71 UntilReleased,
72
73 Latest,
74 Versions(NonZeroUsize),
75}
76
77impl MemorySize for SchemaKey {
82 fn memory_size(&self) -> usize {
83 std::mem::size_of::<Self>().saturating_add(self.id.memory_size().saturating_sub(std::mem::size_of::<Identifier>()))
84 }
85}
86
87impl MemorySize for ObjectValue {
88 fn memory_size(&self) -> usize {
89 std::mem::size_of::<Self>()
90 .saturating_add(self.schema.memory_size().saturating_sub(std::mem::size_of::<SchemaKey>()))
91 .saturating_add(self.item.memory_size().saturating_sub(std::mem::size_of::<ObjectKey>()))
92 .saturating_add(self.payload.capacity())
93 }
94}
95
96impl MemorySize for ObjectKey {
97 fn memory_size(&self) -> usize {
98 self.0.memory_size()
99 }
100}
101
102impl ObjectKey {
103 pub fn new<K: fmt::Display + ?Sized>(key: &K, max_bytes: NonZeroUsize) -> Result<Self> {
104 object_key(key, max_bytes)
105 }
106
107 pub fn as_str(&self) -> &str {
108 &self.0
109 }
110
111 pub fn from_owned(value: String) -> Result<Self> {
112 if value.is_empty() {
113 return Err(invalid("object key is empty"));
114 }
115
116 Ok(Self(value))
117 }
118}
119
120impl fmt::Display for ObjectKey {
121 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
122 formatter.write_str(&self.0)
123 }
124}
125
126impl<'de> Deserialize<'de> for ObjectKey {
127 fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> std::result::Result<Self, D::Error> {
128 Self::from_owned(String::deserialize(deserializer)?).map_err(serde::de::Error::custom)
129 }
130}
131
132impl fmt::Write for KeyWriter {
133 fn write_str(&mut self, value: &str) -> fmt::Result {
134 if value.len() > self.limit - self.value.len() {
135 return Err(fmt::Error);
136 }
137 let remaining = self.value.capacity() - self.value.len();
138 if value.len() > remaining {
139 self.value.reserve_exact(value.len());
140 }
141 self.value.push_str(value);
142 Ok(())
143 }
144}
145
146impl ObjectRetention {
147 pub const fn versions(self) -> NonZeroUsize {
148 match self {
149 Self::UntilReleased | Self::Latest => NonZeroUsize::MIN,
150 Self::Versions(count) => count,
151 }
152 }
153}
154
155pub fn object_key<K: fmt::Display + ?Sized>(key: &K, limit: NonZeroUsize) -> Result<ObjectKey> {
158 let mut writer = KeyWriter { value: String::new(), limit: limit.get() };
159 fmt::write(&mut writer, format_args!("{key}")).map_err(|_| invalid("invalid or oversized object key"))?;
160 ObjectKey::from_owned(writer.value)
161}
162
163pub fn check_length(length: usize, max_payload_bytes: NonZeroUsize) -> Result<()> {
164 if length > max_payload_bytes.get() {
165 return Err(invalid("object payload exceeds byte limit"));
166 }
167 Ok(())
168}
169
170pub fn invalid(reason: &'static str) -> Error {
171 Error::InvalidInput { field: "object catalog", reason }
172}
173
174