verde/internal/db.rs
1use std::{
2 any::TypeId,
3 borrow::Borrow,
4 cell::{Cell, RefCell},
5 hash::Hash,
6 mem::MaybeUninit,
7};
8
9use rustc_hash::{FxHashMap, FxHashSet};
10
11use crate::{
12 internal::{
13 storage::{interned, tracked, ErasedId, ErasedQueryId, Route, RoutingTable, RoutingTableBuilder},
14 Query,
15 Storage,
16 },
17 span,
18 Id,
19 Interned,
20 Pushable,
21 Tracked,
22};
23
24/// A database. This trait provides most of the functionality of the concrete database type.
25pub trait Db {
26 #[doc(hidden)]
27 fn init_routing(table: &mut RoutingTableBuilder)
28 where
29 Self: Sized;
30
31 #[doc(hidden)]
32 fn routing_table(&self) -> &RoutingTable;
33
34 #[doc(hidden)]
35 fn storage_struct(&self, storage: u16) -> &dyn Storage;
36}
37
38#[doc(hidden)]
39pub struct ErasedVec {
40 bytes: [u8; std::mem::size_of::<Vec<()>>()],
41}
42
43impl ErasedVec {
44 fn new<T>() -> Self {
45 let mut bytes = [0; std::mem::size_of::<Vec<()>>()];
46 unsafe {
47 std::ptr::write(bytes.as_mut_ptr() as *mut Vec<T>, Vec::new());
48 }
49 Self { bytes }
50 }
51
52 unsafe fn as_mut<T>(&mut self) -> &mut Vec<T> { unsafe { &mut *(self.bytes.as_mut_ptr() as *mut Vec<T>) } }
53
54 pub(crate) unsafe fn into_inner<T>(self) -> Vec<T> {
55 // This transmute saves if the size of `Vec<T>` is ever different from `Vec<()>`.
56 unsafe { std::mem::transmute(self.bytes) }
57 }
58}
59
60/// A context into the database. Used by query functions to access the database.
61pub struct Ctx<'a> {
62 pub(crate) db: &'a dyn Db,
63 pub(crate) dependencies: RefCell<MaybeUninit<FxHashSet<(ErasedId, u64)>>>,
64 pub(crate) pushed: RefCell<MaybeUninit<FxHashMap<TypeId, (ErasedVec, &'static str)>>>,
65 pub(crate) curr_query: ErasedQueryId,
66 dead: Cell<bool>,
67}
68
69impl<'a> Ctx<'a> {
70 fn new(db: &'a dyn Db, curr_query: ErasedQueryId) -> Self {
71 Self {
72 db,
73 dependencies: RefCell::new(MaybeUninit::new(FxHashSet::default())),
74 pushed: RefCell::new(MaybeUninit::new(FxHashMap::default())),
75 curr_query,
76 dead: Cell::new(false),
77 }
78 }
79
80 /// Insert a tracked value. Useful for returning tracked values other than the query output. These values *must*
81 /// influence query output comparision in some way (such as being stored in it) - since changes to `insert`ed values
82 /// are not tracked as outputs.
83 ///
84 /// Unlike `set_input` called on the database, these values must be unique across only this query type, not
85 /// globally.
86 /// ```rust
87 /// # use verde::{query, Tracked, Ctx, Id, storage, db};
88 /// #[derive(Tracked, Eq, PartialEq)]
89 /// # #[cfg_attr(feature = "serde", derive(verde::serde::Serialize, verde::serde::Deserialize))]
90 /// struct S {
91 /// #[id]
92 /// id: u32,
93 /// value: u32,
94 /// }
95 ///
96 /// # #[storage]
97 /// # struct Storage(S, String, foo);
98 /// # #[db]
99 /// # struct Database(Storage);
100 /// #[query]
101 /// fn foo(ctx: &Ctx, id: Id<S>) -> S {
102 /// let s = ctx.get(id);
103 /// let s2 = ctx.insert(S { id: 0, value: 1 }); // Turns out to be same as the return value!
104 /// S {
105 /// id: s.id,
106 /// value: s.value + 1,
107 /// }
108 /// }
109 ///
110 /// # let mut db = Database::default();
111 /// # let db = &mut db as &mut dyn verde::Db;
112 /// let id = db.set_input(S { id: 0, value: 0 });
113 /// db.execute(|ctx| foo(ctx, id));
114 /// ```
115 pub fn insert<T: Tracked>(&self, value: T) -> Id<T> { self.db.insert(self.curr_query.route, value) }
116
117 /// Get a reference to the value `id` points to.
118 /// ```rust
119 /// # use verde::{query, Tracked, Ctx, Id, storage, db};
120 /// #[derive(Tracked, Eq, PartialEq)]
121 /// # #[cfg_attr(feature = "serde", derive(verde::serde::Serialize, verde::serde::Deserialize))]
122 /// struct S {
123 /// #[id]
124 /// id: u32,
125 /// value: u32,
126 /// }
127 ///
128 /// # #[storage]
129 /// # struct Storage(S, foo);
130 /// # #[db]
131 /// # struct Database(Storage);
132 /// #[query]
133 /// fn foo(ctx: &Ctx, id: Id<S>) -> S {
134 /// let s = ctx.get(id);
135 /// assert_eq!(s.value, 0);
136 /// S {
137 /// id: s.id,
138 /// value: s.value + 1,
139 /// }
140 /// }
141 ///
142 /// # let mut db = Database::default();
143 /// # let db = &mut db as &mut dyn verde::Db;
144 /// let id = db.set_input(S { id: 0, value: 0 });
145 /// db.execute(|ctx| foo(ctx, id));
146 /// ```
147 pub fn get<T: Tracked>(&self, id: Id<T>) -> tracked::Get<'_, T> {
148 let id = id.get();
149 span!(
150 enter trace,
151 "fetching value",
152 ty = std::any::type_name::<T>(),
153 id = id.index
154 );
155 unsafe {
156 let gen = self.get_generation(id);
157 self.dependencies
158 .try_borrow_mut()
159 .expect("Cannot call `get` within a `map` scope")
160 .assume_init_mut()
161 .insert((id, gen));
162 }
163 let storage = self
164 .db
165 .storage_struct(id.route.storage)
166 .tracked_storage(id.route.index)
167 .unwrap();
168 unsafe { storage.get(id.index) }
169 }
170
171 /// Get a reference to the value `id` points to.
172 /// ```rust
173 /// # use verde::{query, Tracked, Ctx, Id, storage, db};
174 /// #[derive(Tracked, Eq, PartialEq)]
175 /// # #[cfg_attr(feature = "serde", derive(verde::serde::Serialize, verde::serde::Deserialize))]
176 /// struct S {
177 /// #[id]
178 /// id: u32,
179 /// value: u32,
180 /// }
181 ///
182 /// # #[storage]
183 /// # struct Storage(S, String, foo);
184 /// # #[db]
185 /// # struct Database(Storage);
186 /// #[query]
187 /// fn foo(ctx: &Ctx, id: Id<S>, id2: Id<String>) -> S {
188 /// let s = ctx.get(id);
189 /// let i = ctx.geti(id2);
190 /// assert_eq!(*i, "Hello");
191 /// S {
192 /// id: s.id,
193 /// value: s.value + 1,
194 /// }
195 /// }
196 ///
197 /// # let mut db = Database::default();
198 /// # let db = &mut db as &mut dyn verde::Db;
199 /// let id = db.set_input(S { id: 0, value: 0 });
200 /// let id2 = db.add("Hello".to_string());
201 /// db.execute(|ctx| foo(ctx, id, id2));
202 /// ```
203 pub fn geti<T: Interned>(&self, id: Id<T>) -> interned::Get<'_, T> { self.db.geti(id) }
204
205 /// Intern a value.
206 /// ```rust
207 /// # use verde::{query, Tracked, Ctx, Id, storage, db};
208 /// #[derive(Tracked, Eq, PartialEq)]
209 /// # #[cfg_attr(feature = "serde", derive(verde::serde::Serialize, verde::serde::Deserialize))]
210 /// struct S {
211 /// #[id]
212 /// id: u32,
213 /// value: u32,
214 /// }
215 ///
216 /// # #[storage]
217 /// # struct Storage(S, String, foo);
218 /// # #[db]
219 /// # struct Database(Storage);
220 /// #[query]
221 /// fn foo(ctx: &Ctx, id: Id<S>) -> S {
222 /// let s = ctx.get(id);
223 /// let id2 = ctx.add("Hello".to_string());
224 /// let i = ctx.geti(id2);
225 /// assert_eq!(*i, "Hello");
226 /// S {
227 /// id: s.id,
228 /// value: s.value + 1,
229 /// }
230 /// }
231 ///
232 /// # let mut db = Database::default();
233 /// # let db = &mut db as &mut dyn verde::Db;
234 /// let id = db.set_input(S { id: 0, value: 0 });
235 /// db.execute(|ctx| foo(ctx, id));
236 /// ```
237 pub fn add<T: Interned>(&self, value: T) -> Id<T> { self.db.add(value) }
238
239 /// Intern a value through a reference.
240 /// ```rust
241 /// # use verde::{query, Tracked, Ctx, Id, storage, db};
242 /// #[derive(Tracked, Eq, PartialEq)]
243 /// # #[cfg_attr(feature = "serde", derive(verde::serde::Serialize, verde::serde::Deserialize))]
244 /// struct S {
245 /// #[id]
246 /// id: u32,
247 /// value: u32,
248 /// }
249 ///
250 /// # #[storage]
251 /// # struct Storage(S, String, foo);
252 /// # #[db]
253 /// # struct Database(Storage);
254 /// #[query]
255 /// fn foo(ctx: &Ctx, id: Id<S>) -> S {
256 /// let s = ctx.get(id);
257 /// let id2 = ctx.add_ref("Hello");
258 /// let i = ctx.geti(id2);
259 /// assert_eq!(*i, "Hello");
260 /// S {
261 /// id: s.id,
262 /// value: s.value + 1,
263 /// }
264 /// }
265 ///
266 /// # let mut db = Database::default();
267 /// # let db = &mut db as &mut dyn verde::Db;
268 /// let id = db.set_input(S { id: 0, value: 0 });
269 /// db.execute(|ctx| foo(ctx, id));
270 /// ```
271 pub fn add_ref<T, U>(&self, value: &U) -> Id<T>
272 where
273 U: ToOwned<Owned = T> + Hash + Eq + ?Sized,
274 T: Borrow<U> + Interned,
275 {
276 self.db.add_ref(value)
277 }
278
279 /// Push a value to the database from this query.
280 /// Get a reference to the value `id` points to.
281 /// ```rust
282 /// # use verde::{query, Tracked, Pushable, Ctx, Id, storage, db};
283 /// #[derive(Tracked, Eq, PartialEq)]
284 /// # #[cfg_attr(feature = "serde", derive(verde::serde::Serialize, verde::serde::Deserialize))]
285 /// struct S {
286 /// #[id]
287 /// id: u32,
288 /// value: u32,
289 /// }
290 ///
291 /// #[derive(Pushable, Eq, PartialEq, Debug)]
292 /// # #[cfg_attr(feature = "serde", derive(verde::serde::Serialize, verde::serde::Deserialize))]
293 /// struct P {
294 /// value: u32,
295 /// }
296 ///
297 /// # #[storage]
298 /// # struct Storage(S, P, foo);
299 /// # #[db]
300 /// # struct Database(Storage);
301 /// #[query]
302 /// fn foo(ctx: &Ctx, id: Id<S>) -> S {
303 /// let s = ctx.get(id);
304 /// ctx.push(P { value: s.value + 1 });
305 /// S {
306 /// id: s.id,
307 /// value: s.value + 1,
308 /// }
309 /// }
310 ///
311 /// # let mut db = Database::default();
312 /// # let db = &mut db as &mut dyn verde::Db;
313 /// let id = db.set_input(S { id: 0, value: 0 });
314 /// db.execute(|ctx| foo(ctx, id));
315 /// assert_eq!(db.get_all::<P>().next(), Some(&P { value: 1 }));
316 /// ```
317 pub fn push<T: Pushable>(&self, value: T) {
318 let name = std::any::type_name::<T>();
319 span!(enter trace, "push", ty = name);
320 let mut borrowed = self
321 .pushed
322 .try_borrow_mut()
323 .expect("Cannot call `push` within a `map` scope");
324 let map = unsafe { borrowed.assume_init_mut() };
325 let vec = map.entry(TypeId::of::<T>()).or_insert((ErasedVec::new::<T>(), name));
326 unsafe {
327 vec.0.as_mut().push(value);
328 }
329 }
330
331 #[doc(hidden)]
332 pub fn start_query<T: Query>(&self, input: T::Input) -> Ctx<'_> {
333 span!(enter trace, "initialize query", query = std::any::type_name::<T>());
334
335 let route = self.db.routing_table().route::<T>();
336 let storage = self
337 .db
338 .storage_struct(route.storage)
339 .query_storage(route.index)
340 .unwrap();
341 unsafe {
342 let index = storage.start_query::<T>(input);
343 let curr_query = ErasedQueryId { route, index };
344 Ctx::new(self.db, curr_query)
345 }
346 }
347
348 #[doc(hidden)]
349 pub fn end_query<T: Query>(&self, f: impl FnOnce() -> T::Output) -> Id<T::Output> {
350 assert!(!self.dead.get(), "Query has already been ended");
351 self.dead.set(true);
352
353 let query = self.db.routing_table().route::<T>();
354 let storage = self
355 .db
356 .storage_struct(query.storage)
357 .query_storage(query.index)
358 .unwrap();
359 let ret = unsafe { storage.execute::<T>(self, f) };
360
361 // Commit the pushed values to the database (if there are any, we don't know)
362 let borrowed = self
363 .pushed
364 .try_borrow_mut()
365 .expect("Cannot end query within a `map` scope");
366 for (id, (vec, name)) in unsafe { borrowed.assume_init_read() } {
367 let route = self.db.routing_table().route_for(id, name);
368 let storage = self
369 .db
370 .storage_struct(route.storage)
371 .pushable_storage(route.index)
372 .unwrap();
373 unsafe { storage.push(self.curr_query, vec) }
374 }
375
376 ret
377 }
378
379 pub(crate) fn get_generation(&self, id: ErasedId) -> u64 {
380 span!(
381 enter trace,
382 "fetching generation",
383 ty = self.db.routing_table().name(id.route),
384 id = id.index
385 );
386 let storage = self
387 .db
388 .storage_struct(id.route.storage)
389 .tracked_storage(id.route.index)
390 .unwrap();
391 storage.get_generation(id.index)
392 }
393}
394
395impl dyn Db + '_ {
396 /// Set an input value.
397 /// ```rust
398 /// # use verde::{Tracked, Ctx, Id, storage, db};
399 /// #[derive(Tracked, Eq, PartialEq, Debug)]
400 /// # #[cfg_attr(feature = "serde", derive(verde::serde::Serialize, verde::serde::Deserialize))]
401 /// struct S {
402 /// #[id]
403 /// id: u32,
404 /// value: u32,
405 /// }
406 ///
407 /// # #[storage]
408 /// # struct Storage(S);
409 /// # #[db]
410 /// # struct Database(Storage);
411 ///
412 /// # let mut db = Database::default();
413 /// # let db = &mut db as &mut dyn verde::Db;
414 /// let id = db.set_input(S { id: 0, value: 0 });
415 /// let s = db.get(id);
416 /// assert_eq!(*s, S { id: 0, value: 0 });
417 /// ```
418 pub fn set_input<T: Tracked>(&self, value: T) -> Id<T> { self.insert(Route::input(), value) }
419
420 /// Get a reference to the value `id` points to.
421 /// ```rust
422 /// # use verde::{Tracked, Ctx, Id, storage, db};
423 /// #[derive(Tracked, Eq, PartialEq, Debug)]
424 /// # #[cfg_attr(feature = "serde", derive(verde::serde::Serialize, verde::serde::Deserialize))]
425 /// struct S {
426 /// #[id]
427 /// id: u32,
428 /// value: u32,
429 /// }
430 ///
431 /// # #[storage]
432 /// # struct Storage(S);
433 /// # #[db]
434 /// # struct Database(Storage);
435 ///
436 /// # let mut db = Database::default();
437 /// # let db = &mut db as &mut dyn verde::Db;
438 /// let id = db.set_input(S { id: 0, value: 0 });
439 /// let s = db.get(id);
440 /// assert_eq!(*s, S { id: 0, value: 0 });
441 /// ```
442 pub fn get<T: Tracked>(&self, id: Id<T>) -> tracked::Get<'_, T> {
443 let id = id.get();
444 span!(
445 enter trace,
446 "fetching value",
447 ty = std::any::type_name::<T>(),
448 id = id.index
449 );
450 let storage = self
451 .storage_struct(id.route.storage)
452 .tracked_storage(id.route.index)
453 .unwrap();
454 unsafe { storage.get(id.index) }
455 }
456
457 /// Get a reference to the value `id` points to.
458 /// ```rust
459 /// # use verde::{Interned, Ctx, Id, storage, db};
460 ///
461 /// # #[storage]
462 /// # struct Storage(String);
463 /// # #[db]
464 /// # struct Database(Storage);
465 ///
466 /// # let mut db = Database::default();
467 /// # let db = &mut db as &mut dyn verde::Db;
468 /// let id = db.add("Hello".to_string());
469 /// let s = db.geti(id);
470 /// assert_eq!(*s, "Hello");
471 /// ```
472 pub fn geti<T: Interned>(&self, id: Id<T>) -> interned::Get<'_, T> {
473 let id = id.get();
474 span!(
475 enter trace,
476 "fetching value",
477 ty = std::any::type_name::<T>(),
478 id = id.index
479 );
480 let storage = self
481 .storage_struct(id.route.storage)
482 .interned_storage(id.route.index)
483 .unwrap();
484 unsafe { storage.get(id.index) }
485 }
486
487 /// Intern a value.
488 /// ```rust
489 /// # use verde::{Interned, Ctx, Id, storage, db};
490 ///
491 /// # #[storage]
492 /// # struct Storage(String);
493 /// # #[db]
494 /// # struct Database(Storage);
495 ///
496 /// # let mut db = Database::default();
497 /// # let db = &mut db as &mut dyn verde::Db;
498 /// let id = db.add("Hello".to_string());
499 /// let s = db.geti(id);
500 /// assert_eq!(*s, "Hello");
501 /// ```
502 pub fn add<T: Interned>(&self, value: T) -> Id<T> {
503 let span = span!(
504 trace,
505 "inserting value",
506 ty = std::any::type_name::<T>(),
507 id = tracing::field::Empty
508 );
509 #[allow(clippy::let_unit_value)]
510 let _e = span.enter();
511 let route = self.routing_table().route::<T>();
512 let storage = self
513 .storage_struct(route.storage)
514 .interned_storage(route.index)
515 .unwrap();
516 let id = unsafe { storage.insert(value) };
517 span.record("id", id);
518 Id::new(id, route)
519 }
520
521 /// Intern a value through a reference.
522 /// ```rust
523 /// # use verde::{Interned, Ctx, Id, storage, db};
524 ///
525 /// # #[storage]
526 /// # struct Storage(String);
527 /// # #[db]
528 /// # struct Database(Storage);
529 ///
530 /// # let mut db = Database::default();
531 /// # let db = &mut db as &mut dyn verde::Db;
532 /// let id = db.add_ref("Hello");
533 /// let s = db.geti(id);
534 /// assert_eq!(*s, "Hello");
535 /// ```
536 pub fn add_ref<T, U>(&self, value: &U) -> Id<T>
537 where
538 U: ToOwned<Owned = T> + Hash + Eq + ?Sized,
539 T: Borrow<U> + Interned,
540 {
541 let span = span!(
542 trace,
543 "inserting value",
544 ty = std::any::type_name::<T>(),
545 id = tracing::field::Empty
546 );
547 #[allow(clippy::let_unit_value)]
548 let _e = span.enter();
549 let route = self.routing_table().route::<T>();
550 let storage = self
551 .storage_struct(route.storage)
552 .interned_storage(route.index)
553 .unwrap();
554 let id = unsafe { storage.insert_ref(value) };
555 span.record("id", id);
556 Id::new(id, route)
557 }
558
559 /// Get all pushed `T`s.
560 /// ```rust
561 /// # use verde::{query, Tracked, Pushable, Ctx, Id, storage, db};
562 /// #[derive(Tracked, Eq, PartialEq)]
563 /// # #[cfg_attr(feature = "serde", derive(verde::serde::Serialize, verde::serde::Deserialize))]
564 /// struct S {
565 /// #[id]
566 /// id: u32,
567 /// value: u32,
568 /// }
569 ///
570 /// #[derive(Pushable, Eq, PartialEq, Debug)]
571 /// # #[cfg_attr(feature = "serde", derive(verde::serde::Serialize, verde::serde::Deserialize))]
572 /// struct P {
573 /// value: u32,
574 /// }
575 ///
576 /// # #[storage]
577 /// # struct Storage(S, P, foo);
578 /// # #[db]
579 /// # struct Database(Storage);
580 /// #[query]
581 /// fn foo(ctx: &Ctx, id: Id<S>) -> S {
582 /// let s = ctx.get(id);
583 /// ctx.push(P { value: s.value + 1 });
584 /// S {
585 /// id: s.id,
586 /// value: s.value + 1,
587 /// }
588 /// }
589 ///
590 /// # let mut db = Database::default();
591 /// # let db = &mut db as &mut dyn verde::Db;
592 /// let id = db.set_input(S { id: 0, value: 0 });
593 /// db.execute(|ctx| foo(ctx, id));
594 /// assert_eq!(db.get_all::<P>().next(), Some(&P { value: 1 }));
595 /// ```
596 pub fn get_all<T: Pushable>(&self) -> impl Iterator<Item = &'_ T> {
597 let route = self.routing_table().route::<T>();
598 let storage = self
599 .storage_struct(route.storage)
600 .pushable_storage(route.index)
601 .unwrap();
602 unsafe { storage.get_all() }
603 }
604
605 /// Get all pushed `T`s from the query `Q`.
606 /// ```rust
607 /// # use verde::{query, Tracked, Pushable, Ctx, Id, storage, db};
608 /// #[derive(Tracked, Eq, PartialEq)]
609 /// # #[cfg_attr(feature = "serde", derive(verde::serde::Serialize, verde::serde::Deserialize))]
610 /// struct S {
611 /// #[id]
612 /// id: u32,
613 /// value: u32,
614 /// }
615 ///
616 /// #[derive(Pushable, Eq, PartialEq, Debug)]
617 /// # #[cfg_attr(feature = "serde", derive(verde::serde::Serialize, verde::serde::Deserialize))]
618 /// struct P {
619 /// value: u32,
620 /// }
621 ///
622 /// # #[storage]
623 /// # struct Storage(S, P, foo, boo);
624 /// # #[db]
625 /// # struct Database(Storage);
626 /// #[query]
627 /// fn foo(ctx: &Ctx, id: Id<S>) -> S {
628 /// let s = ctx.get(id);
629 /// ctx.push(P { value: s.value + 1 });
630 /// S {
631 /// id: s.id,
632 /// value: s.value + 1,
633 /// }
634 /// }
635 ///
636 /// #[query]
637 /// fn boo(ctx: &Ctx, id: Id<S>) -> S {
638 /// let s = ctx.get(id);
639 /// ctx.push(P { value: s.value + 1 });
640 /// S {
641 /// id: s.id,
642 /// value: s.value + 1,
643 /// }
644 /// }
645 ///
646 /// # let mut db = Database::default();
647 /// # let db = &mut db as &mut dyn verde::Db;
648 /// let id = db.set_input(S { id: 0, value: 0 });
649 /// let id2 = db.set_input(S { id: 0, value: 1 });
650 /// db.execute(|ctx| foo(ctx, id));
651 /// db.execute(|ctx| boo(ctx, id));
652 /// assert_eq!(db.get_query::<boo, P>().next(), Some(&P { value: 2 }));
653 /// ```
654 pub fn get_query<Q: Query, T: Pushable>(&self) -> impl Iterator<Item = &'_ T> {
655 let route = self.routing_table().route::<T>();
656 let query = self.routing_table().route::<Q>();
657 let storage = self
658 .storage_struct(route.storage)
659 .pushable_storage(route.index)
660 .unwrap();
661 unsafe { storage.get_query(query) }
662 }
663
664 /// Execute a closure in the context of the database.
665 /// ```rust
666 /// # use verde::{query, Tracked, Ctx, Id, storage, db};
667 /// #[derive(Tracked, Eq, PartialEq)]
668 /// # #[cfg_attr(feature = "serde", derive(verde::serde::Serialize, verde::serde::Deserialize))]
669 /// struct S {
670 /// #[id]
671 /// id: u32,
672 /// value: u32,
673 /// }
674 ///
675 /// # #[storage]
676 /// # struct Storage(S, foo);
677 /// # #[db]
678 /// # struct Database(Storage);
679 /// #[query]
680 /// fn foo(ctx: &Ctx, id: Id<S>) -> S {
681 /// let s = ctx.get(id);
682 /// assert_eq!(s.value, 0);
683 /// S {
684 /// id: s.id,
685 /// value: s.value + 1,
686 /// }
687 /// }
688 ///
689 /// # let mut db = Database::default();
690 /// # let db = &mut db as &mut dyn verde::Db;
691 /// let id = db.set_input(S { id: 0, value: 0 });
692 /// db.execute(|ctx| foo(ctx, id));
693 /// ```
694 pub fn execute<R>(&self, f: impl FnOnce(&Ctx) -> R) -> R {
695 let ctx = Ctx::new(
696 self,
697 ErasedQueryId {
698 route: Route::input(),
699 index: 0,
700 },
701 );
702 f(&ctx)
703 }
704}
705impl dyn Db + Send + Sync + '_ {
706 /// Set an input value.
707 /// ```rust
708 /// # use verde::{Tracked, Ctx, Id, storage, db};
709 /// #[derive(Tracked, Eq, PartialEq, Debug)]
710 /// # #[cfg_attr(feature = "serde", derive(verde::serde::Serialize, verde::serde::Deserialize))]
711 /// struct S {
712 /// #[id]
713 /// id: u32,
714 /// value: u32,
715 /// }
716 ///
717 /// # #[storage]
718 /// # struct Storage(S);
719 /// # #[db]
720 /// # struct Database(Storage);
721 ///
722 /// # let mut db = Database::default();
723 /// # let db = &mut db as &mut dyn verde::Db;
724 /// let id = db.set_input(S { id: 0, value: 0 });
725 /// let s = db.get(id);
726 /// assert_eq!(*s, S { id: 0, value: 0 });
727 /// ```
728 pub fn set_input<T: Tracked>(&self, value: T) -> Id<T> { (self as &dyn Db).set_input(value) }
729
730 /// Get a reference to the value `id` points to.
731 /// ```rust
732 /// # use verde::{Tracked, Ctx, Id, storage, db};
733 /// #[derive(Tracked, Eq, PartialEq, Debug)]
734 /// # #[cfg_attr(feature = "serde", derive(verde::serde::Serialize, verde::serde::Deserialize))]
735 /// struct S {
736 /// #[id]
737 /// id: u32,
738 /// value: u32,
739 /// }
740 ///
741 /// # #[storage]
742 /// # struct Storage(S);
743 /// # #[db]
744 /// # struct Database(Storage);
745 ///
746 /// # let mut db = Database::default();
747 /// # let db = &mut db as &mut dyn verde::Db;
748 /// let id = db.set_input(S { id: 0, value: 0 });
749 /// let s = db.get(id);
750 /// assert_eq!(*s, S { id: 0, value: 0 });
751 /// ```
752 pub fn get<T: Tracked>(&self, id: Id<T>) -> tracked::Get<'_, T> { (self as &dyn Db).get(id) }
753
754 /// Get a reference to the value `id` points to.
755 /// ```rust
756 /// # use verde::{Interned, Ctx, Id, storage, db};
757 ///
758 /// # #[storage]
759 /// # struct Storage(String);
760 /// # #[db]
761 /// # struct Database(Storage);
762 ///
763 /// # let mut db = Database::default();
764 /// # let db = &mut db as &mut dyn verde::Db;
765 /// let id = db.add("Hello".to_string());
766 /// let s = db.geti(id);
767 /// assert_eq!(*s, "Hello");
768 /// ```
769 pub fn geti<T: Interned>(&self, id: Id<T>) -> interned::Get<'_, T> { (self as &dyn Db).geti(id) }
770
771 /// Intern a value.
772 /// ```rust
773 /// # use verde::{Interned, Ctx, Id, storage, db};
774 ///
775 /// # #[storage]
776 /// # struct Storage(String);
777 /// # #[db]
778 /// # struct Database(Storage);
779 ///
780 /// # let mut db = Database::default();
781 /// # let db = &mut db as &mut dyn verde::Db;
782 /// let id = db.add("Hello".to_string());
783 /// let s = db.geti(id);
784 /// assert_eq!(*s, "Hello");
785 /// ```
786 pub fn add<T: Interned>(&self, value: T) -> Id<T> { (self as &dyn Db).add(value) }
787
788 /// Intern a value through a reference.
789 /// ```rust
790 /// # use verde::{Interned, Ctx, Id, storage, db};
791 ///
792 /// # #[storage]
793 /// # struct Storage(String);
794 /// # #[db]
795 /// # struct Database(Storage);
796 ///
797 /// # let mut db = Database::default();
798 /// # let db = &mut db as &mut dyn verde::Db;
799 /// let id = db.add_ref("Hello");
800 /// let s = db.geti(id);
801 /// assert_eq!(*s, "Hello");
802 /// ```
803 pub fn add_ref<T, U>(&self, value: &U) -> Id<T>
804 where
805 U: ToOwned<Owned = T> + Hash + Eq + ?Sized,
806 T: Borrow<U> + Interned,
807 {
808 (self as &dyn Db).add_ref(value)
809 }
810
811 /// Get all pushed `T`s.
812 /// ```rust
813 /// # use verde::{query, Tracked, Pushable, Ctx, Id, storage, db};
814 /// #[derive(Tracked, Eq, PartialEq)]
815 /// # #[cfg_attr(feature = "serde", derive(verde::serde::Serialize, verde::serde::Deserialize))]
816 /// struct S {
817 /// #[id]
818 /// id: u32,
819 /// value: u32,
820 /// }
821 ///
822 /// #[derive(Pushable, Eq, PartialEq, Debug)]
823 /// # #[cfg_attr(feature = "serde", derive(verde::serde::Serialize, verde::serde::Deserialize))]
824 /// struct P {
825 /// value: u32,
826 /// }
827 ///
828 /// # #[storage]
829 /// # struct Storage(S, P, foo);
830 /// # #[db]
831 /// # struct Database(Storage);
832 /// #[query]
833 /// fn foo(ctx: &Ctx, id: Id<S>) -> S {
834 /// let s = ctx.get(id);
835 /// ctx.push(P { value: s.value + 1 });
836 /// S {
837 /// id: s.id,
838 /// value: s.value + 1,
839 /// }
840 /// }
841 ///
842 /// # let mut db = Database::default();
843 /// # let db = &mut db as &mut dyn verde::Db;
844 /// let id = db.set_input(S { id: 0, value: 0 });
845 /// db.execute(|ctx| foo(ctx, id));
846 /// assert_eq!(db.get_all::<P>().next(), Some(&P { value: 1 }));
847 /// ```
848 pub fn get_all<T: Pushable>(&self) -> impl Iterator<Item = &'_ T> { (self as &dyn Db).get_all() }
849
850 /// Get all pushed `T`s from the query `Q`.
851 /// ```rust
852 /// # use verde::{query, Tracked, Pushable, Ctx, Id, storage, db};
853 /// #[derive(Tracked, Eq, PartialEq)]
854 /// # #[cfg_attr(feature = "serde", derive(verde::serde::Serialize, verde::serde::Deserialize))]
855 /// struct S {
856 /// #[id]
857 /// id: u32,
858 /// value: u32,
859 /// }
860 ///
861 /// #[derive(Pushable, Eq, PartialEq, Debug)]
862 /// # #[cfg_attr(feature = "serde", derive(verde::serde::Serialize, verde::serde::Deserialize))]
863 /// struct P {
864 /// value: u32,
865 /// }
866 ///
867 /// # #[storage]
868 /// # struct Storage(S, P, foo, boo);
869 /// # #[db]
870 /// # struct Database(Storage);
871 /// #[query]
872 /// fn foo(ctx: &Ctx, id: Id<S>) -> S {
873 /// let s = ctx.get(id);
874 /// ctx.push(P { value: s.value + 1 });
875 /// S {
876 /// id: s.id,
877 /// value: s.value + 1,
878 /// }
879 /// }
880 ///
881 /// #[query]
882 /// fn boo(ctx: &Ctx, id: Id<S>) -> S {
883 /// let s = ctx.get(id);
884 /// ctx.push(P { value: s.value + 1 });
885 /// S {
886 /// id: s.id,
887 /// value: s.value + 1,
888 /// }
889 /// }
890 ///
891 /// # let mut db = Database::default();
892 /// # let db = &mut db as &mut dyn verde::Db;
893 /// let id = db.set_input(S { id: 0, value: 0 });
894 /// let id2 = db.set_input(S { id: 0, value: 1 });
895 /// db.execute(|ctx| foo(ctx, id));
896 /// db.execute(|ctx| boo(ctx, id));
897 /// assert_eq!(db.get_query::<boo, P>().next(), Some(&P { value: 2 }));
898 /// ```
899 pub fn get_query<Q: Query, T: Pushable>(&self) -> impl Iterator<Item = &'_ T> {
900 (self as &dyn Db).get_query::<Q, T>()
901 }
902
903 /// Execute a closure in the context of the database.
904 /// ```rust
905 /// # use verde::{query, Tracked, Ctx, Id, storage, db};
906 /// #[derive(Tracked, Eq, PartialEq)]
907 /// # #[cfg_attr(feature = "serde", derive(verde::serde::Serialize, verde::serde::Deserialize))]
908 /// struct S {
909 /// #[id]
910 /// id: u32,
911 /// value: u32,
912 /// }
913 ///
914 /// # #[storage]
915 /// # struct Storage(S, foo);
916 /// # #[db]
917 /// # struct Database(Storage);
918 /// #[query]
919 /// fn foo(ctx: &Ctx, id: Id<S>) -> S {
920 /// let s = ctx.get(id);
921 /// assert_eq!(s.value, 0);
922 /// S {
923 /// id: s.id,
924 /// value: s.value + 1,
925 /// }
926 /// }
927 ///
928 /// # let mut db = Database::default();
929 /// # let db = &mut db as &mut dyn verde::Db;
930 /// let id = db.set_input(S { id: 0, value: 0 });
931 /// db.execute(|ctx| foo(ctx, id));
932 /// ```
933 pub fn execute<R>(&self, f: impl FnOnce(&Ctx) -> R) -> R { (self as &dyn Db).execute(f) }
934}
935
936impl dyn Db + '_ {
937 pub(crate) fn insert<T: Tracked>(&self, query: Route, value: T) -> Id<T> {
938 let span = span!(
939 trace,
940 "inserting value",
941 ty = std::any::type_name::<T>(),
942 id = tracing::field::Empty
943 );
944 #[allow(clippy::let_unit_value)]
945 let _e = span.enter();
946 let route = self.routing_table().route::<T>();
947 let storage = self.storage_struct(route.storage).tracked_storage(route.index).unwrap();
948 let id = unsafe { storage.insert(value, query) };
949 span.record("id", id);
950 Id::new(id, route)
951 }
952}
953
954impl Db for Ctx<'_> {
955 fn init_routing(_: &mut RoutingTableBuilder) {
956 panic!("Cannot call `init_routing` on a `Ctx`");
957 }
958
959 fn routing_table(&self) -> &RoutingTable { self.db.routing_table() }
960
961 fn storage_struct(&self, storage: u16) -> &dyn Storage { self.db.storage_struct(storage) }
962}