rkyv_test/validation/validators/
shared.rs

1//! Validators add validation capabilities by wrapping and extending basic validators.
2
3use 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/// Errors that can occur when checking shared memory.
12#[derive(Debug)]
13pub enum SharedError {
14    /// Multiple pointers exist to the same location with different types
15    TypeMismatch {
16        /// A previous type that the location was checked as
17        previous: TypeId,
18        /// The current type that the location is checked as
19        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/// A validator that can verify shared memory.
50#[derive(Debug)]
51pub struct SharedValidator {
52    shared: HashMap<*const u8, TypeId>,
53}
54
55// SAFETY: SharedValidator is safe to send to another thread
56// This trait is not automatically implemented because the struct contains a pointer
57unsafe impl Send for SharedValidator {}
58
59// SAFETY: SharedValidator is safe to share between threads
60// This trait is not automatically implemented because the struct contains a pointer
61unsafe impl Sync for SharedValidator {}
62
63impl SharedValidator {
64    /// Wraps the given context and adds shared memory validation.
65    #[inline]
66    pub fn new() -> Self {
67        Self {
68            // TODO: consider deferring this to avoid the overhead of constructing
69            shared: HashMap::new(),
70        }
71    }
72}
73
74impl Default for SharedValidator {
75    #[inline]
76    fn default() -> Self {
77        Self::new()
78    }
79}
80
81impl Fallible for SharedValidator {
82    type Error = SharedError;
83}
84
85impl SharedContext for SharedValidator {
86    #[inline]
87    fn register_shared_ptr(
88        &mut self,
89        ptr: *const u8,
90        type_id: TypeId,
91    ) -> Result<bool, Self::Error> {
92        if let Some(previous_type_id) = self.shared.get(&ptr) {
93            if previous_type_id != &type_id {
94                Err(SharedError::TypeMismatch {
95                    previous: *previous_type_id,
96                    current: type_id,
97                })
98            } else {
99                Ok(false)
100            }
101        } else {
102            self.shared.insert(ptr, type_id);
103            Ok(true)
104        }
105    }
106}