Skip to main content

midnight_serialize/
serializable.rs

1// This file is part of midnight-ledger.
2// Copyright (C) 2025 Midnight Foundation
3// SPDX-License-Identifier: Apache-2.0
4// Licensed under the Apache License, Version 2.0 (the "License");
5// You may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7// http://www.apache.org/licenses/LICENSE-2.0
8// Unless required by applicable law or agreed to in writing, software
9// distributed under the License is distributed on an "AS IS" BASIS,
10// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11// See the License for the specific language governing permissions and
12// limitations under the License.
13
14use crate::tagged::Tagged;
15use std::{
16    borrow::{Borrow, Cow},
17    collections::{HashMap, HashSet},
18    io::Write,
19    marker::PhantomData,
20    sync::Arc,
21};
22
23pub const GLOBAL_TAG: &str = "midnight:";
24
25// Top-level serialization function
26pub fn tagged_serialize<T: Serializable + Tagged>(
27    value: &T,
28    mut writer: impl Write,
29) -> std::io::Result<()> {
30    let tag = T::tag();
31    write!(&mut writer, "{GLOBAL_TAG}{tag}:")?;
32    value.serialize(&mut writer)
33}
34
35pub fn tagged_serialized_size<T: Serializable + Tagged>(value: &T) -> usize {
36    T::tag().len() + GLOBAL_TAG.len() + 1 + T::serialized_size(value)
37}
38
39/// Binary serialization with embedded versioning.
40///
41/// See [`crate::Deserializable`] for the deserialization counterpart.
42pub trait Serializable {
43    fn serialize(&self, writer: &mut impl Write) -> std::io::Result<()>;
44    fn serialized_size(&self) -> usize;
45}
46
47impl<T: Serializable> Serializable for Vec<T> {
48    fn serialize(&self, writer: &mut impl Write) -> std::io::Result<()> {
49        (self.len() as u32).serialize(writer)?;
50        for elem in self {
51            elem.serialize(writer)?;
52        }
53        Ok(())
54    }
55    fn serialized_size(&self) -> usize {
56        self.iter()
57            .fold((self.len() as u64).serialized_size(), |acc, x| {
58                acc + x.serialized_size()
59            })
60    }
61}
62
63impl<K: Serializable + Ord, V: Serializable> Serializable for HashMap<K, V> {
64    fn serialize(&self, writer: &mut impl Write) -> std::io::Result<()> {
65        (self.len() as u32).serialize(writer)?;
66        let mut kvs = self.iter().collect::<Vec<_>>();
67        kvs.sort_by(|(k1, _), (k2, _)| k1.cmp(k2));
68        for (k, v) in kvs.into_iter() {
69            k.serialize(writer)?;
70            v.serialize(writer)?;
71        }
72        Ok(())
73    }
74
75    fn serialized_size(&self) -> usize {
76        self.iter().fold(4, |acc, (k, v)| {
77            acc + k.serialized_size() + v.serialized_size()
78        })
79    }
80}
81
82impl<T: Serializable + Ord> Serializable for HashSet<T> {
83    fn serialize(&self, writer: &mut impl Write) -> std::io::Result<()> {
84        (self.len() as u32).serialize(writer)?;
85        let mut elems = self.iter().collect::<Vec<_>>();
86        elems.sort();
87        for elem in elems.into_iter() {
88            elem.serialize(writer)?;
89        }
90
91        Ok(())
92    }
93
94    fn serialized_size(&self) -> usize {
95        self.iter()
96            .fold(4, |acc, elem| acc + elem.serialized_size())
97    }
98}
99
100impl<'a, T> Serializable for &'a T
101where
102    T: Serializable + 'a,
103    Self: Borrow<T>,
104{
105    fn serialize(&self, writer: &mut impl Write) -> std::io::Result<()> {
106        T::serialize(self, writer)
107    }
108
109    fn serialized_size(&self) -> usize {
110        T::serialized_size(self)
111    }
112}
113
114impl<T: Serializable> Serializable for Option<T> {
115    fn serialize(&self, writer: &mut impl Write) -> std::io::Result<()> {
116        match self {
117            Some(v) => {
118                1u8.serialize(writer)?;
119                v.serialize(writer)?;
120                Ok(())
121            }
122            None => {
123                0u8.serialize(writer)?;
124                Ok(())
125            }
126        }
127    }
128
129    fn serialized_size(&self) -> usize {
130        match self {
131            Some(v) => 1 + v.serialized_size(),
132            None => 1,
133        }
134    }
135}
136
137impl Serializable for str {
138    fn serialize(&self, writer: &mut impl Write) -> std::io::Result<()> {
139        (self.len() as u64).serialize(writer)?;
140        writer.write_all(self.as_bytes())
141    }
142
143    fn serialized_size(&self) -> usize {
144        let len = self.len();
145        (len as u64).serialized_size() + len
146    }
147}
148
149impl Serializable for String {
150    fn serialize(&self, writer: &mut impl Write) -> std::io::Result<()> {
151        str::serialize(self, writer)
152    }
153
154    fn serialized_size(&self) -> usize {
155        str::serialized_size(self)
156    }
157}
158
159impl Serializable for &str {
160    fn serialize(&self, writer: &mut impl Write) -> std::io::Result<()> {
161        str::serialize(self, writer)
162    }
163
164    fn serialized_size(&self) -> usize {
165        str::serialized_size(self)
166    }
167}
168
169impl<const N: usize> Serializable for [u8; N] {
170    fn serialize(&self, writer: &mut impl Write) -> std::io::Result<()> {
171        writer.write_all(&self[..])
172    }
173    fn serialized_size(&self) -> usize {
174        N
175    }
176}
177
178impl<T: ?Sized> Serializable for PhantomData<T> {
179    fn serialize(&self, _writer: &mut impl Write) -> std::io::Result<()> {
180        Ok(())
181    }
182    fn serialized_size(&self) -> usize {
183        0
184    }
185}
186
187impl<T: ?Sized> Tagged for PhantomData<T> {
188    fn tag() -> Cow<'static, str> {
189        Cow::Borrowed("()")
190    }
191    fn tag_unique_factor() -> String {
192        "()".into()
193    }
194}
195
196impl<T: Serializable> Serializable for Box<T> {
197    fn serialize(&self, writer: &mut impl Write) -> std::io::Result<()> {
198        T::serialize(self, writer)
199    }
200    fn serialized_size(&self) -> usize {
201        T::serialized_size(self)
202    }
203}
204
205impl<T: Serializable> Serializable for Arc<T> {
206    fn serialize(&self, writer: &mut impl Write) -> std::io::Result<()> {
207        T::serialize(self, writer)
208    }
209    fn serialized_size(&self) -> usize {
210        T::serialized_size(self)
211    }
212}
213
214impl<'a, T: ToOwned + ?Sized> Serializable for Cow<'a, T>
215where
216    T: Serializable,
217{
218    fn serialize(&self, writer: &mut impl Write) -> std::io::Result<()> {
219        T::serialize(self, writer)
220    }
221    fn serialized_size(&self) -> usize {
222        T::serialized_size(self)
223    }
224}
225
226impl<'a, T: ToOwned + ?Sized + Tagged> Tagged for Cow<'a, T> {
227    fn tag() -> Cow<'static, str> {
228        T::tag()
229    }
230    fn tag_unique_factor() -> String {
231        T::tag_unique_factor()
232    }
233}