1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
//! Traits and implementations for working with index members.
//!
//! There are 3 ways to interact with an index field:
//!
//!  - [`Store`]: Store the field into the index.
//!  - [`Query`]: Query the field and load selected values into memory.
//!  - [`Load`]: Load all contents of the field into memory.
//!
//! To implement how a field is actually stored in the index, we
//! define an access [`Strategy`]. Currently 2 access strategies are
//! implemented in Infinitree, but the storage system is extensible.
//!
//!  - [`SparseField`]: Store the key in the index, but the value in
//!  the object store
//!  - [`LocalField`]: Store both the key and the value in the index.
//!
//! Additionally, `infinitree` can work with "snapshot" or
//! "incremental" fields. This [`depth`] of the field will determine its
//! behaviour during [`Load`] or [`Query`] operation.
//!
//! This is a detail that you need to be aware
//! of when designing your indexes, but the implementation details are
//! only relevant if you intend to write your own field type.
//!
//!  - [`Incremental`](depth::Incremental): The entire
//! commit list will be traversed, typically useful for incremental collection types.
//!  - [`Snapshot`](depth::Snapshot): Only the last commit is visited,
//! restoring a point-in-time snapshot of the contents.
//!
//! To learn more about index internals, see the module documentation
//! in the [`index`](super) module.

use crate::{
    index::{FieldReader, TransactionList},
    object::{self, AEADReader, Pool},
};
use serde::{de::DeserializeOwned, Serialize};
use std::{cmp::Eq, hash::Hash, sync::Arc};

/// Marker trait for values that can be serialized and used as a
/// value for an index field
///
/// You should generally not implement this trait as a blanket
/// implementation will cover all types that conform.
pub trait Value: Serialize + DeserializeOwned + Send + Sync {}

/// Marker trait for value that can be used as a key in an index
///
/// You should generally not implement this trait as a blanket
/// implementation will cover all types that conform.
pub trait Key: Serialize + DeserializeOwned + Eq + Hash + Send + Sync {}

impl<T> Value for T where T: Serialize + DeserializeOwned + Send + Sync {}
impl<T> Key for T where T: Serialize + DeserializeOwned + Eq + Hash + Send + Sync {}

mod map;
pub use map::Map;

mod list;
pub use list::List;

// mod set;
// pub use set::Set;

mod query;
pub use query::*;

mod serialized;
pub use serialized::Serialized;

mod versioned;
pub use versioned::list::LinkedList;
pub use versioned::map::VersionedMap;

pub mod depth;
use depth::Depth;

pub mod strategy;
#[allow(unused)]
pub(crate) use strategy::Strategy;
pub use strategy::{LocalField, SparseField};

pub mod intent;
pub use intent::{Intent, Load, Query, Store};

/// Query an index field, but do not automatically load it into memory
///
/// To allow lazily loading data from e.g. a [`SparseField`] when
/// relevant, a predicate is taken that controls the iterator.
///
/// This trait should be implemented on a type that also implements
/// [`Strategy`], and _not_ on the field directly.
pub trait Collection {
    /// Use this strategy to load the collection.
    ///
    /// Typically this will be one of two types:
    ///
    ///  * `Incremental` if a collection requires
    ///     crawling the full transaction history for an accurate
    ///     representation after loading.
    ///  * `Snapshot` if the collection is not versioned and
    ///     therefore there's no need to resolve the full the
    ///     transaction list.
    type Depth: Depth;

    /// The key that the predicate will use to decide whether to pull
    /// more data into memory.
    type Key;

    /// The serialized record format. This type will typically
    /// implement [`serde::Serialize`]
    type Serialized: DeserializeOwned;

    /// This is equivalent to `Iterator::Item`, and should contain a
    /// full record that can be inserted into the in-memory store.
    type Item;

    /// Get the key based on the deserialized data. You want this to
    /// be a reference that's easy to derive from the serialized data.
    fn key(from: &Self::Serialized) -> &Self::Key;

    /// Load the full record, and return it
    fn load(from: Self::Serialized, object: &mut dyn object::Reader) -> Self::Item;

    /// Store the deserialized record in the collection
    fn insert(&mut self, record: Self::Item);
}

impl<T> Query for T
where
    T: Collection,
{
    type Key = T::Key;

    fn select(
        &mut self,
        pool: Pool<AEADReader>,
        transaction_list: TransactionList,
        predicate: impl Fn(&Self::Key) -> QueryAction,
    ) {
        let predicate = Arc::new(predicate);
        let mut reader = pool.lease().unwrap();
        for transaction in T::Depth::resolve(pool, transaction_list) {
            let iter = QueryIterator::new(transaction, &mut reader, predicate.clone(), self);
            for item in iter {
                self.insert(item);
            }
        }
    }
}

impl<T: Collection> Collection for LocalField<T> {
    type Depth = T::Depth;

    type Key = T::Key;

    type Serialized = T::Serialized;

    type Item = T::Item;

    fn key(from: &Self::Serialized) -> &Self::Key {
        T::key(from)
    }

    fn load(from: Self::Serialized, object: &mut dyn object::Reader) -> Self::Item {
        T::load(from, object)
    }

    fn insert(&mut self, record: Self::Item) {
        self.field.insert(record)
    }
}