gear_common/
code_storage.rs

1// This file is part of Gear.
2
3// Copyright (C) 2022-2025 Gear Technologies Inc.
4// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0
5
6// This program is free software: you can redistribute it and/or modify
7// it under the terms of the GNU General Public License as published by
8// the Free Software Foundation, either version 3 of the License, or
9// (at your option) any later version.
10
11// This program is distributed in the hope that it will be useful,
12// but WITHOUT ANY WARRANTY; without even the implied warranty of
13// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14// GNU General Public License for more details.
15
16// You should have received a copy of the GNU General Public License
17// along with this program. If not, see <https://www.gnu.org/licenses/>.
18
19use super::*;
20use crate::storage::MapStorage;
21use gear_core::code::{CodeAndId, CodeMetadata, InstrumentedCode, InstrumentedCodeAndMetadata};
22
23#[derive(Clone, Copy, Debug)]
24pub enum Error {
25    /// Code already exists in storage.
26    DuplicateItem,
27}
28
29/// Trait to work with program binary codes in a storage.
30pub trait CodeStorage {
31    type InstrumentedCodeMap: MapStorage<Key = CodeId, Value = InstrumentedCode>;
32    type OriginalCodeMap: MapStorage<Key = CodeId, Value = Vec<u8>>;
33    type CodeMetadataMap: MapStorage<Key = CodeId, Value = CodeMetadata>;
34
35    /// Attempt to remove all items from all the associated maps.
36    fn reset() {
37        Self::CodeMetadataMap::clear();
38        Self::OriginalCodeMap::clear();
39        Self::InstrumentedCodeMap::clear();
40    }
41
42    /// Add the code to the storage.
43    fn add_code(code_and_id: CodeAndId) -> Result<(), Error> {
44        let (code, code_id) = code_and_id.into_parts();
45        let (original_code, instrumented_code, code_metadata) = code.into_parts();
46
47        Self::OriginalCodeMap::mutate(code_id, |maybe| {
48            if maybe.is_some() {
49                return Err(CodeStorageError::DuplicateItem);
50            }
51
52            Self::InstrumentedCodeMap::insert(code_id, instrumented_code);
53            Self::CodeMetadataMap::insert(code_id, code_metadata);
54
55            *maybe = Some(original_code);
56            Ok(())
57        })
58    }
59
60    /// Update the corresponding code and metadata in the storage.
61    fn update_instrumented_code_and_metadata(
62        code_id: CodeId,
63        instrumented_code_and_metadata: InstrumentedCodeAndMetadata,
64    ) {
65        Self::InstrumentedCodeMap::insert(
66            code_id,
67            instrumented_code_and_metadata.instrumented_code,
68        );
69        Self::CodeMetadataMap::insert(code_id, instrumented_code_and_metadata.metadata);
70    }
71
72    /// Update the corresponding metadata in the storage.
73    fn update_code_metadata(code_id: CodeId, metadata: CodeMetadata) {
74        Self::CodeMetadataMap::insert(code_id, metadata);
75    }
76
77    /// Returns true if the original code associated with given id exists.
78    fn original_code_exists(code_id: CodeId) -> bool {
79        Self::OriginalCodeMap::contains_key(&code_id)
80    }
81
82    /// Returns true if the instrumented code associated with given id exists.
83    fn instrumented_code_exists(code_id: CodeId) -> bool {
84        Self::InstrumentedCodeMap::contains_key(&code_id)
85    }
86
87    /// Returns true if the code associated with given id was removed.
88    ///
89    /// If there is no code for the given id then false is returned.
90    fn remove_code(code_id: CodeId) -> bool {
91        Self::OriginalCodeMap::mutate(code_id, |maybe| {
92            if maybe.is_none() {
93                return false;
94            }
95
96            Self::InstrumentedCodeMap::remove(code_id);
97            Self::CodeMetadataMap::remove(code_id);
98
99            *maybe = None;
100            true
101        })
102    }
103
104    fn get_instrumented_code(code_id: CodeId) -> Option<InstrumentedCode> {
105        Self::InstrumentedCodeMap::get(&code_id)
106    }
107
108    fn get_original_code(code_id: CodeId) -> Option<Vec<u8>> {
109        Self::OriginalCodeMap::get(&code_id)
110    }
111
112    fn get_code_metadata(code_id: CodeId) -> Option<CodeMetadata> {
113        Self::CodeMetadataMap::get(&code_id)
114    }
115}