snarkvm_utilities/serialize/traits.rs
1// Copyright 2024 Aleo Network Foundation
2// This file is part of the snarkVM library.
3
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
8// http://www.apache.org/licenses/LICENSE-2.0
9
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15
16use crate::SerializationError;
17pub use crate::io::{Read, Write};
18
19use serde::de::{self, DeserializeOwned, Deserializer};
20
21/// Represents metadata to be appended to an object's serialization. For
22/// example, when serializing elliptic curve points, one can
23/// use a `Flag` to represent whether the serialization is the point
24/// at infinity, or whether the `y` coordinate is positive or not.
25/// These bits will be appended to the end of the point's serialization,
26/// or included in a new byte, depending on space available.
27///
28/// This is meant to be provided to `CanonicalSerializeWithFlags` and
29/// `CanonicalDeserializeWithFlags`
30pub trait Flags: Default + Clone + Copy + Sized {
31 /// The number of bits required to encode `Self`.
32 /// This should be at most 8.
33 const BIT_SIZE: usize;
34
35 // Returns a bit mask corresponding to `self`.
36 // For example, if `Self` contains two variants, there are just two possible
37 // bit masks: `0` and `1 << 7`.
38 fn u8_bitmask(&self) -> u8;
39
40 // Tries to read `Self` from `value`. Should return `None` if the `Self::BIT_SIZE`
41 // most-significant bits of `value` do not correspond to those generated by
42 // `u8_bitmask`.
43 //
44 // That is, this method ignores all but the top `Self::BIT_SIZE` bits, and
45 // decides whether these top bits correspond to a bitmask output by `u8_bitmask`.
46 fn from_u8(value: u8) -> Option<Self>;
47
48 // Convenience method that reads `Self` from `value`, just like `Self::from_u8`, but
49 // additionally zeroes out the bits corresponding to the resulting flag in `value`.
50 // If `Self::from_u8(*value)` would return `None`, then this method should
51 // *not* modify `value`.
52 fn from_u8_remove_flags(value: &mut u8) -> Option<Self> {
53 let flags = Self::from_u8(*value);
54 if let Some(f) = flags {
55 *value &= !f.u8_bitmask();
56 }
57 flags
58 }
59}
60
61#[derive(Copy, Clone, PartialEq, Eq)]
62pub enum Compress {
63 Yes,
64 No,
65}
66
67#[derive(Copy, Clone, PartialEq, Eq)]
68pub enum Validate {
69 Yes,
70 No,
71}
72
73pub trait Valid: Sized + Sync {
74 fn check(&self) -> Result<(), SerializationError>;
75
76 fn batch_check<'a>(batch: impl Iterator<Item = &'a Self> + Send) -> Result<(), SerializationError>
77 where
78 Self: 'a,
79 {
80 #[cfg(not(feature = "serial"))]
81 {
82 use rayon::{iter::ParallelBridge, prelude::ParallelIterator};
83 batch.par_bridge().try_for_each(|e| e.check())?;
84 }
85 #[cfg(feature = "serial")]
86 {
87 for item in batch {
88 item.check()?;
89 }
90 }
91 Ok(())
92 }
93}
94
95/// Serializer in little endian format.
96/// This trait can be derived if all fields of a struct implement
97/// `CanonicalSerialize` and the `derive` feature is enabled.
98///
99/// # Example
100/// ```
101/// // The `derive` feature must be set for the derivation to work.
102/// use snarkvm_utilities::serialize::*;
103///
104/// # #[cfg(feature = "derive")]
105/// #[derive(CanonicalSerialize)]
106/// struct TestStruct {
107/// a: u64,
108/// b: (u64, (u64, u64)),
109/// }
110/// ```
111pub trait CanonicalSerialize {
112 fn serialize_with_mode<W: Write>(&self, writer: W, compress: Compress) -> Result<(), SerializationError>;
113
114 fn serialized_size(&self, compress: Compress) -> usize;
115
116 fn serialize_compressed<W: Write>(&self, writer: W) -> Result<(), SerializationError> {
117 self.serialize_with_mode(writer, Compress::Yes)
118 }
119
120 fn compressed_size(&self) -> usize {
121 self.serialized_size(Compress::Yes)
122 }
123
124 fn serialize_uncompressed<W: Write>(&self, writer: W) -> Result<(), SerializationError> {
125 self.serialize_with_mode(writer, Compress::No)
126 }
127
128 fn uncompressed_size(&self) -> usize {
129 self.serialized_size(Compress::No)
130 }
131}
132
133/// Deserializer in little endian format.
134/// This trait can be derived if all fields of a struct implement
135/// `CanonicalDeserialize` and the `derive` feature is enabled.
136///
137/// # Example
138/// ```
139/// // The `derive` feature must be set for the derivation to work.
140/// use snarkvm_utilities::serialize::*;
141///
142/// # #[cfg(feature = "derive")]
143/// #[derive(CanonicalDeserialize)]
144/// struct TestStruct {
145/// a: u64,
146/// b: (u64, (u64, u64)),
147/// }
148/// ```
149pub trait CanonicalDeserialize: Valid {
150 fn deserialize_with_mode<R: Read>(
151 reader: R,
152 compress: Compress,
153 validate: Validate,
154 ) -> Result<Self, SerializationError>;
155
156 fn deserialize_compressed<R: Read>(reader: R) -> Result<Self, SerializationError> {
157 Self::deserialize_with_mode(reader, Compress::Yes, Validate::Yes)
158 }
159
160 fn deserialize_compressed_unchecked<R: Read>(reader: R) -> Result<Self, SerializationError> {
161 Self::deserialize_with_mode(reader, Compress::Yes, Validate::No)
162 }
163
164 fn deserialize_uncompressed<R: Read>(reader: R) -> Result<Self, SerializationError> {
165 Self::deserialize_with_mode(reader, Compress::No, Validate::Yes)
166 }
167
168 fn deserialize_uncompressed_unchecked<R: Read>(reader: R) -> Result<Self, SerializationError> {
169 Self::deserialize_with_mode(reader, Compress::No, Validate::No)
170 }
171}
172
173/// Serializer in little endian format allowing to encode flags.
174pub trait CanonicalSerializeWithFlags: CanonicalSerialize {
175 /// Serializes `self` and `flags` into `writer`.
176 fn serialize_with_flags<W: Write, F: Flags>(&self, writer: W, flags: F) -> Result<(), SerializationError>;
177
178 /// Serializes `self` and `flags` into `writer`.
179 fn serialized_size_with_flags<F: Flags>(&self) -> usize;
180}
181
182/// Deserializer in little endian format allowing flags to be encoded.
183pub trait CanonicalDeserializeWithFlags: Sized {
184 /// Reads `Self` and `Flags` from `reader`.
185 /// Returns empty flags by default.
186 fn deserialize_with_flags<R: Read, F: Flags>(reader: R) -> Result<(Self, F), SerializationError>;
187}
188
189/// A helper trait used to simplify value extraction.
190pub trait DeserializeExt<'de>
191where
192 Self: DeserializeOwned,
193{
194 fn take_from_value<D: Deserializer<'de>>(value: &mut serde_json::Value, field: &str) -> Result<Self, D::Error>;
195}
196
197impl<'de, T> DeserializeExt<'de> for T
198where
199 T: DeserializeOwned,
200{
201 fn take_from_value<D: Deserializer<'de>>(value: &mut serde_json::Value, field: &str) -> Result<Self, D::Error> {
202 serde_json::from_value(
203 value.get_mut(field).ok_or_else(|| de::Error::custom(format!("The \"{field}\" field is missing")))?.take(),
204 )
205 .map_err(de::Error::custom)
206 }
207}