#![deny(clippy::arithmetic_side_effects)]
#![deny(clippy::cast_possible_truncation)]
#![deny(unused_crate_dependencies)]
#![deny(missing_docs)]
#![deny(warnings)]
use anyhow::anyhow;
use core::array::TryFromSliceError;
use fuel_core_types::services::executor::Error as ExecutorError;
pub use fuel_vm_private::{
fuel_storage::*,
storage::{
ContractsAssetsStorage,
InterpreterStorage,
},
};
pub mod blueprint;
pub mod codec;
pub mod column;
pub mod iter;
pub mod kv_store;
pub mod structured_storage;
pub mod tables;
#[cfg(feature = "test-helpers")]
pub mod test_helpers;
pub mod transactional;
pub mod vm_storage;
use fuel_core_types::fuel_merkle::binary::MerkleTreeError;
pub use fuel_vm_private::storage::{
ContractsAssetKey,
ContractsStateData,
ContractsStateKey,
};
#[doc(hidden)]
pub use paste;
#[cfg(feature = "test-helpers")]
#[doc(hidden)]
pub use rand;
pub type Result<T> = core::result::Result<T, Error>;
#[derive(Debug, derive_more::Display, derive_more::From)]
#[non_exhaustive]
pub enum Error {
#[display(fmt = "error performing serialization or deserialization `{_0}`")]
Codec(anyhow::Error),
#[display(fmt = "error occurred in the underlying datastore `{_0:?}`")]
DatabaseError(Box<dyn core::fmt::Debug + Send + Sync>),
#[display(fmt = "resource of type `{_0}` was not found at the: {_1}")]
NotFound(&'static str, &'static str),
#[from]
Other(anyhow::Error),
}
impl From<Error> for anyhow::Error {
fn from(error: Error) -> Self {
anyhow::Error::msg(error)
}
}
impl From<TryFromSliceError> for Error {
fn from(e: TryFromSliceError) -> Self {
Self::Other(anyhow::anyhow!(e))
}
}
impl From<Error> for ExecutorError {
fn from(e: Error) -> Self {
ExecutorError::StorageError(e.to_string())
}
}
impl From<Error> for fuel_vm_private::prelude::InterpreterError<Error> {
fn from(e: Error) -> Self {
fuel_vm_private::prelude::InterpreterError::Storage(e)
}
}
impl From<Error> for fuel_vm_private::prelude::RuntimeError<Error> {
fn from(e: Error) -> Self {
fuel_vm_private::prelude::RuntimeError::Storage(e)
}
}
impl From<MerkleTreeError<Error>> for Error {
fn from(e: MerkleTreeError<Error>) -> Self {
match e {
MerkleTreeError::StorageError(s) => s,
e => Error::Other(anyhow!(e)),
}
}
}
pub trait IsNotFound {
fn is_not_found(&self) -> bool;
}
impl IsNotFound for Error {
fn is_not_found(&self) -> bool {
matches!(self, Error::NotFound(_, _))
}
}
impl<T> IsNotFound for Result<T> {
fn is_not_found(&self) -> bool {
match self {
Err(err) => err.is_not_found(),
_ => false,
}
}
}
#[impl_tools::autoimpl(for<T: trait> &mut T)]
pub trait StorageBatchMutate<Type: Mappable>: StorageMutate<Type> {
fn init_storage<'a, Iter>(&mut self, set: Iter) -> Result<()>
where
Iter: 'a + Iterator<Item = (&'a Type::Key, &'a Type::Value)>,
Type::Key: 'a,
Type::Value: 'a;
fn insert_batch<'a, Iter>(&mut self, set: Iter) -> Result<()>
where
Iter: 'a + Iterator<Item = (&'a Type::Key, &'a Type::Value)>,
Type::Key: 'a,
Type::Value: 'a;
fn remove_batch<'a, Iter>(&mut self, set: Iter) -> Result<()>
where
Iter: 'a + Iterator<Item = &'a Type::Key>,
Type::Key: 'a;
}
#[macro_export]
macro_rules! not_found {
($name: literal) => {
$crate::Error::NotFound($name, concat!(file!(), ":", line!()))
};
($ty: path) => {
$crate::Error::NotFound(
::core::any::type_name::<<$ty as $crate::Mappable>::OwnedValue>(),
concat!(file!(), ":", line!()),
)
};
}
#[cfg(test)]
mod test {
use crate::tables::Coins;
#[test]
fn not_found_output() {
#[rustfmt::skip]
assert_eq!(
format!("{}", not_found!("BlockId")),
format!("resource of type `BlockId` was not found at the: {}:{}", file!(), line!() - 1)
);
#[rustfmt::skip]
assert_eq!(
format!("{}", not_found!(Coins)),
format!("resource of type `fuel_core_types::entities::coins::coin::CompressedCoin` was not found at the: {}:{}", file!(), line!() - 1)
);
}
}