unsafe_tools_canary/
lib.rs1#![doc = include_str!("../README.md")]
2
3use std::ops::{Deref, DerefMut};
4
5#[repr(C)]
6#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
7pub struct Canary<T, const CANARY: u64> {
8 _canary: u64,
9 inner: T,
10}
11
12impl<T, const CANARY: u64> Canary<T, CANARY> {
13 pub const fn new(inner: T) -> Self {
14 Self {
15 _canary: CANARY,
16 inner,
17 }
18 }
19
20 pub fn assert_valid(me: &Self) {
21 assert!(
22 me._canary == CANARY,
23 "canary mismatch! {} is not properly initialized (expected {CANARY} but found {})",
24 core::any::type_name::<T>(),
25 me._canary
26 );
27 }
28
29 pub fn into_inner(self) -> T {
30 self.inner
31 }
32}
33
34impl<T, const CANARY: u64> Deref for Canary<T, CANARY> {
35 type Target = T;
36
37 fn deref(&self) -> &Self::Target {
38 #[cfg(debug_assertions)]
39 Self::assert_valid(self);
40
41 &self.inner
42 }
43}
44
45impl<T, const CANARY: u64> DerefMut for Canary<T, CANARY> {
46 fn deref_mut(&mut self) -> &mut Self::Target {
47 #[cfg(debug_assertions)]
48 Self::assert_valid(self);
49
50 &mut self.inner
51 }
52}
53
54#[cfg(test)]
55mod tests {
56 use super::*;
57
58 #[test]
59 fn basically_works() {
60 const CANARY: u64 = u64::from_le_bytes(*b"testmagc");
61
62 let mut canary = Canary::<_, CANARY>::new(42);
63 assert_eq!(*canary, 42);
64 *canary += 1;
65 assert_eq!(*canary, 43);
66 }
67
68 #[test]
69 #[cfg_attr(debug_assertions, should_panic)]
70 fn panics_with_incorrect_canary() {
71 const CANARY: u64 = u64::from_le_bytes(*b"testmagc");
72
73 let mut canary = Canary::<_, CANARY>::new(42);
74 canary._canary = 10;
75 assert_eq!(*canary, 42);
76 }
77}