Skip to main content

harmos_domain/model/storage/
keys.rs

1/* ***
2 *
3 * Harmos
4 *
5 * SPDX-License-Identifier: Apache-2.0
6 *
7 * ***
8 */
9
10// Schema, Object And Payload Keys Shared By Storage Requests And Records.
11
12/* === Modules === */
13
14/* === Re-Exports === */
15
16/* === Imports === */
17
18// Standard Library Imports
19use std::fmt;
20use std::num::{NonZeroU32, NonZeroUsize};
21// Third Party Imports
22use serde::{Deserialize, Serialize};
23// Local Imports
24use crate::{Error, Identifier, MemorySize, Result};
25
26/* === Constants === */
27
28/* === Macros === */
29
30/* === Type Aliases === */
31
32/* === Structs === */
33
34#[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/* === Enums === */
61
62#[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
77/* === Traits === */
78
79/* === Implementations === */
80
81impl 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
155/* === Public Functions === */
156
157pub 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/* === Private Functions === */
175
176/* === Tests === */