incremental_query/
query_parameter.rs1use std::{
2 hash::{Hash, Hasher},
3 marker::PhantomData,
4 ptr::NonNull,
5 rc::Rc,
6};
7
8use super::{storage::Storage, QueryHasher};
9
10pub 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 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 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}