infinitree/fields/intent.rs
1//! Intent to execute some operation on an [`Index`](crate::Index) field
2
3use super::{query::QueryAction, LocalField};
4use crate::{
5 index::{Transaction, TransactionList},
6 object::{self, AEADReader, Pool},
7};
8
9/// A wrapper to allow working with trait objects and `impl Trait`
10/// types when accessing the index field.
11#[non_exhaustive]
12#[derive(Clone)]
13pub struct Intent<T> {
14 /// The stringy name of the field that's being accessed. This MUST
15 /// be unique within the index.
16 pub name: String,
17
18 /// The strategy for the given access that's to be executed.
19 pub strategy: T,
20}
21
22impl<T> Intent<T> {
23 /// Create a new wrapper that binds a stringy field name to an
24 /// access strategy
25 #[inline(always)]
26 pub fn new(name: impl AsRef<str>, strategy: T) -> Self {
27 Intent {
28 name: name.as_ref().to_string(),
29 strategy,
30 }
31 }
32}
33
34impl<T: Store + 'static> From<Intent<Box<T>>> for Intent<Box<dyn Store>> {
35 #[inline(always)]
36 fn from(a: Intent<Box<T>>) -> Self {
37 Intent {
38 name: a.name,
39 strategy: a.strategy,
40 }
41 }
42}
43
44impl<T: Load + 'static> From<Intent<Box<T>>> for Intent<Box<dyn Load>> {
45 #[inline(always)]
46 fn from(a: Intent<Box<T>>) -> Self {
47 Intent {
48 name: a.name,
49 strategy: a.strategy,
50 }
51 }
52}
53
54/// Store data into the index.
55///
56/// This trait is usually implemented on a type that also implements
57/// [`Strategy`](super::strategy::Strategy), and _not_ on the field directly.
58pub trait Store {
59 /// Store the contents of the field into the index. The field
60 /// itself needs to track whether this should be a complete
61 /// rewrite or an upsert.
62 ///
63 /// The `transaction` parameter is provided for strategies to
64 /// store values in the index, while the `object` is to store
65 /// values in the object pool.
66 ///
67 /// Typically, the [`ChunkPointer`][crate::ChunkPointer] values returned by `object`
68 /// should be stored in the index.
69 fn store(&mut self, transaction: &mut dyn Transaction, object: &mut dyn object::Writer);
70}
71
72impl<T: Store> Store for LocalField<T> {
73 fn store(&mut self, transaction: &mut dyn Transaction, object: &mut dyn object::Writer) {
74 self.field.store(transaction, object)
75 }
76}
77
78/// Load all data from the index field into memory.
79///
80/// This trait is usually implemented on a type that also implements
81/// [`Strategy`](super::strategy::Strategy), and _not_ on the field directly.
82///
83/// In addition, `Load` has a blanket implementation for all types
84/// that implement [`Query`], so very likely you never have to
85/// manually implement this yourself.
86pub trait Load {
87 /// Execute a load action.
88 ///
89 /// The `index` and `object` readers are provided to interact with
90 /// the indexes and the object pool, respectively.
91 ///
92 /// `transaction_list` can contain any list of transactions that
93 /// this loader should restore into memory.
94 ///
95 /// Note that this is decidedly not a type safe way to interact
96 /// with a collection, and therefore it is recommended that
97 /// `transaction_list` is prepared and sanitized for the field
98 /// that's being restored.
99 fn load(&mut self, pool: Pool<AEADReader>, transaction_list: TransactionList);
100}
101
102impl<K, T> Load for T
103where
104 T: Query<Key = K>,
105{
106 #[inline(always)]
107 fn load(&mut self, pool: Pool<AEADReader>, transaction_list: TransactionList) {
108 Query::select(self, pool, transaction_list, |_| QueryAction::Take)
109 }
110}
111
112/// Load data into memory where a predicate indicates it's needed
113///
114/// This trait should be implemented on a type that also implements
115/// [`Strategy`](super::strategy::Strategy), and _not_ on the field directly.
116pub trait Query {
117 /// The key that the predicate will use to decide whether to pull
118 /// more data into memory.
119 type Key;
120
121 /// Load items into memory based on a predicate
122 ///
123 /// The `index` and `object` readers are provided to interact with
124 /// the indexes and the object pool, respectively.
125 ///
126 /// `transaction_list` can contain any list of transactions that
127 /// this loader should restore into memory.
128 ///
129 /// Note that this is decidedly not a type safe way to interact
130 /// with a collection, and therefore it is recommended that
131 /// `transaction_list` is prepared and sanitized for the field
132 /// that's being restored.
133 fn select(
134 &mut self,
135 pool: Pool<AEADReader>,
136 transaction_list: TransactionList,
137 predicate: impl Fn(&Self::Key) -> QueryAction,
138 );
139}