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
#![forbid(unsafe_code)]
#![deny(missing_docs)]

//! # Iron Sea - Index
//!
//! Traits definitions for the Iron Sea database toolkit indices.
//!
//! ## Iron Sea: Database Toolkit
//! **Iron Sea** provides a set of database engine bricks, which can be
//! combined and applied on arbitrary data structures.
//!
//! Unlike a traditional database, it does not assume a specific
//! physical structure for the tables nor the records, but relies on the
//! developer to provide a set of extractor functions which are used by
//! the specific indices provided.
//!
//! This enables the index implementations to be agnostic from the
//! underlying data structure, and re-used.
//!
//!

/// Record behavior used by Indexed implementations.
///
/// This trait provides common methods used by index implementations to
/// retrieve information about a single record. This is provided by the
/// users of indices, for each of their `struct` they wish to index.
///
/// Multiple implementation can be provided, as long as their types are
/// different.
///
// TODO: Add more complex scenarii where multiple implementations with
//       the same types are necessary, for example returning either a or
//       b.
///
/// # Examples
///
/// ```
/// use ironsea_index::Record;
///
/// #[derive(Clone, Debug)]
/// pub struct MyPair {
///     a: i64,
///     b: i64,
/// }
///
/// impl Record<String> for MyPair {
///    fn key(&self) -> String {
///        format!("{}", self.a)
///    }
/// }
///
/// impl Record<i64> for MyPair {
///    fn key(&self) -> i64 {
///        self.a
///    }
/// }
///
/// fn main() {
///
///    let table = vec![MyPair{ a: 10, b:34}, MyPair{ a: 1, b:56}, MyPair{ a: 2, b:23}];
///
///    // Example without using an actual index crate, we will simply use
///    // the Record<K> trait to sort the array of pairs.
///    let mut lex_sort = table.clone();
///    lex_sort.sort_unstable_by_key(|e| {let k: String = e.key(); k});
///
///    let mut num_sort = table.clone();
///    num_sort.sort_unstable_by_key(|e| {let k: i64 = e.key(); k});
///
///    assert_eq!(format!("unsorted {:?}", table),
///         "unsorted [MyPair { a: 10, b: 34 }, MyPair { a: 1, b: 56 }, MyPair { a: 2, b: 23 }]");
///    assert_eq!(format!("lex sort {:?}", lex_sort),
///         "lex sort [MyPair { a: 1, b: 56 }, MyPair { a: 10, b: 34 }, MyPair { a: 2, b: 23 }]");
///    assert_eq!(format!("num sort {:?}", num_sort),
///         "num sort [MyPair { a: 1, b: 56 }, MyPair { a: 2, b: 23 }, MyPair { a: 10, b: 34 }]");
/// }
/// ```
pub trait Record<K> {
    /// Extract the key from the record.
    fn key(&self) -> K;
}

/// Record behavior used by IndexedDestructured implementations.
///
/// RecordFields is used by indices which de-structure records into two
/// components, the key and the fields associated to that unique key.
/// This is provided by the users of indices, for each of their `struct`
/// they wish to index.
pub trait RecordFields<F> {
    /// Extract the fields of the record
    fn fields(&self) -> F;
}

/// Methods provided by indices.
///
/// This kind of indices can work on references to the original vector
/// or take ownership of the records, based on the type given for the
/// records.
///
///  * `R`: Type of the records
///  * `K`: Type of the keys

// Generic types are not sorted alphabetically, to match next trait
// semantic order
pub trait Indexed<R, K> {
    /// Retrieve all records matching the key.
    fn find(&self, key: &K) -> Vec<&R>;

    /// Retrieve all records matching in the key range defined by
    /// `start` and `end`.
    ///
    /// * `start` is included
    // TODO: TBC for `end`
    fn find_range(&self, start: &K, end: &K) -> Vec<&R>;
}

/// Methods provided by destructuring indices.
///
/// This kind of indices store inside the index both keys and values,
/// meaning the original records can be freed.
///
///  * `F`: Type of the struct containing the remaining fields
///  * `K`: Type of the keys
pub trait IndexedDestructured<F, K> {
    /// Retrieve all records matching the key.
    fn find(&self, key: &K) -> Vec<&F>;

    /// Retrieve all records matching in the key range defined by
    /// `start` and `end`.
    ///
    /// * `start` is included
    // TODO: TBC for `end`
    fn find_range(&self, start: &K, end: &K) -> Vec<(K, &F)>;
}