incremental_query/
query_parameter.rs

1use std::{
2    hash::{Hash, Hasher},
3    marker::PhantomData,
4    ptr::NonNull,
5    rc::Rc,
6};
7
8use super::{storage::Storage, QueryHasher};
9
10/// Query parameters should be hashable and clonable.
11///
12/// The hash infrastructure is part of this trait itself, because
13/// it's not unlikely you want to hash the elements you pass into
14/// queries in a different way than they are hashed by default.
15pub trait QueryParameter: Sized + Clone + 'static {
16    fn hash_stable(&self, hasher: &mut QueryHasher);
17
18    fn get_clone<'cx>() -> TypeErasedCloneFn<'cx>
19    where
20        Self: 'cx,
21    {
22        fn clone<'a, T: QueryParameter>(
23            this: TypeErasedQueryParam,
24            storage: &'a Storage,
25        ) -> TypeErasedQueryParam<'a> {
26            // safety: T == Self, this clone function clones self
27            let this_ref = unsafe { this.get_ref::<T>() };
28            let new_this = this_ref.clone();
29            let new_ref = storage.alloc(new_this);
30            TypeErasedQueryParam::new(new_ref)
31        }
32
33        clone::<Self>
34    }
35}
36
37impl<T> QueryParameter for Option<T>
38where
39    T: QueryParameter,
40{
41    fn hash_stable(&self, hasher: &mut QueryHasher) {
42        self.is_some().hash(hasher);
43        if let Some(i) = self {
44            T::hash_stable(i, hasher);
45        }
46    }
47}
48impl<T> QueryParameter for Box<T>
49where
50    T: QueryParameter,
51{
52    fn hash_stable(&self, hasher: &mut QueryHasher) {
53        T::hash_stable(self, hasher)
54    }
55}
56impl<T> QueryParameter for Rc<T>
57where
58    T: QueryParameter,
59{
60    fn hash_stable(&self, hasher: &mut QueryHasher) {
61        T::hash_stable(self, hasher)
62    }
63}
64impl QueryParameter for () {
65    fn hash_stable(&self, _hasher: &mut QueryHasher) {}
66}
67
68type TypeErasedCloneFn<'cx> =
69    for<'a> fn(this: TypeErasedQueryParam<'cx>, &'a Storage) -> TypeErasedQueryParam<'a>;
70
71#[derive(Copy, Clone)]
72pub struct TypeErasedQueryParam<'cx> {
73    ptr: NonNull<()>,
74    clone: TypeErasedCloneFn<'cx>,
75    phantom: PhantomData<&'cx ()>,
76}
77
78impl<'cx> TypeErasedQueryParam<'cx> {
79    pub fn new<Q: QueryParameter>(inp: &'cx Q) -> Self {
80        TypeErasedQueryParam {
81            ptr: std::ptr::NonNull::from(inp).cast(),
82            clone: Q::get_clone(),
83            phantom: PhantomData,
84        }
85    }
86
87    pub fn get_ptr(&self) -> NonNull<()> {
88        self.ptr
89    }
90
91    /// Convert this pointer to a query parameter,
92    /// into a reference to a concrete query parameter
93    ///
94    /// # Safety
95    /// unsound unless T is the original type of this query parameter
96    pub unsafe fn get_ref<T>(&self) -> &'cx T {
97        &*self.ptr.as_ptr().cast()
98    }
99
100    pub fn deep_clone<'a>(&self, storage: &'a Storage) -> TypeErasedQueryParam<'a> {
101        (self.clone)(*self, storage)
102    }
103}
104
105macro_rules! count {
106    () => (0usize);
107    ( $x:tt $($xs:tt)* ) => (1usize + count!($($xs)*));
108}
109
110macro_rules! replace_expr {
111    ($_t:tt $sub:expr) => {
112        $sub
113    };
114}
115
116macro_rules! map {
117    (let $name: ident; $e: expr; $tup: ident; $($items: tt)*) => {
118        $(
119            let $name = replace_expr!($items &$tup.${index()});
120            $e;
121        )*
122    };
123}
124
125macro_rules! impl_query_parameter {
126    () => {};
127    ($first: ident $($rest: ident)*) => {
128        impl<$first: QueryParameter, $($rest: QueryParameter),*> QueryParameter for ($first, $($rest),*) {
129            fn hash_stable(&self, hasher: &mut $crate::QueryHasher) {
130                hasher.write_usize(count!($first $($rest)*));
131
132                map!(let x; x.hash_stable(hasher); self; $first $($rest)*);
133            }
134        }
135
136        impl_query_parameter!($($rest)*);
137    };
138}
139
140impl_query_parameter!(
141    T1 T2 T3 T4 T5 T6
142);
143
144macro_rules! impl_integers {
145    ($($ty: ty => $name: ident),* $(,)?) => {
146        $(
147            impl QueryParameter for $ty {
148                fn hash_stable(&self, hasher: &mut $crate::QueryHasher) {
149                    hasher.$name(*self);
150                }
151            }
152        )*
153    };
154}
155
156impl_integers!(
157    usize => write_usize,
158    isize => write_isize,
159
160    u64 => write_u64,
161    u32 => write_u32,
162    u16 => write_u16,
163    u8 => write_u8,
164
165    i64 => write_i64,
166    i32 => write_i32,
167    i16 => write_i16,
168    i8 => write_i8,
169);
170
171impl QueryParameter for bool {
172    fn hash_stable(&self, hasher: &mut QueryHasher) {
173        hasher.write_u8(*self as u8);
174    }
175}