venus_core/state/
output.rs1use std::any::TypeId;
16use std::collections::hash_map::DefaultHasher;
17use std::hash::{Hash, Hasher};
18
19use rkyv::{Archive, Deserialize, Serialize};
20
21use crate::error::{Error, Result};
22
23pub trait CellOutput: Send + Sync + 'static {
28 fn serialize_output(&self) -> Result<Vec<u8>>;
30
31 fn type_hash(&self) -> u64;
33
34 fn type_name(&self) -> &'static str;
36}
37
38impl<T> CellOutput for T
40where
41 T: for<'a> Serialize<rkyv::rancor::Strategy<
42 rkyv::ser::Serializer<
43 rkyv::util::AlignedVec,
44 rkyv::ser::allocator::ArenaHandle<'a>,
45 rkyv::ser::sharing::Share,
46 >,
47 rkyv::rancor::Error,
48 >> + Send
49 + Sync
50 + 'static,
51{
52 fn serialize_output(&self) -> Result<Vec<u8>> {
53 rkyv::to_bytes::<rkyv::rancor::Error>(self)
54 .map(|v| v.into_vec())
55 .map_err(|e| Error::Serialization(e.to_string()))
56 }
57
58 fn type_hash(&self) -> u64 {
59 let mut hasher = DefaultHasher::new();
64 TypeId::of::<T>().hash(&mut hasher);
65 hasher.finish()
66 }
67
68 fn type_name(&self) -> &'static str {
69 std::any::type_name::<T>()
70 }
71}
72
73pub fn deserialize_output<T>(bytes: &[u8]) -> Result<T>
80where
81 T: Archive,
82 T::Archived: Deserialize<T, rkyv::rancor::Strategy<rkyv::de::Pool, rkyv::rancor::Error>>,
83{
84 unsafe { rkyv::from_bytes_unchecked::<T, rkyv::rancor::Error>(bytes) }
87 .map_err(|e: rkyv::rancor::Error| Error::Deserialization(e.to_string()))
88}
89
90pub trait ZeroCopyOutput: CellOutput {}
96
97#[derive(Debug, Clone, Archive, Serialize, Deserialize)]
99pub struct BoxedOutput {
100 bytes: Vec<u8>,
102
103 type_hash: u64,
105
106 type_name: String,
108
109 display_text: Option<String>,
111}
112
113impl BoxedOutput {
114 pub fn new<T: CellOutput>(value: &T) -> Result<Self> {
116 Ok(Self {
117 bytes: value.serialize_output()?,
118 type_hash: value.type_hash(),
119 type_name: value.type_name().to_string(),
120 display_text: None,
121 })
122 }
123
124 pub fn from_raw_bytes(bytes: Vec<u8>) -> Self {
133 Self {
134 bytes,
135 type_hash: 0, type_name: "<ffi>".to_string(),
137 display_text: None,
138 }
139 }
140
141 pub fn from_raw_bytes_with_display(bytes: Vec<u8>, display: String) -> Self {
146 Self {
147 bytes,
148 type_hash: 0, type_name: "<ffi>".to_string(),
150 display_text: Some(display),
151 }
152 }
153
154 pub fn from_raw_with_type(bytes: Vec<u8>, type_hash: u64, type_name: String) -> Self {
159 Self {
160 bytes,
161 type_hash,
162 type_name,
163 display_text: None,
164 }
165 }
166
167 pub fn bytes(&self) -> &[u8] {
169 &self.bytes
170 }
171
172 pub fn type_hash(&self) -> u64 {
174 self.type_hash
175 }
176
177 pub fn type_name(&self) -> &str {
179 &self.type_name
180 }
181
182 pub fn display_text(&self) -> Option<&str> {
184 self.display_text.as_deref()
185 }
186
187 pub fn deserialize<T>(&self) -> Result<T>
191 where
192 T: CellOutput + Archive,
193 T::Archived: Deserialize<T, rkyv::rancor::Strategy<rkyv::de::Pool, rkyv::rancor::Error>>,
194 {
195 let expected_hash = {
197 let mut hasher = DefaultHasher::new();
198 std::any::TypeId::of::<T>().hash(&mut hasher);
199 hasher.finish()
200 };
201
202 if self.type_hash != expected_hash {
203 return Err(Error::SchemaEvolution(format!(
204 "Type mismatch: stored {} (hash {:x}), requested {} (hash {:x})",
205 self.type_name,
206 self.type_hash,
207 std::any::type_name::<T>(),
208 expected_hash
209 )));
210 }
211
212 deserialize_output(&self.bytes)
213 }
214}
215
216#[cfg(test)]
217mod tests {
218 use super::*;
219
220 #[derive(Debug, Clone, PartialEq, Archive, Serialize, Deserialize)]
221 struct TestOutput {
222 value: i32,
223 name: String,
224 }
225
226 #[test]
227 fn test_cell_output_serialize() {
228 let output = TestOutput {
229 value: 42,
230 name: "test".to_string(),
231 };
232
233 let bytes = output.serialize_output().unwrap();
234 assert!(!bytes.is_empty());
235
236 let restored: TestOutput = deserialize_output(&bytes).unwrap();
237 assert_eq!(output, restored);
238 }
239
240 #[test]
241 fn test_type_hash_consistency() {
242 let output1 = TestOutput {
243 value: 1,
244 name: "a".to_string(),
245 };
246 let output2 = TestOutput {
247 value: 2,
248 name: "b".to_string(),
249 };
250
251 assert_eq!(output1.type_hash(), output2.type_hash());
253
254 let other: i32 = 42;
256 assert_ne!(output1.type_hash(), other.type_hash());
257 }
258
259 #[test]
260 fn test_boxed_output() {
261 let output = TestOutput {
262 value: 42,
263 name: "test".to_string(),
264 };
265
266 let boxed = BoxedOutput::new(&output).unwrap();
267 assert!(boxed.type_name().contains("TestOutput"));
268
269 let restored: TestOutput = boxed.deserialize().unwrap();
270 assert_eq!(output, restored);
271 }
272
273 #[test]
274 fn test_boxed_output_type_mismatch() {
275 let output = TestOutput {
276 value: 42,
277 name: "test".to_string(),
278 };
279
280 let boxed = BoxedOutput::new(&output).unwrap();
281
282 let result: Result<i32> = boxed.deserialize();
284 assert!(result.is_err());
285 assert!(result.unwrap_err().to_string().contains("Type mismatch"));
286 }
287
288 #[test]
289 fn test_primitive_outputs() {
290 let int_val: i64 = 12345;
292 let bytes = int_val.serialize_output().unwrap();
293 let restored: i64 = deserialize_output(&bytes).unwrap();
294 assert_eq!(int_val, restored);
295
296 let string_val = "hello world".to_string();
297 let bytes = string_val.serialize_output().unwrap();
298 let restored: String = deserialize_output(&bytes).unwrap();
299 assert_eq!(string_val, restored);
300
301 let vec_val = vec![1, 2, 3, 4, 5];
302 let bytes = vec_val.serialize_output().unwrap();
303 let restored: Vec<i32> = deserialize_output(&bytes).unwrap();
304 assert_eq!(vec_val, restored);
305 }
306}