harmos_domain/metadata/
codec.rs1use std::borrow::Cow;
18use super::{Identifier, Metadata};
22use crate::MessageError;
23use crate::message::{PostcardReader as Reader, PostcardValue, decoding_add};
24use crate::schema::declaration::{Definition, Field, Kind};
25use crate::schema::{Cardinality, Described};
26use crate::value::codec::{
27 ENTRY_DEFINITION, TIMESTAMP_DEFINITION, VALUE_DEPTH, entries_memory, entries_size, read_entries, read_timestamp, timestamp_size,
28 write_entries, write_timestamp,
29};
30
31const IDENTIFIER_FIELDS: &[Field] =
34 &[Field { name: Cow::Borrowed("value"), tag: 1, kind: Kind::String, cardinality: Cardinality::Required }];
35
36const METADATA_FIELDS: &[Field] = &[
37 field("identifier", 1, Kind::String, Cardinality::Required),
38 field("label", 2, Kind::String, Cardinality::Required),
39 field("description", 3, Kind::String, Cardinality::Optional),
40 field("tags", 4, Kind::String, Cardinality::Repeated),
41 field("attributes", 5, message(ENTRY_DEFINITION), Cardinality::Repeated),
42 field("created_at", 6, message(TIMESTAMP_DEFINITION), Cardinality::Optional),
43 field("updated_at", 7, message(TIMESTAMP_DEFINITION), Cardinality::Optional),
44];
45
46impl Described for Identifier {
59 const NAME: &'static str = "harmos::Identifier";
60 const FIELDS: &'static [Field] = IDENTIFIER_FIELDS;
61 const MARKER: &'static [u8] = &crate::schema::declaration::encode::<
62 { crate::schema::declaration::encoded_len(Self::NAME, Self::FIELDS) },
63 >(Self::NAME, Self::FIELDS);
64}
65
66impl Described for Metadata {
67 const NAME: &'static str = "harmos::Metadata";
68 const FIELDS: &'static [Field] = METADATA_FIELDS;
69 const MARKER: &'static [u8] = &crate::schema::declaration::encode::<
70 { crate::schema::declaration::encoded_len(Self::NAME, Self::FIELDS) },
71 >(Self::NAME, Self::FIELDS);
72}
73
74impl PostcardValue for Metadata {
75 fn write(&self, bytes: &mut Vec<u8>) {
76 self.identifier.write(bytes);
77 self.label.write(bytes);
78 self.description.write(bytes);
79 self.tags.write(bytes);
80 write_entries(&self.attributes, bytes);
81 write_instant(self.created_at, bytes);
82 write_instant(self.updated_at, bytes);
83 }
84
85 fn size(&self) -> usize {
86 self.identifier
87 .size()
88 .saturating_add(self.label.size())
89 .saturating_add(self.description.size())
90 .saturating_add(self.tags.size())
91 .saturating_add(entries_size(&self.attributes))
92 .saturating_add(instant_size(self.created_at))
93 .saturating_add(instant_size(self.updated_at))
94 }
95
96 fn memory(input: &mut Reader<'_>) -> Result<usize, MessageError> {
97 input.nested(|input| {
98 let mut owned = std::mem::size_of::<Self>();
99 for allocation in [
100 Identifier::memory(input)?.saturating_sub(std::mem::size_of::<Identifier>()),
101 String::memory(input)?.saturating_sub(std::mem::size_of::<String>()),
102 Option::<String>::memory(input)?.saturating_sub(std::mem::size_of::<Option<String>>()),
103 Vec::<String>::memory(input)?.saturating_sub(std::mem::size_of::<Vec<String>>()),
104 entries_memory(input, VALUE_DEPTH)?,
105 ] {
106 owned = decoding_add(owned, allocation)?;
107 }
108 read_instant(input)?;
109 read_instant(input)?;
110 Ok(owned)
111 })
112 }
113
114 fn read(input: &mut Reader<'_>) -> Result<Self, MessageError> {
115 input.nested(|input| {
116 let identifier = Identifier::read(input)?;
117 let label = String::read(input)?;
118 let description = Option::<String>::read(input)?;
119 let tags = Vec::<String>::read(input)?;
120 let attributes = read_entries(input, VALUE_DEPTH)?;
121 let created_at = read_instant(input)?;
122 let updated_at = read_instant(input)?;
123 let mut metadata = Self::definition(identifier, label, description, tags);
124 metadata.tags.shrink_to_fit();
125 metadata.attributes = attributes;
126 metadata.created_at = created_at;
127 metadata.updated_at = updated_at;
128 Ok(metadata)
129 })
130 }
131}
132
133const fn field(name: &'static str, tag: u32, kind: Kind, cardinality: Cardinality) -> Field {
138 Field { name: Cow::Borrowed(name), tag, kind, cardinality }
139}
140
141const fn message(definition: Definition) -> Kind {
142 Kind::Message { definition }
143}
144
145fn write_instant(value: Option<time::OffsetDateTime>, bytes: &mut Vec<u8>) {
146 value.is_some().write(bytes);
147 if let Some(value) = value {
148 write_timestamp(value, bytes);
149 }
150}
151
152fn instant_size(value: Option<time::OffsetDateTime>) -> usize {
153 1usize.saturating_add(value.map_or(0, timestamp_size))
154}
155
156fn read_instant(input: &mut Reader<'_>) -> Result<Option<time::OffsetDateTime>, MessageError> {
157 if bool::read(input)? { read_timestamp(input).map(Some) } else { Ok(None) }
158}
159
160