Skip to main content

nimiq_database/
utils.rs

1use std::borrow::Cow;
2
3use nimiq_database_value::{AsDatabaseBytes, FromDatabaseBytes};
4
5use crate::traits::{DupTableValue, Key, Value};
6
7/// A data type used in dup tables that have a subkey.
8/// It allows having tables that map from a main key to a subkey (`index`) to a value (`value`).
9///
10/// The index/subkey type must have a fixed size declared in its `AsDatabaseBytes` implementation.
11/// Otherwise, the code will panic at compile time.
12#[derive(Debug, Clone, PartialEq, Eq)]
13pub struct IndexedValue<I: Key, V: Value> {
14    /// The subkey or index.
15    pub index: I,
16    /// The associated value.
17    pub value: V,
18}
19
20impl<I: Key, V: Value> IndexedValue<I, V> {
21    /// Create a new indexed value.
22    pub fn new(index: I, value: V) -> Self {
23        Self { index, value }
24    }
25}
26
27impl<I: Key, V: Value> DupTableValue for IndexedValue<I, V> {
28    /// The subkey/index type.
29    type SubKey = I;
30
31    /// The value type.
32    type Value = V;
33
34    /// Returns a reference to the subkey.
35    fn subkey(&self) -> &Self::SubKey {
36        &self.index
37    }
38
39    /// Returns a reference to the value.
40    fn value(&self) -> &Self::Value {
41        &self.value
42    }
43}
44
45impl<I: Key, V: Value> AsDatabaseBytes for IndexedValue<I, V> {
46    fn as_key_bytes(&self) -> Cow<'_, [u8]> {
47        let bytes = [
48            &self.index.as_value_bytes()[..],
49            &self.value.as_value_bytes()[..],
50        ]
51        .concat();
52        Cow::Owned(bytes)
53    }
54
55    const FIXED_SIZE: Option<usize> = match (I::FIXED_SIZE, V::FIXED_SIZE) {
56        (Some(index_len), Some(value_len)) => Some(index_len + value_len),
57        (Some(_), None) => None,
58        (None, _) => panic!("Index must have a fixed size"),
59    };
60}
61
62impl<I: Key, V: Value> FromDatabaseBytes for IndexedValue<I, V> {
63    fn from_key_bytes(bytes: &[u8]) -> Self
64    where
65        Self: Sized,
66    {
67        let index_size = I::FIXED_SIZE.expect("Index must have a fixed size");
68        IndexedValue {
69            index: I::from_value_bytes(&bytes[..index_size]),
70            value: V::from_value_bytes(&bytes[index_size..]),
71        }
72    }
73}