1use crate::buffer::{Reader, Writer};
19use crate::config::Config;
20use std::collections::HashMap;
21use std::mem;
22
23use crate::error::Error;
24use crate::meta::MetaString;
25use crate::resolver::meta_resolver::{MetaReaderResolver, MetaWriterResolver};
26use crate::resolver::meta_string_resolver::{MetaStringReaderResolver, MetaStringWriterResolver};
27use crate::resolver::{RefReader, RefWriter};
28use crate::resolver::{TypeInfo, TypeResolver};
29use crate::serializer::StructSerializer;
30use crate::type_id as types;
31use crate::TypeId;
32use std::rc::Rc;
33
34pub struct ContextCache<T> {
38 cached_id: u64,
40 cached_context: Option<Box<T>>,
41 others: HashMap<u64, Box<T>>,
43}
44
45impl<T> ContextCache<T> {
46 pub fn new() -> Self {
47 ContextCache {
48 cached_id: u64::MAX,
49 cached_context: None,
50 others: HashMap::new(),
51 }
52 }
53
54 #[inline(always)]
55 pub fn get_or_insert(&mut self, id: u64, create: impl FnOnce() -> Box<T>) -> &mut T {
56 if self.cached_id == id {
57 return self.cached_context.as_mut().unwrap();
59 }
60
61 if self.cached_context.is_some() {
63 let old_id = self.cached_id;
65 let old_context = self.cached_context.take().unwrap();
66 self.others.insert(old_id, old_context);
67 }
68
69 let context = self.others.remove(&id).unwrap_or_else(create);
71 self.cached_id = id;
72 self.cached_context = Some(context);
73 self.cached_context.as_mut().unwrap()
74 }
75
76 #[inline(always)]
79 pub fn get_or_insert_result<E>(
80 &mut self,
81 id: u64,
82 create: impl FnOnce() -> Result<Box<T>, E>,
83 ) -> Result<&mut T, E> {
84 if self.cached_id == id {
85 return Ok(self.cached_context.as_mut().unwrap());
87 }
88
89 if self.cached_context.is_some() {
91 let old_id = self.cached_id;
93 let old_context = self.cached_context.take().unwrap();
94 self.others.insert(old_id, old_context);
95 }
96
97 let context = match self.others.remove(&id) {
99 Some(ctx) => ctx,
100 None => create()?,
101 };
102 self.cached_id = id;
103 self.cached_context = Some(context);
104 Ok(self.cached_context.as_mut().unwrap())
105 }
106}
107
108impl<T> Default for ContextCache<T> {
109 fn default() -> Self {
110 Self::new()
111 }
112}
113
114#[allow(clippy::needless_lifetimes)]
117pub struct WriteContext<'a> {
118 type_resolver: TypeResolver,
120 compatible: bool,
121 share_meta: bool,
122 compress_string: bool,
123 xlang: bool,
124 check_struct_version: bool,
125 track_ref: bool,
126
127 default_writer: Option<Writer<'a>>,
129 pub writer: Writer<'a>,
130 meta_resolver: MetaWriterResolver,
131 meta_string_resolver: MetaStringWriterResolver,
132 pub ref_writer: RefWriter,
133}
134
135#[allow(clippy::needless_lifetimes)]
136impl<'a> WriteContext<'a> {
137 pub fn new(type_resolver: TypeResolver, config: Config) -> WriteContext<'a> {
138 WriteContext {
139 type_resolver,
140 compatible: config.compatible,
141 share_meta: config.share_meta,
142 compress_string: config.compress_string,
143 xlang: config.xlang,
144 check_struct_version: config.check_struct_version,
145 track_ref: config.track_ref,
146 default_writer: None,
147 writer: Writer::from_buffer(Self::get_leak_buffer()),
148 meta_resolver: MetaWriterResolver::default(),
149 meta_string_resolver: MetaStringWriterResolver::default(),
150 ref_writer: RefWriter::new(),
151 }
152 }
153
154 #[inline(always)]
155 fn get_leak_buffer() -> &'static mut Vec<u8> {
156 Box::leak(Box::new(vec![]))
157 }
158
159 #[inline(always)]
160 pub fn attach_writer(&mut self, writer: Writer<'a>) {
161 let old = mem::replace(&mut self.writer, writer);
162 self.default_writer = Some(old);
163 }
164
165 #[inline(always)]
166 pub fn detach_writer(&mut self) {
167 let default = mem::take(&mut self.default_writer);
168 self.writer = default.unwrap();
169 }
170
171 #[inline(always)]
173 pub fn get_type_resolver(&self) -> &TypeResolver {
174 &self.type_resolver
175 }
176
177 #[inline(always)]
178 pub fn get_type_info(&self, type_id: &std::any::TypeId) -> Result<Rc<TypeInfo>, Error> {
179 self.type_resolver.get_type_info(type_id)
180 }
181
182 #[inline(always)]
184 pub fn is_compatible(&self) -> bool {
185 self.compatible
186 }
187
188 #[inline(always)]
190 pub fn is_share_meta(&self) -> bool {
191 self.share_meta
192 }
193
194 #[inline(always)]
196 pub fn is_compress_string(&self) -> bool {
197 self.compress_string
198 }
199
200 #[inline(always)]
202 pub fn is_xlang(&self) -> bool {
203 self.xlang
204 }
205
206 #[inline(always)]
208 pub fn is_check_struct_version(&self) -> bool {
209 self.check_struct_version
210 }
211
212 #[inline(always)]
214 pub fn is_track_ref(&self) -> bool {
215 self.track_ref
216 }
217
218 #[inline(always)]
221 pub fn write_type_meta(&mut self, type_id: std::any::TypeId) -> Result<(), Error> {
222 self.meta_resolver
223 .write_type_meta(&mut self.writer, type_id, &self.type_resolver)
224 }
225
226 #[inline(always)]
228 pub fn write_struct_type_info<T: StructSerializer>(&mut self) -> Result<(), Error> {
229 let rust_type_id = std::any::TypeId::of::<T>();
230 let type_index = T::fory_type_index();
231 let type_id = self.type_resolver.get_type_id_by_index(type_index)?;
232 match type_id {
233 TypeId::STRUCT | TypeId::ENUM | TypeId::EXT | TypeId::TYPED_UNION => {
234 self.writer.write_u8(type_id as u8);
235 let user_type_id = self
236 .type_resolver
237 .get_user_type_id_by_index(&rust_type_id, type_index)?;
238 self.writer.write_var_u32(user_type_id);
239 }
240 TypeId::COMPATIBLE_STRUCT | TypeId::NAMED_COMPATIBLE_STRUCT => {
241 self.writer.write_u8(type_id as u8);
242 self.meta_resolver.write_type_meta_fast(
243 &mut self.writer,
244 rust_type_id,
245 type_index,
246 &self.type_resolver,
247 )?;
248 }
249 TypeId::NAMED_ENUM | TypeId::NAMED_EXT | TypeId::NAMED_STRUCT | TypeId::NAMED_UNION
250 if self.is_share_meta() =>
251 {
252 self.writer.write_u8(type_id as u8);
253 self.meta_resolver.write_type_meta_fast(
254 &mut self.writer,
255 rust_type_id,
256 type_index,
257 &self.type_resolver,
258 )?;
259 }
260 _ => {
261 self.write_any_type_info(type_id as u32, rust_type_id)?;
262 }
263 }
264 Ok(())
265 }
266
267 pub fn write_any_type_info(
268 &mut self,
269 fory_type_id: u32,
270 concrete_type_id: std::any::TypeId,
271 ) -> Result<Rc<TypeInfo>, Error> {
272 if types::is_internal_type(fory_type_id) {
273 self.writer.write_u8(fory_type_id as u8);
274 return self
275 .type_resolver
276 .get_type_info_by_id(fory_type_id)
277 .ok_or_else(|| Error::type_error("Type info for internal type not found"));
278 }
279 let type_info = self.type_resolver.get_type_info(&concrete_type_id)?;
280 let fory_type_id = type_info.get_type_id();
281 let namespace = type_info.get_namespace();
282 let type_name = type_info.get_type_name();
283 self.writer.write_u8(fory_type_id as u8);
284 match fory_type_id {
286 TypeId::ENUM | TypeId::STRUCT | TypeId::EXT | TypeId::TYPED_UNION => {
287 let user_type_id = type_info.get_user_type_id();
288 self.writer.write_var_u32(user_type_id);
289 }
290 TypeId::COMPATIBLE_STRUCT | TypeId::NAMED_COMPATIBLE_STRUCT => {
291 self.meta_resolver.write_type_meta(
293 &mut self.writer,
294 concrete_type_id,
295 &self.type_resolver,
296 )?;
297 }
298 TypeId::NAMED_ENUM | TypeId::NAMED_EXT | TypeId::NAMED_STRUCT | TypeId::NAMED_UNION => {
299 if self.is_share_meta() {
300 self.meta_resolver.write_type_meta(
302 &mut self.writer,
303 concrete_type_id,
304 &self.type_resolver,
305 )?;
306 } else {
307 self.write_meta_string_bytes(namespace)?;
308 self.write_meta_string_bytes(type_name)?;
309 }
310 }
311 _ => {
312 }
314 }
315 Ok(type_info)
316 }
317
318 #[inline(always)]
319 pub fn write_meta_string_bytes(&mut self, ms: Rc<MetaString>) -> Result<(), Error> {
320 self.meta_string_resolver
321 .write_meta_string_bytes(&mut self.writer, ms)
322 }
323
324 #[inline(always)]
325 pub fn reset(&mut self) {
326 self.meta_resolver.reset();
327 self.meta_string_resolver.reset();
328 self.ref_writer.reset();
329 }
330}
331
332#[allow(clippy::needless_lifetimes)]
333impl<'a> Drop for WriteContext<'a> {
334 fn drop(&mut self) {
335 unsafe {
336 drop(Box::from_raw(self.writer.bf));
337 }
338 }
339}
340
341#[allow(clippy::needless_lifetimes)]
346unsafe impl<'a> Send for WriteContext<'a> {}
347#[allow(clippy::needless_lifetimes)]
348unsafe impl<'a> Sync for WriteContext<'a> {}
349
350pub struct ReadContext<'a> {
353 type_resolver: TypeResolver,
355 config: Config,
356 compatible: bool,
357 share_meta: bool,
358 xlang: bool,
359 max_dyn_depth: u32,
360 check_struct_version: bool,
361 check_string_read: bool,
362 pub(crate) remaining_graph_memory_bytes: usize,
363
364 pub reader: Reader<'a>,
366 pub meta_resolver: MetaReaderResolver,
367 meta_string_resolver: MetaStringReaderResolver,
368 pub ref_reader: RefReader,
369 current_depth: u32,
370}
371
372#[allow(clippy::needless_lifetimes)]
377unsafe impl<'a> Send for ReadContext<'a> {}
378#[allow(clippy::needless_lifetimes)]
379unsafe impl<'a> Sync for ReadContext<'a> {}
380
381impl<'a> ReadContext<'a> {
382 pub fn new(type_resolver: TypeResolver, config: Config) -> ReadContext<'a> {
383 ReadContext {
384 type_resolver,
385 config: config.clone(),
386 compatible: config.compatible,
387 share_meta: config.share_meta,
388 xlang: config.xlang,
389 max_dyn_depth: config.max_dyn_depth,
390 check_struct_version: config.check_struct_version,
391 check_string_read: config.check_string_read,
392 remaining_graph_memory_bytes: 0,
393 reader: Reader::default(),
394 meta_resolver: MetaReaderResolver::default(),
395 meta_string_resolver: MetaStringReaderResolver::default(),
396 ref_reader: RefReader::new(),
397 current_depth: 0,
398 }
399 }
400
401 #[inline(always)]
403 pub fn get_type_resolver(&self) -> &TypeResolver {
404 &self.type_resolver
405 }
406
407 #[inline(always)]
409 pub fn is_compatible(&self) -> bool {
410 self.compatible
411 }
412
413 #[inline(always)]
415 pub fn is_share_meta(&self) -> bool {
416 self.share_meta
417 }
418
419 #[inline(always)]
421 pub fn is_xlang(&self) -> bool {
422 self.xlang
423 }
424
425 #[inline(always)]
427 pub fn is_check_struct_version(&self) -> bool {
428 self.check_struct_version
429 }
430
431 #[inline(always)]
433 pub fn is_check_string_read(&self) -> bool {
434 self.check_string_read
435 }
436
437 #[inline(always)]
439 pub fn max_dyn_depth(&self) -> u32 {
440 self.max_dyn_depth
441 }
442
443 #[inline(always)]
444 pub fn attach_reader(&mut self, reader: Reader<'a>) {
445 self.reader = reader;
446 }
447
448 #[inline(always)]
449 #[doc(hidden)]
450 pub fn reserve_graph_memory(&mut self, bytes: usize) -> Result<(), Error> {
451 let remaining = self.remaining_graph_memory_bytes;
452 if bytes > remaining {
453 return Err(graph_memory_exceeded(
454 bytes,
455 remaining,
456 self.config.max_graph_memory_bytes,
457 ));
458 }
459 self.remaining_graph_memory_bytes = remaining - bytes;
460 Ok(())
461 }
462
463 #[inline(always)]
464 pub fn detach_reader(&mut self) -> Reader<'_> {
465 mem::take(&mut self.reader)
466 }
467
468 #[inline(always)]
469 pub fn get_type_info_by_index(&self, type_index: usize) -> Result<&Rc<TypeInfo>, Error> {
470 self.meta_resolver.get(type_index).ok_or_else(|| {
471 Error::type_error(format!("TypeInfo not found for type index: {}", type_index))
472 })
473 }
474
475 #[inline(always)]
476 pub fn get_meta(&self, type_index: usize) -> Result<&Rc<TypeInfo>, Error> {
477 self.get_type_info_by_index(type_index)
478 }
479
480 #[inline(always)]
483 pub fn read_type_meta(&mut self) -> Result<Rc<TypeInfo>, Error> {
484 self.meta_resolver
485 .read_type_meta(&mut self.reader, &self.type_resolver, &self.config)
486 }
487
488 pub fn read_any_type_info(&mut self) -> Result<Rc<TypeInfo>, Error> {
489 let fory_type_id = self.reader.read_u8()? as u32;
490 match fory_type_id {
492 types::ENUM | types::STRUCT | types::EXT | types::TYPED_UNION => {
493 let user_type_id = self.reader.read_var_u32()?;
494 self.type_resolver
495 .get_user_type_info_by_id(user_type_id)
496 .ok_or_else(|| Error::type_error("ID harness not found"))
497 }
498 types::COMPATIBLE_STRUCT | types::NAMED_COMPATIBLE_STRUCT => {
499 self.read_type_meta()
501 }
502 types::NAMED_ENUM | types::NAMED_EXT | types::NAMED_STRUCT | types::NAMED_UNION => {
503 if self.is_share_meta() {
504 self.read_type_meta()
506 } else {
507 let namespace = self.read_meta_string()?.to_owned();
508 let type_name = self.read_meta_string()?.to_owned();
509 let rc_namespace = Rc::from(namespace.clone());
510 let rc_type_name = Rc::from(type_name.clone());
511 self.type_resolver
512 .get_type_info_by_meta_string_name(rc_namespace, rc_type_name)
513 .or_else(|| {
514 self.type_resolver.get_type_info_by_name(
515 namespace.original.as_str(),
516 type_name.original.as_str(),
517 )
518 })
519 .ok_or_else(|| {
520 Error::type_error(format!(
521 "Name harness not found: namespace='{}', type='{}'",
522 namespace.original, type_name.original
523 ))
524 })
525 }
526 }
527 _ => self
528 .type_resolver
529 .get_type_info_by_id(fory_type_id)
530 .ok_or_else(|| Error::type_error("ID harness not found")),
531 }
532 }
533
534 #[inline(always)]
535 pub fn get_type_info(&self, type_id: &std::any::TypeId) -> Result<Rc<TypeInfo>, Error> {
536 self.type_resolver.get_type_info(type_id)
537 }
538
539 #[inline(always)]
540 pub fn read_meta_string(&mut self) -> Result<&MetaString, Error> {
541 self.meta_string_resolver.read_meta_string(&mut self.reader)
542 }
543
544 #[inline(always)]
545 pub fn inc_depth(&mut self) -> Result<(), Error> {
546 self.current_depth += 1;
547 if self.current_depth > self.max_dyn_depth() {
548 return Err(Error::depth_exceed(format!(
549 "Maximum dynamic object nesting depth ({}) exceeded. Current depth: {}. \
550 This may indicate a circular reference or overly deep object graph. \
551 Consider increasing max_dyn_depth if this is expected.",
552 self.max_dyn_depth(),
553 self.current_depth
554 )));
555 }
556 Ok(())
557 }
558
559 #[inline(always)]
560 pub fn dec_depth(&mut self) {
561 self.current_depth = self.current_depth.saturating_sub(1);
562 }
563
564 #[inline(always)]
565 pub fn reset(&mut self) {
566 self.meta_resolver.reset();
567 self.meta_string_resolver.reset();
568 self.ref_reader.reset();
569 self.current_depth = 0;
570 }
571}
572
573#[cold]
574#[inline(never)]
575fn graph_memory_exceeded(bytes: usize, remaining: usize, limit: usize) -> Error {
576 Error::invalid_data(format!(
577 "estimated graph memory request {} bytes exceeds max_graph_memory_bytes remaining budget {} bytes out of effective limit {} bytes",
578 bytes, remaining, limit
579 ))
580}