1#![feature(macro_metavar_expr)]
2#![doc = include_str!("../README.md")]
3
4use siphasher::sip128::SipHasher13;
5
6mod context;
7mod generation;
8mod query;
9mod query_parameter;
10mod storage;
11
12pub use incremental_query_macros::*;
13
14pub use context::Context;
15pub use query_parameter::QueryParameter;
16pub use storage::Storage;
17
18#[doc(hidden)]
20pub use query::{ErasedQueryRun, Query, QueryMode};
21#[doc(hidden)]
22pub use query_parameter::TypeErasedQueryParam;
23
24pub type QueryHasher = SipHasher13;
25
26#[cfg(test)]
27pub fn log() {
28 use tracing_subscriber::EnvFilter;
29
30 let format = tracing_subscriber::fmt::format()
31 .without_time()
32 .with_source_location(false);
33
34 tracing_subscriber::fmt()
35 .event_format(format)
36 .with_env_filter(EnvFilter::from_default_env())
37 .try_init()
38 .ok();
39}
40
41#[cfg(test)]
42mod tests {
43 use crate::log;
44
45 use std::{
62 cell::{Cell, RefCell},
63 collections::VecDeque,
64 hash::Hash,
65 ops::Deref,
66 rc::Rc,
67 };
68
69 use crate::{
70 query, query_parameter::QueryParameter, rerun, storage::Storage, Context, QueryHasher,
71 };
72 use rand::{thread_rng, Rng};
73
74 pub mod incremental_query {
75 pub use crate::*;
76 }
77
78 #[derive(Clone)]
79 struct Counter(pub u64, Rc<Cell<usize>>);
80 impl Counter {
81 pub fn new(i: u64) -> Self {
85 Self(i, Default::default())
86 }
87
88 pub fn add(&self) {
89 self.1.set(self.1.get() + 1);
90 }
91
92 pub fn get(&self) -> usize {
93 self.1.get()
94 }
95 }
96
97 #[derive(Clone)]
98 struct ReturnInOrder<T> {
99 data: Rc<RefCell<VecDeque<T>>>,
100 id: u64,
101 }
102
103 impl<T> ReturnInOrder<T> {
104 fn new(inp: impl IntoIterator<Item = T>, id: u64) -> Self {
105 Self {
106 data: Rc::new(RefCell::new(inp.into_iter().collect())),
107 id,
108 }
109 }
110
111 fn is_empty(&self) -> bool {
112 self.data.borrow().len() == 0
113 }
114
115 fn next(&self) -> T {
116 self.data.borrow_mut().pop_front().expect("empty")
117 }
118 }
119
120 impl QueryParameter for Counter {
121 fn hash_stable(&self, hasher: &mut QueryHasher) {
122 self.0.hash(hasher);
123 }
124 }
125 impl<T: Clone + 'static> QueryParameter for ReturnInOrder<T> {
126 fn hash_stable(&self, hasher: &mut QueryHasher) {
127 self.id.hash(hasher);
128 }
129 }
130
131 #[test]
132 fn call_once() {
133 #[query]
134 fn test<'cx>(_cx: &Context<'cx>, input: &Counter) {
135 input.add();
136 }
137
138 log();
139 let storage = Storage::new();
140
141 let ctr = Counter::new(0);
142 let cx = Context::new(&storage);
143 test(&cx, ctr.clone());
144 assert_eq!(ctr.get(), 1);
145 }
146
147 #[test]
148 fn call_twice() {
149 #[query]
150 fn called_twice<#[lt] 'a>(_cx: &Context<'a>, input: &Counter) {
151 input.add();
152 }
153 log();
154
155 let storage = Storage::new();
156
157 let ctr = Counter::new(0);
158 let cx = Context::new(&storage);
159
160 called_twice(&cx, ctr.clone());
161 called_twice(&cx, ctr.clone());
162 assert_eq!(ctr.get(), 1);
163 }
164
165 #[test]
166 fn impure_rerun() {
167 #[query]
168 #[rerun(always)]
169 fn random<'cx>(_cx: &Context<'cx>) -> u64 {
170 thread_rng().gen_range(0..u64::MAX)
171 }
172
173 #[query]
174 fn depends_on_impure<'cx>(cx: &Context<'cx>, inp: &Counter) {
175 inp.add();
176 let _dep = random(cx);
177 }
178
179 log();
180
181 let storage = Storage::new();
182
183 let ctr = Counter::new(0);
184 let cx = Context::new(&storage);
185 depends_on_impure(&cx, ctr.clone());
186 depends_on_impure(&cx, ctr.clone());
187
188 assert_eq!(ctr.get(), 2);
189 }
190
191 #[test]
192 fn test_intvalue() {
193 #[query]
194 #[rerun(always)]
195 fn intvalue<'cx>(_cx: &Context<'cx>, r: &ReturnInOrder<i64>) -> i64 {
196 r.next()
197 }
198
199 #[query]
200 fn sign_of<'cx>(cx: &Context<'cx>, r: &ReturnInOrder<i64>, c2: &Counter) -> bool {
201 let v = intvalue(cx, r.clone());
202 c2.add();
203
204 v.is_positive()
205 }
206
207 #[query]
208 fn some_other_query<'cx>(
209 cx: &Context<'cx>,
210 r: &ReturnInOrder<i64>,
211 c1: &Counter,
212 c2: &Counter,
213 ) {
214 c1.add();
215 sign_of(cx, r.clone(), c2.clone());
216 }
217 log();
218
219 let storage = Storage::new();
220
221 let order = ReturnInOrder::new(vec![1000, 2000, 2000], 1);
227 let counter1 = Counter::new(1);
228 let counter2 = Counter::new(2);
229 let cx = Context::new(&storage);
230
231 some_other_query(&cx, order.clone(), counter1.clone(), counter2.clone());
232 some_other_query(&cx, order.clone(), counter1.clone(), counter2.clone());
233
234 assert!(order.is_empty());
235 assert_eq!(counter1.get(), 1);
236 assert_eq!(counter2.get(), 2);
237 }
238
239 #[test]
240 fn test_intvalue_generational() {
241 #[query]
242 #[rerun(generation)]
243 fn intvalue<'cx>(_cx: &Context<'cx>, r: &ReturnInOrder<i64>) -> i64 {
244 r.next()
245 }
246
247 #[query]
248 fn sign_of<'cx>(cx: &Context<'cx>, r: &ReturnInOrder<i64>, c2: &Counter) -> bool {
249 let v = intvalue(cx, r.clone());
250 c2.add();
251
252 v.is_positive()
253 }
254
255 #[query]
256 fn some_other_query<'cx>(
257 cx: &Context<'cx>,
258 r: &ReturnInOrder<i64>,
259 c1: &Counter,
260 c2: &Counter,
261 ) {
262 c1.add();
263 sign_of(cx, r.clone(), c2.clone());
264 }
265 log();
266
267 let storage = Storage::new();
268
269 let order = ReturnInOrder::new(vec![1000, 2000], 1);
272 let counter1 = Counter::new(1);
273 let counter2 = Counter::new(2);
274 let cx = Context::new(&storage);
275
276 some_other_query(&cx, order.clone(), counter1.clone(), counter2.clone());
277 cx.next_generation();
278 some_other_query(&cx, order.clone(), counter1.clone(), counter2.clone());
279
280 assert!(order.is_empty());
281 assert_eq!(counter1.get(), 1);
282 assert_eq!(counter2.get(), 2);
283 }
284
285 #[test]
286 fn test_intvalue_many_generation() {
287 #[query]
288 #[rerun(generation)]
289 fn intvalue<'cx>(_cx: &Context<'cx>, r: &ReturnInOrder<i64>) -> i64 {
290 r.next()
291 }
292
293 #[query]
294 fn sign_of<'cx>(cx: &Context<'cx>, r: &ReturnInOrder<i64>, c2: &Counter) -> bool {
295 let v = intvalue(cx, r.clone());
296 c2.add();
297
298 v.is_positive()
299 }
300
301 #[query]
302 fn some_other_query<'cx>(
303 cx: &Context<'cx>,
304 r: &ReturnInOrder<i64>,
305 c1: &Counter,
306 c2: &Counter,
307 ) {
308 c1.add();
309 sign_of(cx, r.clone(), c2.clone());
310 }
311 log();
312
313 let storage = Storage::new();
314
315 let order = ReturnInOrder::new(vec![1000, 2000, 3000], 1);
318 let counter1 = Counter::new(1);
319 let counter2 = Counter::new(2);
320 let cx = Context::new(&storage);
321
322 some_other_query(&cx, order.clone(), counter1.clone(), counter2.clone());
323 cx.next_generation();
324 some_other_query(&cx, order.clone(), counter1.clone(), counter2.clone());
325 cx.next_generation();
326 some_other_query(&cx, order.clone(), counter1.clone(), counter2.clone());
327
328 assert!(order.is_empty());
329 assert_eq!(counter1.get(), 1);
330 assert_eq!(counter2.get(), 3);
331 }
332
333 #[test]
334 fn test_intvalue_assume_pure_wrong() {
335 #[query]
336 fn intvalue<'cx>(_cx: &Context<'cx>, r: &ReturnInOrder<i64>) -> i64 {
337 r.next()
338 }
339
340 #[query]
341 fn sign_of<'cx>(cx: &Context<'cx>, r: &ReturnInOrder<i64>, c2: &Counter) -> bool {
342 let v = intvalue(cx, r.clone());
343 c2.add();
344
345 v.is_positive()
346 }
347
348 #[query]
349 fn some_other_query<'cx>(
350 cx: &Context<'cx>,
351 r: &ReturnInOrder<i64>,
352 c1: &Counter,
353 c2: &Counter,
354 ) {
355 c1.add();
356 sign_of(cx, r.clone(), c2.clone());
357 }
358 log();
359
360 let storage = Storage::new();
361
362 let order = ReturnInOrder::new(vec![1000, 2000], 1);
365 let counter1 = Counter::new(1);
366 let counter2 = Counter::new(2);
367 let cx = Context::new(&storage);
368
369 some_other_query(&cx, order.clone(), counter1.clone(), counter2.clone());
370 some_other_query(&cx, order.clone(), counter1.clone(), counter2.clone());
371
372 assert!(!order.is_empty());
373 assert_eq!(counter1.get(), 1);
374 assert_eq!(counter2.get(), 1);
375 }
376
377 #[test]
378 fn conditional_query() {
379 #[query]
380 #[rerun(generation)]
381 fn boolean_query<'cx>(_cx: &Context<'cx>, r: &ReturnInOrder<bool>) -> bool {
382 r.next()
383 }
384
385 #[query]
386 fn one<'cx>(_cx: &Context<'cx>) -> u64 {
387 1
388 }
389 #[query]
390 fn two<'cx>(_cx: &Context<'cx>, c: &Counter) -> u64 {
391 c.add();
392 2
393 }
394
395 #[query]
396 fn conditional<'cx>(cx: &Context<'cx>, r: &ReturnInOrder<bool>, c: &Counter) -> u64 {
397 if *boolean_query(cx, r.clone()) {
398 *one(cx)
399 } else {
400 *two(cx, c.clone())
401 }
402 }
403
404 log();
405
406 let storage = Storage::new();
407 let order = ReturnInOrder::new(vec![true, false], 1);
408 let counter = Counter::new(0);
409 let cx = Context::new(&storage);
410
411 assert_eq!(conditional(&cx, order.clone(), counter.clone()), &1);
412 cx.next_generation();
413 assert_eq!(conditional(&cx, order.clone(), counter.clone()), &2);
414 assert_eq!(conditional(&cx, order.clone(), counter.clone()), &2);
415 assert_eq!(conditional(&cx, order.clone(), counter.clone()), &2);
416 assert_eq!(counter.get(), 1);
417 assert!(order.is_empty())
418 }
419
420 #[test]
421 #[should_panic]
422 fn cycle() {
423 #[query]
424 fn cyclic<'cx>(cx: &Context<'cx>, r: &u64) -> bool {
425 *cyclic(cx, *r)
426 }
427
428 log();
429
430 let storage = Storage::new();
431 let cx = Context::new(&storage);
432 cyclic(&cx, 10);
433 }
434
435 #[test]
436 #[should_panic]
437 fn long_cycle() {
438 #[query]
439 fn e<'cx>(cx: &Context<'cx, i64>, r: &u64) -> bool {
440 *a(cx, *r)
441 }
442
443 #[query]
444 fn d<'cx>(cx: &Context<'cx, i64>, r: &u64) -> bool {
445 *e(cx, *r)
446 }
447
448 #[query]
449 fn c<'cx>(cx: &Context<'cx, i64>, r: &u64) -> bool {
450 *d(cx, *r)
451 }
452
453 #[query]
454 fn b<'cx>(cx: &Context<'cx, i64>, r: &u64) -> bool {
455 *c(cx, *r)
456 }
457
458 #[query]
459 fn a<'cx>(cx: &Context<'cx, i64>, r: &u64) -> bool {
460 *b(cx, *r)
461 }
462 log();
463
464 let storage = Storage::new();
465 let cx = Context::with_data(&storage, 12);
466 a(&cx, 10);
467 assert_eq!(cx.deref(), &12);
468 }
469
470 #[test]
471 fn garbage_collect() {
472 #[query]
473 fn value_dependent<'cx>(_cx: &Context<'cx>, r: &i64) -> i64 {
474 r * 2
475 }
476
477 #[query]
478 #[rerun(generation)]
479 fn intvalue<'cx>(_cx: &Context<'cx>, r: &ReturnInOrder<i64>) -> i64 {
480 r.next()
481 }
482
483 #[query]
484 fn sign_of<'cx>(cx: &Context<'cx>, r: &ReturnInOrder<i64>) -> bool {
485 let v = intvalue(cx, r.clone());
486 value_dependent(cx, *v).is_positive()
487 }
488
489 #[query]
490 fn some_other_query<'cx>(cx: &Context<'cx>, r: &ReturnInOrder<i64>) {
491 sign_of(cx, r.clone());
492 }
493 log();
494
495 const N: i64 = 1000;
496
497 let storage = Storage::new();
498
499 let mut data = Vec::new();
500 for i in 0..N {
501 data.push(i * 1000);
502 }
503
504 let order = ReturnInOrder::new(data, 1);
507 let cx = Context::new(&storage);
508
509 for _ in 0..N {
510 some_other_query(&cx, order.clone());
511 cx.next_generation();
512 }
513 assert!(order.is_empty());
514
515 let new_storage = Storage::new();
516
517 tracing::info!("{}", cx.size());
518 let res = cx.gc(&new_storage);
519 drop(storage);
520 tracing::info!("{}", res.size());
521 }
522
523 #[test]
524 fn impure_cache_rerun() {
525 #[query]
526 #[rerun(always)]
527 fn random<'cx>(_cx: &Context<'cx>) -> u64 {
528 thread_rng().gen_range(0..u64::MAX)
529 }
530
531 #[query]
532 fn depends_on_impure<'cx>(cx: &Context<'cx>, inp: &Counter) {
533 inp.add();
534 let _dep = random(&cx);
535 }
536
537 log();
538
539 let storage = Storage::new();
540
541 let ctr = Counter::new(0);
542 let cx = Context::new(&storage);
543 depends_on_impure(&cx, ctr.clone());
544 depends_on_impure(&cx, ctr.clone());
545 depends_on_impure(&cx, ctr.clone());
546 depends_on_impure(&cx, ctr.clone());
547 depends_on_impure(&cx, ctr.clone());
548
549 assert_eq!(ctr.get(), 5);
550 }
551
552 #[test]
553 fn cache_off() {
554 #[query]
556 #[inline(always)] fn random<'cx>(_cx: &Context<'cx>) -> u64 {
558 thread_rng().gen_range(0..u64::MAX)
559 }
560
561 #[query]
562 fn depends_on_impure<'cx>(cx: &Context<'cx>, inp: &Counter) {
563 inp.add();
564 let _dep = random(cx);
565 }
566
567 log();
568
569 let storage = Storage::new();
570
571 let ctr = Counter::new(0);
572 let cx = Context::new(&storage);
573 cx.set_cache_enabled(false);
574 depends_on_impure(&cx, ctr.clone());
575 depends_on_impure(&cx, ctr.clone());
576 depends_on_impure(&cx, ctr.clone());
577 depends_on_impure(&cx, ctr.clone());
578 depends_on_impure(&cx, ctr.clone());
579
580 assert_eq!(ctr.get(), 5);
581
582 let ctr = Counter::new(0);
583 let cx = Context::new(&storage);
584 cx.set_cache_enabled(true);
585 depends_on_impure(&cx, ctr.clone());
586 depends_on_impure(&cx, ctr.clone());
587 depends_on_impure(&cx, ctr.clone());
588 depends_on_impure(&cx, ctr.clone());
589 depends_on_impure(&cx, ctr.clone());
590
591 assert_eq!(ctr.get(), 1);
592 }
593}