1use crate::buffer::{Reader, Writer};
19use crate::config::Config;
20use crate::error::Error;
21use crate::meta::TypeMeta;
22use crate::resolver::type_resolver::NO_USER_TYPE_ID;
23use crate::resolver::{TypeInfo, TypeResolver};
24use std::collections::HashMap;
25use std::rc::Rc;
26
27#[derive(Default)]
32pub struct MetaWriterResolver {
33 type_info_index_map: HashMap<*const TypeInfo, usize>,
36 type_index_index_map: Vec<usize>,
37 next_index: usize,
38}
39
40const MIN_REMOTE_TYPE_META_VERSIONS: u64 = 8192;
41const MAX_REMOTE_TYPE_META_KEYS: usize = 8192;
42const NO_WRITTEN_TYPE_INDEX: usize = usize::MAX;
43
44#[allow(dead_code)]
45impl MetaWriterResolver {
46 #[inline(always)]
49 pub fn write_type_meta(
50 &mut self,
51 writer: &mut Writer,
52 provider_type_id: std::any::TypeId,
53 type_resolver: &TypeResolver,
54 ) -> Result<(), Error> {
55 let type_info = type_resolver.get_provider_type_info(&provider_type_id)?;
56 self.write_resolved_type_meta(writer, &type_info)
57 }
58
59 #[inline(always)]
60 pub(crate) fn write_resolved_type_meta(
61 &mut self,
62 writer: &mut Writer,
63 type_info: &Rc<TypeInfo>,
64 ) -> Result<(), Error> {
65 let identity = Rc::as_ptr(type_info);
66 match self.type_info_index_map.get(&identity) {
67 Some(&index) => {
68 writer.write_var_u32(((index as u32) << 1) | 1);
70 }
71 None => {
72 let index = self.next_index;
74 self.next_index += 1;
75 writer.write_var_u32((index as u32) << 1);
76 self.type_info_index_map.insert(identity, index);
77 let type_def = type_info.get_type_def();
78 writer.write_bytes(&type_def);
79 }
80 }
81 Ok(())
82 }
83
84 #[inline(always)]
86 pub fn write_type_meta_fast(
87 &mut self,
88 writer: &mut Writer,
89 type_id: std::any::TypeId,
90 type_index: u32,
91 type_resolver: &TypeResolver,
92 ) -> Result<(), Error> {
93 let type_index = type_index as usize;
94 if let Some(&index) = self.type_index_index_map.get(type_index) {
95 if index != NO_WRITTEN_TYPE_INDEX {
96 writer.write_var_u32(((index as u32) << 1) | 1);
97 return Ok(());
98 }
99 }
100
101 let index = self.next_index;
102 self.next_index += 1;
103 writer.write_var_u32((index as u32) << 1);
104 if type_index >= self.type_index_index_map.len() {
105 self.type_index_index_map
106 .resize(type_index + 1, NO_WRITTEN_TYPE_INDEX);
107 }
108 self.type_index_index_map[type_index] = index;
109 let type_meta = type_resolver.get_type_meta_by_index_ref(&type_id, type_index as u32)?;
110 writer.write_bytes(type_meta.get_bytes());
111 Ok(())
112 }
113
114 #[inline(always)]
115 pub fn reset(&mut self) {
116 self.type_info_index_map.clear();
117 self.type_index_index_map.clear();
118 self.next_index = 0;
119 }
120}
121
122#[derive(Default)]
127pub struct MetaReaderResolver {
128 pub reading_type_infos: Vec<Rc<TypeInfo>>,
129 parsed_type_infos: HashMap<i64, Rc<TypeInfo>>,
130 remote_schema_versions_by_type: HashMap<String, usize>,
131 total_accepted_schema_versions: u64,
132 cached_meta_hash: i64,
133 cached_type_info: Option<Rc<TypeInfo>>,
134}
135
136#[derive(Clone, Copy)]
137enum TypeInfoExpectation<'a> {
138 Any,
139 Exact(&'a Rc<TypeInfo>),
140 Structural(&'a Rc<TypeInfo>),
141}
142
143impl<'a> TypeInfoExpectation<'a> {
144 #[inline(always)]
145 fn local(self) -> Option<&'a Rc<TypeInfo>> {
146 match self {
147 Self::Any => None,
148 Self::Exact(type_info) | Self::Structural(type_info) => Some(type_info),
149 }
150 }
151
152 #[inline(always)]
153 fn allows_stub(self) -> bool {
154 matches!(self, Self::Structural(_))
155 }
156}
157
158impl MetaReaderResolver {
159 #[inline(always)]
160 pub fn get(&self, index: usize) -> Option<&Rc<TypeInfo>> {
161 self.reading_type_infos.get(index)
162 }
163
164 #[inline(always)]
167 pub fn read_type_meta(
168 &mut self,
169 reader: &mut Reader,
170 type_resolver: &TypeResolver,
171 config: &Config,
172 ) -> Result<Rc<TypeInfo>, Error> {
173 self.read_type_meta_with_expected(reader, type_resolver, config, TypeInfoExpectation::Any)
174 }
175
176 #[inline(always)]
177 pub(crate) fn read_type_meta_for(
178 &mut self,
179 reader: &mut Reader,
180 type_resolver: &TypeResolver,
181 config: &Config,
182 expected: &Rc<TypeInfo>,
183 ) -> Result<Rc<TypeInfo>, Error> {
184 self.read_type_meta_with_expected(
185 reader,
186 type_resolver,
187 config,
188 TypeInfoExpectation::Exact(expected),
189 )
190 }
191
192 #[inline(always)]
193 pub(crate) fn read_struct_type_meta_for(
194 &mut self,
195 reader: &mut Reader,
196 type_resolver: &TypeResolver,
197 config: &Config,
198 expected: &Rc<TypeInfo>,
199 ) -> Result<Rc<TypeInfo>, Error> {
200 self.read_type_meta_with_expected(
201 reader,
202 type_resolver,
203 config,
204 TypeInfoExpectation::Structural(expected),
205 )
206 }
207
208 #[inline(always)]
209 fn read_type_meta_with_expected(
210 &mut self,
211 reader: &mut Reader,
212 type_resolver: &TypeResolver,
213 config: &Config,
214 expected: TypeInfoExpectation<'_>,
215 ) -> Result<Rc<TypeInfo>, Error> {
216 let index_marker = reader.read_var_u32()?;
217 let is_ref = (index_marker & 1) == 1;
218 let index = (index_marker >> 1) as usize;
219
220 if is_ref {
221 let type_info = self.reading_type_infos.get(index).cloned().ok_or_else(|| {
223 Error::type_error(format!("TypeInfo not found for type index: {}", index))
224 })?;
225 Self::check_expected_owner(&type_info, expected)?;
226 Ok(type_info)
227 } else {
228 let meta_header = reader.read_i64()?;
230 let meta_hash = TypeMeta::header_hash(meta_header);
231 if let Some(type_info) = expected
232 .local()
233 .filter(|type_info| type_info.get_type_meta_ref().get_hash() == meta_hash)
234 .cloned()
235 {
236 TypeMeta::skip_bytes_for_validated_header(reader, meta_header)?;
239 self.reading_type_infos.push(type_info.clone());
240 return Ok(type_info);
241 }
242 if let Some(type_info) = self
243 .cached_type_info
244 .as_ref()
245 .filter(|_| self.cached_meta_hash == meta_hash)
246 .cloned()
247 {
248 Self::check_expected_owner(&type_info, expected)?;
251 TypeMeta::skip_bytes_for_validated_header(reader, meta_header)?;
252 self.reading_type_infos.push(type_info.clone());
253 return Ok(type_info);
254 }
255 if let Some(type_info) = self.parsed_type_infos.get(&meta_hash).cloned() {
256 Self::check_expected_owner(&type_info, expected)?;
259 TypeMeta::skip_bytes_for_validated_header(reader, meta_header)?;
260 self.cached_meta_hash = meta_hash;
261 self.cached_type_info = Some(type_info.clone());
262 self.reading_type_infos.push(type_info.clone());
263 Ok(type_info)
264 } else {
265 self.read_remote_type_meta(
266 reader,
267 type_resolver,
268 config,
269 meta_header,
270 meta_hash,
271 expected,
272 )
273 }
274 }
275 }
276
277 #[inline(always)]
278 fn check_expected_owner(
279 type_info: &TypeInfo,
280 expected: TypeInfoExpectation<'_>,
281 ) -> Result<(), Error> {
282 let Some(expected_type_info) = expected.local() else {
283 return Ok(());
284 };
285 let expected_target = expected_type_info
286 .get_harness()
287 .target_type_id()
288 .ok_or_else(|| Error::type_error("expected TypeInfo has no concrete target"))?;
289 let resolved_target = type_info.get_harness().target_type_id();
290 if expected.allows_stub()
291 && !crate::type_id::is_struct_type_id(type_info.get_type_meta_ref().get_type_id())
292 {
293 return Err(Self::type_info_kind_mismatch(
294 type_info.get_type_meta_ref().get_type_id(),
295 ));
296 }
297 if resolved_target != Some(expected_target)
298 && !(expected.allows_stub() && resolved_target.is_none())
299 {
300 return Err(Self::type_info_owner_mismatch(
301 resolved_target,
302 expected_target,
303 ));
304 }
305 Ok(())
306 }
307
308 #[cold]
309 #[inline(never)]
310 fn type_info_owner_mismatch(
311 resolved: Option<std::any::TypeId>,
312 expected: std::any::TypeId,
313 ) -> Error {
314 Error::type_error(format!(
315 "resolved TypeInfo target {:?} does not match declared target {:?}",
316 resolved, expected,
317 ))
318 }
319
320 #[cold]
321 #[inline(never)]
322 fn type_info_kind_mismatch(resolved: u32) -> Error {
323 Error::type_error(format!(
324 "resolved TypeInfo wire kind {} is not structural metadata",
325 resolved,
326 ))
327 }
328
329 #[cold]
330 #[inline(never)]
331 fn read_remote_type_meta(
332 &mut self,
333 reader: &mut Reader,
334 type_resolver: &TypeResolver,
335 config: &Config,
336 meta_header: i64,
337 meta_hash: i64,
338 expected: TypeInfoExpectation<'_>,
339 ) -> Result<Rc<TypeInfo>, Error> {
340 let type_meta = Rc::new(TypeMeta::from_bytes_with_header(
341 reader,
342 type_resolver,
343 meta_header,
344 config.max_type_fields(),
345 config.max_type_meta_bytes(),
346 )?);
347
348 let namespace = type_meta.get_namespace();
349 let type_name = type_meta.get_type_name();
350 let register_by_name = !namespace.original.is_empty() || !type_name.original.is_empty();
351 let remote_schema_key;
352 let type_info = if register_by_name {
356 if let Some(local_type_info) =
357 type_resolver.get_type_info_by_name(&namespace.original, &type_name.original)
358 {
359 if local_type_info.get_type_meta_ref().get_hash() == meta_hash {
360 Self::check_expected_owner(&local_type_info, expected)?;
361 self.reading_type_infos.push(local_type_info.clone());
362 return Ok(local_type_info);
363 } else {
364 remote_schema_key = self.check_remote_type_meta_limit(&type_meta, config)?;
365 Rc::new(TypeInfo::from_remote_meta(
366 type_meta.clone(),
367 Some(local_type_info.get_harness()),
368 Some(local_type_info.get_type_id() as u32),
369 Some(local_type_info.get_user_type_id()),
370 ))
371 }
372 } else {
373 remote_schema_key = self.check_remote_type_meta_limit(&type_meta, config)?;
374 Rc::new(TypeInfo::from_remote_meta(
375 type_meta.clone(),
376 None,
377 None,
378 None,
379 ))
380 }
381 } else {
382 let type_id = type_meta.get_type_id();
383 let user_type_id = type_meta.get_user_type_id();
384 let local_type_info = if user_type_id != NO_USER_TYPE_ID {
385 type_resolver.get_user_type_info_by_id(user_type_id)
386 } else {
387 type_resolver.get_type_info_by_id(type_id)
388 };
389 if let Some(local_type_info) = local_type_info {
390 if local_type_info.get_type_meta_ref().get_hash() == meta_hash {
391 Self::check_expected_owner(&local_type_info, expected)?;
392 self.reading_type_infos.push(local_type_info.clone());
393 return Ok(local_type_info);
394 } else {
395 remote_schema_key = self.check_remote_type_meta_limit(&type_meta, config)?;
396 Rc::new(TypeInfo::from_remote_meta(
397 type_meta.clone(),
398 Some(local_type_info.get_harness()),
399 Some(local_type_info.get_type_id() as u32),
400 Some(local_type_info.get_user_type_id()),
401 ))
402 }
403 } else {
404 remote_schema_key = self.check_remote_type_meta_limit(&type_meta, config)?;
405 Rc::new(TypeInfo::from_remote_meta(
406 type_meta.clone(),
407 None,
408 None,
409 None,
410 ))
411 }
412 };
413
414 Self::check_expected_owner(&type_info, expected)?;
418 self.parsed_type_infos.insert(meta_hash, type_info.clone());
419 self.cached_meta_hash = meta_hash;
420 self.cached_type_info = Some(type_info.clone());
421 self.reading_type_infos.push(type_info.clone());
422 self.record_remote_type_meta(remote_schema_key);
423 Ok(type_info)
424 }
425
426 #[cold]
427 #[inline(never)]
428 fn check_remote_type_meta_limit(
429 &self,
430 type_meta: &TypeMeta,
431 config: &Config,
432 ) -> Result<String, Error> {
433 let namespace = type_meta.get_namespace();
434 let type_name = type_meta.get_type_name();
435 let key = if !namespace.original.is_empty() || !type_name.original.is_empty() {
436 format!("n{}\0{}", namespace.original, type_name.original)
437 } else {
438 format!("i{}", type_meta.get_user_type_id())
439 };
440
441 let versions_for_type = self
442 .remote_schema_versions_by_type
443 .get(&key)
444 .copied()
445 .unwrap_or(0);
446 if versions_for_type == 0
449 && self.remote_schema_versions_by_type.len() >= MAX_REMOTE_TYPE_META_KEYS
450 {
451 return Err(Error::invalid_data(
452 "remote logical TypeMeta key limit exceeded. The data may be malicious",
453 ));
454 }
455 if versions_for_type >= config.max_schema_versions_per_type() {
456 return Err(Error::invalid_data(format!(
457 "remote schema version limit exceeded for one type. The data may be malicious. If the data is not malicious, please increase max_schema_versions_per_type={}",
458 config.max_schema_versions_per_type()
459 )));
460 }
461
462 let accepted_type_count = (self.remote_schema_versions_by_type.len()
463 + if versions_for_type == 0 { 1 } else { 0 }) as u64;
464 let max_average = config.max_average_schema_versions_per_type() as u64;
465 let reached_average_limit = max_average == 0
466 || self.total_accepted_schema_versions / max_average >= accepted_type_count;
467 if self.total_accepted_schema_versions == u64::MAX
468 || (self.total_accepted_schema_versions >= MIN_REMOTE_TYPE_META_VERSIONS
469 && reached_average_limit)
470 {
471 return Err(Error::invalid_data(format!(
472 "remote schema version limit exceeded globally. The data may be malicious. If the data is not malicious, please increase max_average_schema_versions_per_type={}",
473 config.max_average_schema_versions_per_type()
474 )));
475 }
476
477 Ok(key)
478 }
479
480 fn record_remote_type_meta(&mut self, key: String) {
481 let versions_for_type = self
482 .remote_schema_versions_by_type
483 .get(&key)
484 .copied()
485 .unwrap_or(0);
486 self.remote_schema_versions_by_type
487 .insert(key, versions_for_type + 1);
488 self.total_accepted_schema_versions += 1;
491 }
492
493 #[inline(always)]
494 pub fn reset(&mut self) {
495 self.reading_type_infos.clear();
496 }
497}
498
499#[cfg(test)]
500mod tests {
501 use super::*;
502 use crate::config::Config;
503 use crate::context::{ReadContext, WriteContext};
504 use crate::meta::{
505 FieldInfo, FieldType, MetaString, NAMESPACE_ENCODER, NAMESPACE_ENCODINGS,
506 TYPE_NAME_ENCODER, TYPE_NAME_ENCODINGS,
507 };
508 use crate::serializer::{Serializer, StructSerializer};
509 use crate::TypeId;
510
511 const LOCAL_COLLISION_FIELD: &str = "!AsA3daaa";
512 const REMOTE_COLLISION_FIELD: &str = "!aR5Ocaaaa";
513
514 struct LocalExt;
515
516 impl Serializer for LocalExt {
517 type Target = Self;
518
519 fn write_data(_value: &Self, _context: &mut WriteContext) -> Result<(), Error> {
520 Ok(())
521 }
522
523 fn read_data(_context: &mut ReadContext) -> Result<Self, Error> {
524 Ok(LocalExt)
525 }
526 }
527
528 struct CollisionStruct;
529
530 impl Serializer for CollisionStruct {
531 type Target = Self;
532
533 fn write_data(_value: &Self, _context: &mut WriteContext) -> Result<(), Error> {
534 Ok(())
535 }
536
537 fn read_data(_context: &mut ReadContext) -> Result<Self, Error> {
538 Ok(CollisionStruct)
539 }
540
541 fn static_type_id() -> TypeId {
542 TypeId::STRUCT
543 }
544 }
545
546 impl StructSerializer for CollisionStruct {
547 fn type_index() -> u32 {
548 9001
549 }
550
551 fn fields_info(_type_resolver: &TypeResolver) -> Result<Vec<FieldInfo>, Error> {
552 Ok(vec![FieldInfo::new(
553 LOCAL_COLLISION_FIELD,
554 FieldType::new(crate::type_id::INT32, false, vec![]),
555 )])
556 }
557
558 fn variants_fields_info(
559 _type_resolver: &TypeResolver,
560 ) -> Result<Vec<(String, std::any::TypeId, Vec<FieldInfo>)>, Error> {
561 Ok(vec![])
562 }
563
564 fn sorted_field_names() -> &'static [&'static str] {
565 &[LOCAL_COLLISION_FIELD]
566 }
567
568 fn read_compatible(
569 _context: &mut ReadContext,
570 _type_info: &Rc<TypeInfo>,
571 ) -> Result<Self, Error> {
572 Ok(CollisionStruct)
573 }
574 }
575
576 struct ForeignStruct;
577
578 impl Serializer for ForeignStruct {
579 type Target = Self;
580
581 fn write_data(_value: &Self, _context: &mut WriteContext) -> Result<(), Error> {
582 Ok(())
583 }
584
585 fn read_data(_context: &mut ReadContext) -> Result<Self, Error> {
586 Ok(ForeignStruct)
587 }
588
589 fn static_type_id() -> TypeId {
590 TypeId::STRUCT
591 }
592 }
593
594 impl StructSerializer for ForeignStruct {
595 fn type_index() -> u32 {
596 9002
597 }
598
599 fn fields_info(_type_resolver: &TypeResolver) -> Result<Vec<FieldInfo>, Error> {
600 Ok(vec![FieldInfo::new(
601 "local_b",
602 FieldType::new(crate::type_id::INT32, false, vec![]),
603 )])
604 }
605
606 fn variants_fields_info(
607 _type_resolver: &TypeResolver,
608 ) -> Result<Vec<(String, std::any::TypeId, Vec<FieldInfo>)>, Error> {
609 Ok(vec![])
610 }
611
612 fn sorted_field_names() -> &'static [&'static str] {
613 &["local_b"]
614 }
615
616 fn read_compatible(
617 _context: &mut ReadContext,
618 _type_info: &Rc<TypeInfo>,
619 ) -> Result<Self, Error> {
620 Ok(ForeignStruct)
621 }
622 }
623
624 fn read_type_def(
625 resolver: &mut MetaReaderResolver,
626 config: &Config,
627 type_def: &[u8],
628 ) -> Result<Rc<TypeInfo>, Error> {
629 let type_resolver = TypeResolver::default();
630 read_type_def_with_type_resolver(resolver, config, &type_resolver, type_def)
631 }
632
633 fn read_type_def_with_type_resolver(
634 resolver: &mut MetaReaderResolver,
635 config: &Config,
636 type_resolver: &TypeResolver,
637 type_def: &[u8],
638 ) -> Result<Rc<TypeInfo>, Error> {
639 let mut bytes = vec![];
640 let mut writer = Writer::from_buffer(&mut bytes);
641 writer.write_var_u32(0);
642 writer.write_bytes(type_def);
643 let mut reader = Reader::new(&bytes);
644 resolver.read_type_meta(&mut reader, type_resolver, config)
645 }
646
647 fn remote_struct_meta(user_type_id: u32, field_name: &str) -> TypeMeta {
648 TypeMeta::new(
649 TypeId::STRUCT as u32,
650 user_type_id,
651 MetaString::get_empty().clone(),
652 MetaString::get_empty().clone(),
653 false,
654 vec![FieldInfo::new(
655 field_name,
656 FieldType::new(crate::type_id::INT32, false, vec![]),
657 )],
658 )
659 .unwrap()
660 }
661
662 fn named_struct_meta(namespace: &str, type_name: &str, field_name: &str) -> TypeMeta {
663 named_meta(
664 TypeId::NAMED_STRUCT,
665 namespace,
666 type_name,
667 vec![FieldInfo::new(
668 field_name,
669 FieldType::new(crate::type_id::INT32, false, vec![]),
670 )],
671 )
672 }
673
674 fn named_meta(
675 type_id: TypeId,
676 namespace: &str,
677 type_name: &str,
678 fields: Vec<FieldInfo>,
679 ) -> TypeMeta {
680 TypeMeta::new(
681 type_id as u32,
682 NO_USER_TYPE_ID,
683 NAMESPACE_ENCODER
684 .encode_with_encodings(namespace, NAMESPACE_ENCODINGS)
685 .unwrap(),
686 TYPE_NAME_ENCODER
687 .encode_with_encodings(type_name, TYPE_NAME_ENCODINGS)
688 .unwrap(),
689 true,
690 fields,
691 )
692 .unwrap()
693 }
694
695 fn read_type_def_for(
696 resolver: &mut MetaReaderResolver,
697 config: &Config,
698 type_resolver: &TypeResolver,
699 expected: &Rc<TypeInfo>,
700 type_def: &[u8],
701 ) -> Result<Rc<TypeInfo>, Error> {
702 let mut bytes = vec![];
703 let mut writer = Writer::from_buffer(&mut bytes);
704 writer.write_var_u32(0);
705 writer.write_bytes(type_def);
706 let mut reader = Reader::new(&bytes);
707 resolver.read_type_meta_for(&mut reader, type_resolver, config, expected)
708 }
709
710 fn read_struct_type_def_for(
711 resolver: &mut MetaReaderResolver,
712 config: &Config,
713 type_resolver: &TypeResolver,
714 expected: &Rc<TypeInfo>,
715 type_def: &[u8],
716 ) -> Result<Rc<TypeInfo>, Error> {
717 let mut bytes = vec![];
718 let mut writer = Writer::from_buffer(&mut bytes);
719 writer.write_var_u32(0);
720 writer.write_bytes(type_def);
721 let mut reader = Reader::new(&bytes);
722 resolver.read_struct_type_meta_for(&mut reader, type_resolver, config, expected)
723 }
724
725 fn type_def_frame(meta_hash: i64, flags: i64, body_size: usize, fill: u8) -> Vec<u8> {
726 assert_eq!(flags & !0xf00, 0);
727 let inline_size = body_size.min(0xff);
728 let header = (((meta_hash as u64) << 12) | flags as u64 | inline_size as u64) as i64;
729 let mut type_def = vec![];
730 let mut writer = Writer::from_buffer(&mut type_def);
731 writer.write_i64(header);
732 if body_size >= 0xff {
733 writer.write_var_u32(u32::try_from(body_size - 0xff).unwrap());
734 }
735 writer.write_bytes(&vec![fill; body_size]);
736 type_def
737 }
738
739 fn read_type_def_with_cursor(
740 resolver: &mut MetaReaderResolver,
741 config: &Config,
742 type_def: &[u8],
743 ) -> (Result<Rc<TypeInfo>, Error>, usize, usize) {
744 let mut bytes = vec![];
745 let mut writer = Writer::from_buffer(&mut bytes);
746 writer.write_var_u32(0);
747 writer.write_bytes(type_def);
748 let mut reader = Reader::new(&bytes);
749 let result = resolver.read_type_meta(&mut reader, &TypeResolver::default(), config);
750 (result, reader.get_cursor(), bytes.len())
751 }
752
753 fn fill_remote_schema_keys(resolver: &mut MetaReaderResolver, count: usize, versions: usize) {
754 assert!(count <= MAX_REMOTE_TYPE_META_KEYS);
755 for user_type_id in 0..count {
756 resolver
757 .remote_schema_versions_by_type
758 .insert(format!("i{user_type_id}"), versions);
759 }
760 resolver.total_accepted_schema_versions = count as u64 * versions as u64;
761 }
762
763 #[test]
764 fn logical_type_key_cap() {
765 let config = Config::default();
766 let mut resolver = MetaReaderResolver::default();
767 fill_remote_schema_keys(&mut resolver, MAX_REMOTE_TYPE_META_KEYS - 1, 1);
768
769 let last = remote_struct_meta((MAX_REMOTE_TYPE_META_KEYS - 1) as u32, "a");
770 read_type_def(&mut resolver, &config, last.get_bytes()).unwrap();
771 assert_eq!(
772 resolver.remote_schema_versions_by_type.len(),
773 MAX_REMOTE_TYPE_META_KEYS
774 );
775 assert_eq!(
776 resolver.total_accepted_schema_versions,
777 MAX_REMOTE_TYPE_META_KEYS as u64
778 );
779
780 let parsed_count = resolver.parsed_type_infos.len();
781 let reading_count = resolver.reading_type_infos.len();
782 let cached_hash = resolver.cached_meta_hash;
783 let cached_type_info = resolver.cached_type_info.as_ref().map(Rc::as_ptr);
784 let rejected = remote_struct_meta(MAX_REMOTE_TYPE_META_KEYS as u32, "a");
785 let err = read_type_def(&mut resolver, &config, rejected.get_bytes())
786 .unwrap_err()
787 .to_string();
788
789 assert!(err.contains("logical TypeMeta key limit"));
790 assert_eq!(
791 resolver.remote_schema_versions_by_type.len(),
792 MAX_REMOTE_TYPE_META_KEYS
793 );
794 assert_eq!(
795 resolver.total_accepted_schema_versions,
796 MAX_REMOTE_TYPE_META_KEYS as u64
797 );
798 assert_eq!(resolver.parsed_type_infos.len(), parsed_count);
799 assert_eq!(resolver.reading_type_infos.len(), reading_count);
800 assert_eq!(resolver.cached_meta_hash, cached_hash);
801 assert_eq!(
802 resolver.cached_type_info.as_ref().map(Rc::as_ptr),
803 cached_type_info
804 );
805 }
806
807 #[test]
808 fn existing_key_keeps_limits() {
809 let mut per_type_resolver = MetaReaderResolver::default();
810 fill_remote_schema_keys(&mut per_type_resolver, MAX_REMOTE_TYPE_META_KEYS, 1);
811 let per_type_config = Config {
812 max_schema_versions_per_type: 1,
813 ..Default::default()
814 };
815 let changed = remote_struct_meta(0, "b");
816 let err = read_type_def(
817 &mut per_type_resolver,
818 &per_type_config,
819 changed.get_bytes(),
820 )
821 .unwrap_err()
822 .to_string();
823 assert!(err.contains("max_schema_versions_per_type"));
824
825 let mut average_resolver = MetaReaderResolver::default();
826 fill_remote_schema_keys(&mut average_resolver, MAX_REMOTE_TYPE_META_KEYS, 3);
827 *average_resolver
828 .remote_schema_versions_by_type
829 .get_mut("i0")
830 .unwrap() = 2;
831 average_resolver.total_accepted_schema_versions -= 1;
832 let average_config = Config {
833 max_schema_versions_per_type: 10,
834 max_average_schema_versions_per_type: 3,
835 ..Default::default()
836 };
837
838 let accepted = remote_struct_meta(0, "b");
839 read_type_def(&mut average_resolver, &average_config, accepted.get_bytes()).unwrap();
840 assert_eq!(average_resolver.total_accepted_schema_versions, 24_576);
841
842 let rejected = remote_struct_meta(0, "c");
843 let err = read_type_def(&mut average_resolver, &average_config, rejected.get_bytes())
844 .unwrap_err()
845 .to_string();
846 assert!(err.contains("max_average_schema_versions_per_type"));
847 assert_eq!(average_resolver.total_accepted_schema_versions, 24_576);
848 }
849
850 #[test]
851 fn schema_total_does_not_wrap() {
852 let config = Config {
853 max_schema_versions_per_type: u32::MAX,
854 max_average_schema_versions_per_type: u32::MAX,
855 ..Default::default()
856 };
857 let mut resolver = MetaReaderResolver::default();
858 fill_remote_schema_keys(&mut resolver, 1, 1);
859 resolver.total_accepted_schema_versions = u64::MAX;
860 let meta = remote_struct_meta(0, "b");
861
862 let err = read_type_def(&mut resolver, &config, meta.get_bytes())
863 .unwrap_err()
864 .to_string();
865
866 assert!(err.contains("remote schema version limit exceeded globally"));
867 assert_eq!(resolver.total_accepted_schema_versions, u64::MAX);
868 assert_eq!(resolver.remote_schema_versions_by_type.get("i0"), Some(&1));
869 assert!(resolver.parsed_type_infos.is_empty());
870 assert!(resolver.cached_type_info.is_none());
871 assert!(resolver.reading_type_infos.is_empty());
872 }
873
874 #[test]
875 fn checked_cache_bypasses_key_cap() {
876 let config = Config::default();
877 let mut resolver = MetaReaderResolver::default();
878 fill_remote_schema_keys(&mut resolver, MAX_REMOTE_TYPE_META_KEYS - 1, 1);
879 let meta = remote_struct_meta((MAX_REMOTE_TYPE_META_KEYS - 1) as u32, "a");
880 let first = read_type_def(&mut resolver, &config, meta.get_bytes()).unwrap();
881
882 resolver.reset();
883 resolver.cached_type_info = None;
884 let strict_config = Config {
885 max_schema_versions_per_type: 1,
886 max_average_schema_versions_per_type: 1,
887 ..Default::default()
888 };
889 let cached = read_type_def(&mut resolver, &strict_config, meta.get_bytes()).unwrap();
890
891 assert!(Rc::ptr_eq(&first, &cached));
892 assert_eq!(resolver.reading_type_infos.len(), 1);
893 assert_eq!(
894 resolver.remote_schema_versions_by_type.len(),
895 MAX_REMOTE_TYPE_META_KEYS
896 );
897 assert_eq!(
898 resolver.total_accepted_schema_versions,
899 MAX_REMOTE_TYPE_META_KEYS as u64
900 );
901 }
902
903 #[test]
904 fn checked_hash_ignores_frame_length() {
905 let mut resolver = MetaReaderResolver::default();
906 let meta = remote_struct_meta(9001, "a");
907 let first = read_type_def(&mut resolver, &Config::default(), meta.get_bytes()).unwrap();
908 let parsed_count = resolver.parsed_type_infos.len();
909 let accepted_versions = resolver.total_accepted_schema_versions;
910 let strict_config = Config {
911 max_type_fields: 0,
912 max_type_meta_bytes: 1,
913 max_schema_versions_per_type: 0,
914 max_average_schema_versions_per_type: 0,
915 ..Default::default()
916 };
917
918 resolver.reset();
919 resolver.cached_type_info = None;
920 let inline = type_def_frame(meta.get_hash(), 0b101 << 9, 17, 0xff);
921 let inline_header = i64::from_le_bytes(inline[..8].try_into().unwrap());
922 assert_eq!(TypeMeta::header_hash(inline_header), meta.get_hash());
923 let (inline_result, inline_cursor, inline_len) =
924 read_type_def_with_cursor(&mut resolver, &strict_config, &inline);
925 assert!(Rc::ptr_eq(&first, &inline_result.unwrap()));
926 assert_eq!(inline_cursor, inline_len);
927
928 resolver.reset();
929 let extended = type_def_frame(meta.get_hash(), 0b1 << 8, 257, 0xa5);
930 let extended_header = i64::from_le_bytes(extended[..8].try_into().unwrap());
931 assert_eq!(TypeMeta::header_hash(extended_header), meta.get_hash());
932 let (extended_result, extended_cursor, extended_len) =
933 read_type_def_with_cursor(&mut resolver, &strict_config, &extended);
934 assert!(Rc::ptr_eq(&first, &extended_result.unwrap()));
935 assert_eq!(extended_cursor, extended_len);
936 assert_eq!(resolver.parsed_type_infos.len(), parsed_count);
937 assert_eq!(resolver.total_accepted_schema_versions, accepted_versions);
938 }
939
940 #[test]
941 fn checked_hash_rejects_truncation() {
942 let mut resolver = MetaReaderResolver::default();
943 let meta = remote_struct_meta(9001, "a");
944 read_type_def(&mut resolver, &Config::default(), meta.get_bytes()).unwrap();
945 let parsed_count = resolver.parsed_type_infos.len();
946
947 resolver.reset();
948 resolver.cached_type_info = None;
949 let mut truncated = meta.get_bytes().to_vec();
950 truncated.pop();
951 let (result, _, _) =
952 read_type_def_with_cursor(&mut resolver, &Config::default(), &truncated);
953
954 assert!(result.is_err());
955 assert!(resolver.reading_type_infos.is_empty());
956 assert!(resolver.cached_type_info.is_none());
957 assert_eq!(resolver.parsed_type_infos.len(), parsed_count);
958 }
959
960 #[test]
961 fn exact_local_bypasses_key_cap() {
962 let mut type_resolver = TypeResolver::default();
963 type_resolver
964 .register_serializer_by_name::<LocalExt>("example.SharedExt")
965 .unwrap();
966 let type_resolver = type_resolver.build_final_type_resolver().unwrap();
967 let local_info = type_resolver
968 .get_type_info_by_name("example", "SharedExt")
969 .unwrap();
970 let exact = local_info.get_type_meta_ref().get_bytes().to_vec();
971
972 let mut resolver = MetaReaderResolver::default();
973 fill_remote_schema_keys(&mut resolver, MAX_REMOTE_TYPE_META_KEYS, 1);
974 let strict_config = Config {
975 max_schema_versions_per_type: 1,
976 max_average_schema_versions_per_type: 1,
977 ..Default::default()
978 };
979 let resolved =
980 read_type_def_with_type_resolver(&mut resolver, &strict_config, &type_resolver, &exact)
981 .unwrap();
982
983 assert!(Rc::ptr_eq(&local_info, &resolved));
984 assert_eq!(
985 resolver.remote_schema_versions_by_type.len(),
986 MAX_REMOTE_TYPE_META_KEYS
987 );
988 assert_eq!(
989 resolver.total_accepted_schema_versions,
990 MAX_REMOTE_TYPE_META_KEYS as u64
991 );
992 }
993
994 #[test]
995 fn local_hash_owns_validated_miss() {
996 let mut type_resolver = TypeResolver::default();
997 type_resolver
998 .register_by_name::<CollisionStruct>("e!.C!")
999 .unwrap();
1000 let type_resolver = type_resolver.build_final_type_resolver().unwrap();
1001 let local_info = type_resolver.get_type_info_by_name("e!", "C!").unwrap();
1002 let local_type_def = local_info.get_type_meta_ref().get_bytes();
1003 let namespace = NAMESPACE_ENCODER
1004 .encode_with_encodings("e!", NAMESPACE_ENCODINGS)
1005 .unwrap();
1006 let type_name = TYPE_NAME_ENCODER
1007 .encode_with_encodings("C!", TYPE_NAME_ENCODINGS)
1008 .unwrap();
1009 let remote_meta = TypeMeta::new(
1013 TypeId::NAMED_STRUCT as u32,
1014 NO_USER_TYPE_ID,
1015 namespace,
1016 type_name,
1017 true,
1018 vec![FieldInfo::new(
1019 REMOTE_COLLISION_FIELD,
1020 FieldType::new(crate::type_id::INT32, false, vec![]),
1021 )],
1022 )
1023 .unwrap();
1024 let remote_type_def = remote_meta.get_bytes();
1025 let local_header = i64::from_le_bytes(local_type_def[..8].try_into().unwrap());
1026 let remote_header = i64::from_le_bytes(remote_type_def[..8].try_into().unwrap());
1027 assert_ne!(local_header & 0xfff, remote_header & 0xfff);
1028 assert_ne!(&local_type_def[8..], &remote_type_def[8..]);
1029 assert_eq!(
1030 TypeMeta::header_hash(remote_header),
1031 local_info.get_type_meta_ref().get_hash()
1032 );
1033
1034 let mut resolver = MetaReaderResolver::default();
1035 fill_remote_schema_keys(&mut resolver, MAX_REMOTE_TYPE_META_KEYS, 1);
1036 let cached_hash = resolver.cached_meta_hash;
1037 let strict_config = Config {
1038 max_schema_versions_per_type: 1,
1039 max_average_schema_versions_per_type: 1,
1040 ..Default::default()
1041 };
1042 let resolved = read_type_def_with_type_resolver(
1043 &mut resolver,
1044 &strict_config,
1045 &type_resolver,
1046 remote_type_def,
1047 )
1048 .unwrap();
1049
1050 assert!(Rc::ptr_eq(&local_info, &resolved));
1051 assert_eq!(resolver.reading_type_infos.len(), 1);
1052 assert!(resolver.parsed_type_infos.is_empty());
1053 assert_eq!(resolver.cached_meta_hash, cached_hash);
1054 assert!(resolver.cached_type_info.is_none());
1055 assert!(!resolver
1056 .remote_schema_versions_by_type
1057 .contains_key("ne!\0C!"));
1058 assert_eq!(
1059 resolver.total_accepted_schema_versions,
1060 MAX_REMOTE_TYPE_META_KEYS as u64
1061 );
1062
1063 let remote_header_hash = TypeMeta::header_hash(remote_header);
1066 let mut warmed = MetaReaderResolver::default();
1067 let remote_owner = read_type_def_with_type_resolver(
1068 &mut warmed,
1069 &Config::default(),
1070 &TypeResolver::default(),
1071 remote_type_def,
1072 )
1073 .unwrap();
1074 let versions = warmed.total_accepted_schema_versions;
1075 assert_eq!(warmed.parsed_type_infos.len(), 1);
1076 assert!(Rc::ptr_eq(
1077 warmed.parsed_type_infos.get(&remote_header_hash).unwrap(),
1078 &remote_owner,
1079 ));
1080
1081 let mut bytes = vec![];
1082 let mut writer = Writer::from_buffer(&mut bytes);
1083 writer.write_var_u32(0);
1084 writer.write_bytes(local_type_def);
1085 let mut reader = Reader::new(&bytes);
1086 let resolved = warmed
1087 .read_type_meta_for(&mut reader, &type_resolver, &Config::default(), &local_info)
1088 .unwrap();
1089
1090 assert!(Rc::ptr_eq(&local_info, &resolved));
1091 assert_eq!(reader.get_cursor(), bytes.len());
1092 assert_eq!(warmed.total_accepted_schema_versions, versions);
1093 assert_eq!(warmed.parsed_type_infos.len(), 1);
1094 assert!(Rc::ptr_eq(
1095 warmed.parsed_type_infos.get(&remote_header_hash).unwrap(),
1096 &remote_owner,
1097 ));
1098 assert!(Rc::ptr_eq(
1099 warmed.cached_type_info.as_ref().unwrap(),
1100 &remote_owner,
1101 ));
1102 }
1103
1104 #[test]
1105 fn expected_owner_rejects_foreign() {
1106 let mut type_resolver = TypeResolver::default();
1107 type_resolver
1108 .register_by_name::<CollisionStruct>("owner.StructA")
1109 .unwrap();
1110 type_resolver
1111 .register_by_name::<ForeignStruct>("owner.StructB")
1112 .unwrap();
1113 let type_resolver = type_resolver.build_final_type_resolver().unwrap();
1114 let expected = type_resolver
1115 .get_type_info_by_name("owner", "StructA")
1116 .unwrap();
1117 let foreign = type_resolver
1118 .get_type_info_by_name("owner", "StructB")
1119 .unwrap();
1120 let config = Config::default();
1121
1122 let unknown = named_struct_meta("owner", "Unknown", "remote");
1123 let mut unknown_resolver = MetaReaderResolver::default();
1124 let error = read_type_def_for(
1125 &mut unknown_resolver,
1126 &config,
1127 &type_resolver,
1128 &expected,
1129 unknown.get_bytes(),
1130 )
1131 .unwrap_err();
1132 assert!(error.to_string().contains("does not match declared target"));
1133 assert!(unknown_resolver.reading_type_infos.is_empty());
1134 assert!(unknown_resolver.parsed_type_infos.is_empty());
1135 assert!(unknown_resolver.cached_type_info.is_none());
1136 assert!(unknown_resolver.remote_schema_versions_by_type.is_empty());
1137 assert_eq!(unknown_resolver.total_accepted_schema_versions, 0);
1138
1139 let mut structural_stub_resolver = MetaReaderResolver::default();
1140 let structural_stub = read_struct_type_def_for(
1141 &mut structural_stub_resolver,
1142 &config,
1143 &type_resolver,
1144 &expected,
1145 unknown.get_bytes(),
1146 )
1147 .unwrap();
1148 assert!(structural_stub.get_harness().target_type_id().is_none());
1149 assert_eq!(structural_stub_resolver.reading_type_infos.len(), 1);
1150 assert_eq!(structural_stub_resolver.parsed_type_infos.len(), 1);
1151 assert_eq!(structural_stub_resolver.total_accepted_schema_versions, 1);
1152
1153 let non_struct_meta = [
1154 (TypeId::NAMED_EXT, "UnknownExt"),
1155 (TypeId::NAMED_ENUM, "UnknownEnum"),
1156 (TypeId::NAMED_UNION, "UnknownUnion"),
1157 ];
1158 for (type_id, type_name) in non_struct_meta {
1159 let remote = named_meta(type_id, "remote", type_name, vec![]);
1160 let mut resolver = MetaReaderResolver::default();
1161 let error = read_struct_type_def_for(
1162 &mut resolver,
1163 &config,
1164 &type_resolver,
1165 &expected,
1166 remote.get_bytes(),
1167 )
1168 .unwrap_err();
1169 assert!(error.to_string().contains("not structural metadata"));
1170 assert!(resolver.reading_type_infos.is_empty());
1171 assert!(resolver.parsed_type_infos.is_empty());
1172 assert!(resolver.cached_type_info.is_none());
1173 assert!(resolver.remote_schema_versions_by_type.is_empty());
1174 assert_eq!(resolver.total_accepted_schema_versions, 0);
1175 }
1176
1177 let same_name_ext = named_meta(TypeId::NAMED_EXT, "owner", "StructA", vec![]);
1178 for structural in [false, true] {
1179 let mut resolver = MetaReaderResolver::default();
1180 let result = if structural {
1181 read_struct_type_def_for(
1182 &mut resolver,
1183 &config,
1184 &type_resolver,
1185 &expected,
1186 same_name_ext.get_bytes(),
1187 )
1188 } else {
1189 read_type_def_with_type_resolver(
1190 &mut resolver,
1191 &config,
1192 &type_resolver,
1193 same_name_ext.get_bytes(),
1194 )
1195 };
1196 let error = result.unwrap_err();
1197 assert!(
1198 error
1199 .to_string()
1200 .contains("kind does not match registered type metadata"),
1201 "{error}"
1202 );
1203 assert!(resolver.reading_type_infos.is_empty());
1204 assert!(resolver.parsed_type_infos.is_empty());
1205 assert!(resolver.cached_type_info.is_none());
1206 assert!(resolver.remote_schema_versions_by_type.is_empty());
1207 assert_eq!(resolver.total_accepted_schema_versions, 0);
1208 }
1209
1210 let unknown_ext = named_meta(TypeId::NAMED_EXT, "remote", "CachedExt", vec![]);
1211 let mut ext_resolver = MetaReaderResolver::default();
1212 let ext_info = read_type_def_with_type_resolver(
1213 &mut ext_resolver,
1214 &config,
1215 &type_resolver,
1216 unknown_ext.get_bytes(),
1217 )
1218 .unwrap();
1219 assert!(ext_info.get_harness().target_type_id().is_none());
1220 let mut ref_bytes = vec![];
1221 Writer::from_buffer(&mut ref_bytes).write_var_u32(1);
1222 let mut ref_reader = Reader::new(&ref_bytes);
1223 let error = ext_resolver
1224 .read_struct_type_meta_for(&mut ref_reader, &type_resolver, &config, &expected)
1225 .unwrap_err();
1226 assert!(error.to_string().contains("not structural metadata"));
1227 assert_eq!(ext_resolver.reading_type_infos.len(), 1);
1228 assert_eq!(ext_resolver.parsed_type_infos.len(), 1);
1229 assert_eq!(ext_resolver.total_accepted_schema_versions, 1);
1230
1231 ext_resolver.reset();
1232 let parsed_count = ext_resolver.parsed_type_infos.len();
1233 let accepted_versions = ext_resolver.total_accepted_schema_versions;
1234 let cached_hash = ext_resolver.cached_meta_hash;
1235 let cached_owner = ext_resolver.cached_type_info.as_ref().map(Rc::as_ptr);
1236 let error = read_struct_type_def_for(
1237 &mut ext_resolver,
1238 &config,
1239 &type_resolver,
1240 &expected,
1241 unknown_ext.get_bytes(),
1242 )
1243 .unwrap_err();
1244 assert!(error.to_string().contains("not structural metadata"));
1245 assert!(ext_resolver.reading_type_infos.is_empty());
1246 assert_eq!(ext_resolver.parsed_type_infos.len(), parsed_count);
1247 assert_eq!(
1248 ext_resolver.total_accepted_schema_versions,
1249 accepted_versions
1250 );
1251 assert_eq!(ext_resolver.cached_meta_hash, cached_hash);
1252 assert_eq!(
1253 ext_resolver.cached_type_info.as_ref().map(Rc::as_ptr),
1254 cached_owner
1255 );
1256
1257 let changed_foreign = named_struct_meta("owner", "StructB", "remote_b");
1258 assert_ne!(
1259 changed_foreign.get_hash(),
1260 foreign.get_type_meta_ref().get_hash()
1261 );
1262 let mut miss_resolver = MetaReaderResolver::default();
1263 let error = read_type_def_for(
1264 &mut miss_resolver,
1265 &config,
1266 &type_resolver,
1267 &expected,
1268 changed_foreign.get_bytes(),
1269 )
1270 .unwrap_err();
1271 assert!(error.to_string().contains("does not match declared target"));
1272 assert!(miss_resolver.reading_type_infos.is_empty());
1273 assert!(miss_resolver.parsed_type_infos.is_empty());
1274 assert!(miss_resolver.cached_type_info.is_none());
1275 assert!(miss_resolver.remote_schema_versions_by_type.is_empty());
1276 assert_eq!(miss_resolver.total_accepted_schema_versions, 0);
1277
1278 let mut structural_miss_resolver = MetaReaderResolver::default();
1279 let error = read_struct_type_def_for(
1280 &mut structural_miss_resolver,
1281 &config,
1282 &type_resolver,
1283 &expected,
1284 changed_foreign.get_bytes(),
1285 )
1286 .unwrap_err();
1287 assert!(error.to_string().contains("does not match declared target"));
1288 assert!(structural_miss_resolver.reading_type_infos.is_empty());
1289 assert!(structural_miss_resolver.parsed_type_infos.is_empty());
1290 assert!(structural_miss_resolver.cached_type_info.is_none());
1291 assert!(structural_miss_resolver
1292 .remote_schema_versions_by_type
1293 .is_empty());
1294 assert_eq!(structural_miss_resolver.total_accepted_schema_versions, 0);
1295
1296 let mut ref_resolver = MetaReaderResolver::default();
1297 let resolved = read_type_def_with_type_resolver(
1298 &mut ref_resolver,
1299 &config,
1300 &type_resolver,
1301 foreign.get_type_meta_ref().get_bytes(),
1302 )
1303 .unwrap();
1304 assert!(Rc::ptr_eq(&resolved, &foreign));
1305 let mut ref_bytes = vec![];
1306 Writer::from_buffer(&mut ref_bytes).write_var_u32(1);
1307 let mut ref_reader = Reader::new(&ref_bytes);
1308 let error = ref_resolver
1309 .read_type_meta_for(&mut ref_reader, &type_resolver, &config, &expected)
1310 .unwrap_err();
1311 assert!(error.to_string().contains("does not match declared target"));
1312 assert_eq!(ref_resolver.reading_type_infos.len(), 1);
1313 assert!(ref_resolver.parsed_type_infos.is_empty());
1314 assert!(ref_resolver.cached_type_info.is_none());
1315 assert_eq!(ref_resolver.total_accepted_schema_versions, 0);
1316
1317 let mut cache_resolver = MetaReaderResolver::default();
1318 let cached = read_type_def_with_type_resolver(
1319 &mut cache_resolver,
1320 &config,
1321 &type_resolver,
1322 changed_foreign.get_bytes(),
1323 )
1324 .unwrap();
1325 assert_eq!(
1326 cached.get_harness().target_type_id(),
1327 foreign.get_harness().target_type_id()
1328 );
1329 cache_resolver.reset();
1330 let parsed_count = cache_resolver.parsed_type_infos.len();
1331 let accepted_versions = cache_resolver.total_accepted_schema_versions;
1332 let cached_hash = cache_resolver.cached_meta_hash;
1333 let cached_owner = cache_resolver.cached_type_info.as_ref().map(Rc::as_ptr);
1334 let error = read_type_def_for(
1335 &mut cache_resolver,
1336 &config,
1337 &type_resolver,
1338 &expected,
1339 changed_foreign.get_bytes(),
1340 )
1341 .unwrap_err();
1342 assert!(error.to_string().contains("does not match declared target"));
1343 assert!(cache_resolver.reading_type_infos.is_empty());
1344 assert_eq!(cache_resolver.parsed_type_infos.len(), parsed_count);
1345 assert_eq!(
1346 cache_resolver.total_accepted_schema_versions,
1347 accepted_versions
1348 );
1349 assert_eq!(cache_resolver.cached_meta_hash, cached_hash);
1350 assert_eq!(
1351 cache_resolver.cached_type_info.as_ref().map(Rc::as_ptr),
1352 cached_owner
1353 );
1354 }
1355
1356 #[test]
1357 fn type_meta_field_limit_rejects_large_struct() {
1358 let meta = TypeMeta::new(
1359 TypeId::STRUCT as u32,
1360 9001,
1361 MetaString::get_empty().clone(),
1362 MetaString::get_empty().clone(),
1363 false,
1364 vec![
1365 FieldInfo::new("a", FieldType::new(crate::type_id::INT32, false, vec![])),
1366 FieldInfo::new("b", FieldType::new(crate::type_id::INT32, false, vec![])),
1367 ],
1368 )
1369 .unwrap();
1370 let config = Config {
1371 max_type_fields: 1,
1372 ..Default::default()
1373 };
1374 let err = read_type_def(
1375 &mut MetaReaderResolver::default(),
1376 &config,
1377 meta.get_bytes(),
1378 )
1379 .unwrap_err()
1380 .to_string();
1381 assert!(err.contains("max_type_fields"));
1382 }
1383
1384 #[test]
1385 fn type_meta_body_limit_rejects_large_metadata() {
1386 let meta = TypeMeta::new(
1387 TypeId::STRUCT as u32,
1388 9001,
1389 MetaString::get_empty().clone(),
1390 MetaString::get_empty().clone(),
1391 false,
1392 vec![FieldInfo::new(
1393 "a",
1394 FieldType::new(crate::type_id::INT32, false, vec![]),
1395 )],
1396 )
1397 .unwrap();
1398 let config = Config {
1399 max_type_meta_bytes: 1,
1400 ..Default::default()
1401 };
1402 let err = read_type_def(
1403 &mut MetaReaderResolver::default(),
1404 &config,
1405 meta.get_bytes(),
1406 )
1407 .unwrap_err()
1408 .to_string();
1409 assert!(err.contains("max_type_meta_bytes"));
1410 }
1411
1412 #[test]
1413 fn schema_limit_tracks_unknown_struct_types_separately() {
1414 fn type_def(user_type_id: u32, field_name: &str) -> Vec<u8> {
1415 TypeMeta::new(
1416 TypeId::STRUCT as u32,
1417 user_type_id,
1418 MetaString::get_empty().clone(),
1419 MetaString::get_empty().clone(),
1420 false,
1421 vec![FieldInfo::new(
1422 field_name,
1423 FieldType::new(crate::type_id::INT32, false, vec![]),
1424 )],
1425 )
1426 .unwrap()
1427 .get_bytes()
1428 .to_vec()
1429 }
1430
1431 let config = Config {
1432 max_schema_versions_per_type: 1,
1433 ..Default::default()
1434 };
1435
1436 let mut resolver = MetaReaderResolver::default();
1437 read_type_def(&mut resolver, &config, &type_def(9001, "a")).unwrap();
1438 read_type_def(&mut resolver, &config, &type_def(9002, "a")).unwrap();
1439
1440 let err = read_type_def(&mut resolver, &config, &type_def(9001, "b"))
1441 .unwrap_err()
1442 .to_string();
1443 assert!(err.contains("max_schema_versions_per_type"));
1444 }
1445
1446 #[test]
1447 fn schema_limit_rejects_extra_versions_for_type() {
1448 let meta = TypeMeta::new(
1449 TypeId::STRUCT as u32,
1450 9001,
1451 MetaString::get_empty().clone(),
1452 MetaString::get_empty().clone(),
1453 false,
1454 vec![FieldInfo::new(
1455 "a",
1456 FieldType::new(crate::type_id::INT32, false, vec![]),
1457 )],
1458 )
1459 .unwrap();
1460 let type_def = meta.get_bytes().to_vec();
1461
1462 let config = Config {
1463 max_schema_versions_per_type: 1,
1464 ..Default::default()
1465 };
1466 let mut resolver = MetaReaderResolver::default();
1467 let mut bytes = vec![];
1468 let mut writer = Writer::from_buffer(&mut bytes);
1469 writer.write_var_u32(0);
1470 writer.write_bytes(&type_def);
1471 let mut reader = Reader::new(&bytes);
1472 resolver
1473 .read_type_meta(&mut reader, &TypeResolver::default(), &config)
1474 .unwrap();
1475
1476 let changed = TypeMeta::new(
1477 TypeId::STRUCT as u32,
1478 9001,
1479 MetaString::get_empty().clone(),
1480 MetaString::get_empty().clone(),
1481 false,
1482 vec![FieldInfo::new(
1483 "b",
1484 FieldType::new(crate::type_id::INT32, false, vec![]),
1485 )],
1486 )
1487 .unwrap();
1488 let mut bytes = vec![];
1489 let mut writer = Writer::from_buffer(&mut bytes);
1490 writer.write_var_u32(0);
1491 writer.write_bytes(changed.get_bytes());
1492 let mut reader = Reader::new(&bytes);
1493 let err = resolver
1494 .read_type_meta(&mut reader, &TypeResolver::default(), &config)
1495 .unwrap_err()
1496 .to_string();
1497 assert!(err.contains("max_schema_versions_per_type"));
1498 }
1499
1500 #[test]
1501 fn schema_limit_check_is_not_recorded() {
1502 let config = Config {
1503 max_schema_versions_per_type: 1,
1504 ..Default::default()
1505 };
1506 let mut resolver = MetaReaderResolver::default();
1507 let checked = TypeMeta::new(
1508 TypeId::STRUCT as u32,
1509 9001,
1510 MetaString::get_empty().clone(),
1511 MetaString::get_empty().clone(),
1512 false,
1513 vec![FieldInfo::new(
1514 "a",
1515 FieldType::new(crate::type_id::INT32, false, vec![]),
1516 )],
1517 )
1518 .unwrap();
1519 let accepted = TypeMeta::new(
1520 TypeId::STRUCT as u32,
1521 9001,
1522 MetaString::get_empty().clone(),
1523 MetaString::get_empty().clone(),
1524 false,
1525 vec![FieldInfo::new(
1526 "b",
1527 FieldType::new(crate::type_id::INT32, false, vec![]),
1528 )],
1529 )
1530 .unwrap();
1531
1532 resolver
1533 .check_remote_type_meta_limit(&checked, &config)
1534 .unwrap();
1535
1536 let mut bytes = vec![];
1537 let mut writer = Writer::from_buffer(&mut bytes);
1538 writer.write_var_u32(0);
1539 writer.write_bytes(accepted.get_bytes());
1540 let mut reader = Reader::new(&bytes);
1541 resolver
1542 .read_type_meta(&mut reader, &TypeResolver::default(), &config)
1543 .unwrap();
1544 }
1545
1546 #[test]
1547 fn non_struct_type_meta_uses_limit() {
1548 let config = Config {
1549 max_schema_versions_per_type: 1,
1550 ..Default::default()
1551 };
1552 let mut resolver = MetaReaderResolver::default();
1553 let namespace = NAMESPACE_ENCODER
1554 .encode_with_encodings("example", NAMESPACE_ENCODINGS)
1555 .unwrap();
1556 let type_name = TYPE_NAME_ENCODER
1557 .encode_with_encodings("RemoteEnum", TYPE_NAME_ENCODINGS)
1558 .unwrap();
1559 let first = TypeMeta::new(
1560 TypeId::NAMED_ENUM as u32,
1561 NO_USER_TYPE_ID,
1562 namespace.clone(),
1563 type_name.clone(),
1564 true,
1565 vec![],
1566 )
1567 .unwrap();
1568 let second = TypeMeta::new(
1569 TypeId::NAMED_EXT as u32,
1570 NO_USER_TYPE_ID,
1571 namespace,
1572 type_name,
1573 true,
1574 vec![],
1575 )
1576 .unwrap();
1577
1578 let key = resolver
1579 .check_remote_type_meta_limit(&first, &config)
1580 .unwrap();
1581 resolver.record_remote_type_meta(key);
1582
1583 let err = resolver
1584 .check_remote_type_meta_limit(&second, &config)
1585 .unwrap_err()
1586 .to_string();
1587 assert!(err.contains("max_schema_versions_per_type"));
1588 }
1589
1590 #[test]
1591 fn exact_local_non_struct_type_meta_bypasses_limit() {
1592 let config = Config {
1593 max_schema_versions_per_type: 1,
1594 ..Default::default()
1595 };
1596 let mut type_resolver = TypeResolver::default();
1597 type_resolver
1598 .register_serializer_by_name::<LocalExt>("example.SharedExt")
1599 .unwrap();
1600 let type_resolver = type_resolver.build_final_type_resolver().unwrap();
1601 let local_info = type_resolver
1602 .get_type_info_by_name("example", "SharedExt")
1603 .unwrap();
1604 let exact = local_info.get_type_meta_ref().get_bytes().to_vec();
1605
1606 let mut resolver = MetaReaderResolver::default();
1607 read_type_def_with_type_resolver(&mut resolver, &config, &type_resolver, &exact).unwrap();
1608
1609 let namespace = NAMESPACE_ENCODER
1610 .encode_with_encodings("example", NAMESPACE_ENCODINGS)
1611 .unwrap();
1612 let type_name = TYPE_NAME_ENCODER
1613 .encode_with_encodings("SharedExt", TYPE_NAME_ENCODINGS)
1614 .unwrap();
1615 let second = TypeMeta::new(
1616 TypeId::NAMED_ENUM as u32,
1617 NO_USER_TYPE_ID,
1618 namespace,
1619 type_name,
1620 true,
1621 vec![],
1622 )
1623 .unwrap();
1624 resolver
1625 .check_remote_type_meta_limit(&second, &config)
1626 .unwrap();
1627 }
1628}