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}