fil_actors_shared/v9/util/
multimap.rs

1// Copyright 2019-2022 ChainSafe Systems
2// SPDX-License-Identifier: Apache-2.0, MIT
3
4use cid::Cid;
5use fvm_ipld_blockstore::Blockstore;
6use fvm_ipld_hamt::Error;
7use serde::Serialize;
8use serde::de::DeserializeOwned;
9
10use crate::v9::{Array, BytesKey, Map, make_empty_map, make_map_with_root_and_bitwidth};
11
12/// `Multimap` stores multiple values per key in a HAMT of `Amt`s.
13/// The order of insertion of values for each key is retained.
14pub struct Multimap<'a, BS>(Map<'a, BS, Cid>, u32);
15impl<'a, BS> Multimap<'a, BS>
16where
17    BS: Blockstore,
18{
19    /// Initializes a new empty `Multimap`.
20    /// The `outer_bitwidth` is the width of the HAMT and the
21    /// `inner_bitwidth` is the width of the `AMT`s inside of it.
22    pub fn new(bs: &'a BS, outer_bitwidth: u32, inner_bitwidth: u32) -> Self {
23        Self(make_empty_map(bs, outer_bitwidth), inner_bitwidth)
24    }
25
26    /// Initializes a `Multimap` from a root Cid
27    pub fn from_root(
28        bs: &'a BS,
29        cid: &Cid,
30        outer_bitwidth: u32,
31        inner_bitwidth: u32,
32    ) -> Result<Self, Error> {
33        Ok(Self(
34            make_map_with_root_and_bitwidth(cid, bs, outer_bitwidth)?,
35            inner_bitwidth,
36        ))
37    }
38
39    /// Retrieve root from the `Multimap`.
40    #[inline]
41    pub fn root(&mut self) -> Result<Cid, Error> {
42        self.0.flush()
43    }
44
45    /// Adds a value for a key.
46    pub fn add<V>(&mut self, key: BytesKey, value: V) -> Result<(), Error>
47    where
48        V: Serialize + DeserializeOwned,
49    {
50        // Get construct amt from retrieved cid or create new
51        let mut arr = self
52            .get::<V>(&key)?
53            .unwrap_or_else(|| Array::new_with_bit_width(self.0.store(), self.1));
54
55        // Set value at next index
56        arr.set(arr.count(), value)
57            .map_err(|e| anyhow::anyhow!(e))?;
58
59        // flush to get new array root to put in HAMT
60        let new_root = arr.flush().map_err(|e| anyhow::anyhow!(e))?;
61
62        // Set HAMT node to array root
63        self.0.set(key, new_root)?;
64        Ok(())
65    }
66
67    /// Gets the Array of value type `V` using the `Multimap` store.
68    #[inline]
69    pub fn get<V>(&self, key: &[u8]) -> Result<Option<Array<'a, V, BS>>, Error>
70    where
71        V: DeserializeOwned + Serialize,
72    {
73        match self.0.get(key)? {
74            Some(cid) => Ok(Some(
75                Array::load(cid, *self.0.store()).map_err(|e| anyhow::anyhow!(e))?,
76            )),
77            None => Ok(None),
78        }
79    }
80
81    /// Removes all values for a key.
82    #[inline]
83    pub fn remove_all(&mut self, key: &[u8]) -> Result<(), Error> {
84        // Remove entry from table
85        self.0
86            .delete(key)?
87            .ok_or("failed to delete from multimap")?;
88
89        Ok(())
90    }
91
92    /// Iterates through all values in the array at a given key.
93    pub fn for_each<F, V>(&self, key: &[u8], f: F) -> Result<(), Error>
94    where
95        V: Serialize + DeserializeOwned,
96        F: FnMut(u64, &V) -> anyhow::Result<()>,
97    {
98        if let Some(amt) = self.get::<V>(key)? {
99            amt.for_each(f).map_err(|e| anyhow::anyhow!(e))?;
100        }
101
102        Ok(())
103    }
104
105    /// Iterates through all arrays in the multi-map
106    pub fn for_all<F, V>(&self, mut f: F) -> Result<(), Error>
107    where
108        V: Serialize + DeserializeOwned,
109        F: FnMut(&BytesKey, &Array<V, BS>) -> anyhow::Result<()>,
110    {
111        self.0.for_each::<_>(|key, arr_root| {
112            let arr = Array::load(arr_root, *self.0.store())?;
113            f(key, &arr)
114        })?;
115
116        Ok(())
117    }
118}