rkyv/validation/validators/
shared.rs1use crate::{validation::SharedContext, Fallible};
4use core::{any::TypeId, fmt};
5
6#[cfg(not(feature = "std"))]
7use hashbrown::HashMap;
8#[cfg(feature = "std")]
9use std::collections::HashMap;
10
11#[derive(Debug)]
13pub enum SharedError {
14 TypeMismatch {
16 previous: TypeId,
18 current: TypeId,
20 },
21}
22
23impl fmt::Display for SharedError {
24 #[inline]
25 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
26 match self {
27 SharedError::TypeMismatch { previous, current } => write!(
28 f,
29 "the same memory region has been claimed as two different types ({:?} and {:?})",
30 previous, current
31 ),
32 }
33 }
34}
35
36#[cfg(feature = "std")]
37const _: () = {
38 use std::error::Error;
39
40 impl Error for SharedError {
41 fn source(&self) -> Option<&(dyn Error + 'static)> {
42 match self {
43 SharedError::TypeMismatch { .. } => None,
44 }
45 }
46 }
47};
48
49#[derive(Debug)]
51pub struct SharedValidator {
52 shared: HashMap<*const u8, TypeId>,
53}
54
55unsafe impl Send for SharedValidator {}
58
59unsafe impl Sync for SharedValidator {}
62
63impl SharedValidator {
64 #[inline]
66 pub fn new() -> Self {
67 Self {
68 shared: HashMap::new(),
70 }
71 }
72
73 #[inline]
75 pub fn with_capacity(capacity: usize) -> Self {
76 Self {
77 shared: HashMap::with_capacity(capacity),
78 }
79 }
80}
81
82impl Default for SharedValidator {
83 #[inline]
84 fn default() -> Self {
85 Self::new()
86 }
87}
88
89impl Fallible for SharedValidator {
90 type Error = SharedError;
91}
92
93impl SharedContext for SharedValidator {
94 #[inline]
95 fn register_shared_ptr(
96 &mut self,
97 ptr: *const u8,
98 type_id: TypeId,
99 ) -> Result<bool, Self::Error> {
100 #[cfg(not(feature = "std"))]
101 use hashbrown::hash_map::Entry;
102 #[cfg(feature = "std")]
103 use std::collections::hash_map::Entry;
104
105 match self.shared.entry(ptr) {
106 Entry::Occupied(previous_type_entry) => {
107 let previous_type_id = previous_type_entry.get();
108 if previous_type_id != &type_id {
109 Err(SharedError::TypeMismatch {
110 previous: *previous_type_id,
111 current: type_id,
112 })
113 } else {
114 Ok(false)
115 }
116 }
117 Entry::Vacant(ent) => {
118 ent.insert(type_id);
119 Ok(true)
120 }
121 }
122 }
123}