ic_dbms_api/memory/
error.rs

1use std::array::TryFromSliceError;
2
3use candid::CandidType;
4use serde::{Deserialize, Serialize};
5use thiserror::Error;
6
7use crate::memory::{Page, PageOffset};
8
9/// An enum representing possible memory-related errors.
10#[derive(Debug, Error, CandidType, Deserialize, Serialize)]
11pub enum MemoryError {
12    /// Error when the data to be written is too large for the page.
13    #[error("Data too large for page (page size: {page_size}, requested: {requested})")]
14    DataTooLarge { page_size: u64, requested: u64 },
15    /// Error when failing to decode data from bytes.
16    #[error("Failed to decode data from bytes: {0}")]
17    DecodeError(DecodeError),
18    /// Error when failing to allocate a new page.
19    #[error("Failed to allocate a new page")]
20    FailedToAllocatePage,
21    #[error("Offset {offset} is not aligned to {alignment} bytes")]
22    OffsetNotAligned { offset: PageOffset, alignment: u16 },
23    /// Error when attempting to access stable memory out of bounds.
24    #[error("Stable memory access out of bounds")]
25    OutOfBounds,
26    /// Error when attempting to write out of the allocated page.
27    #[error(
28        "Tried to read or write out of the allocated page (page: {page}, offset: {offset}, data size: {data_size}, page size: {page_size})"
29    )]
30    SegmentationFault {
31        page: Page,
32        offset: PageOffset,
33        data_size: u64,
34        page_size: u64,
35    },
36    /// Error when failing to grow stable memory.
37    #[error("Failed to grow stable memory: {0}")]
38    StableMemoryError(String),
39}
40
41impl From<ic_cdk::stable::StableMemoryError> for MemoryError {
42    fn from(err: ic_cdk::stable::StableMemoryError) -> Self {
43        MemoryError::StableMemoryError(err.to_string())
44    }
45}
46
47impl From<TryFromSliceError> for MemoryError {
48    fn from(err: TryFromSliceError) -> Self {
49        MemoryError::DecodeError(DecodeError::from(err))
50    }
51}
52
53impl From<std::string::FromUtf8Error> for MemoryError {
54    fn from(err: std::string::FromUtf8Error) -> Self {
55        MemoryError::DecodeError(DecodeError::from(err))
56    }
57}
58
59impl From<candid::types::principal::PrincipalError> for MemoryError {
60    fn from(err: candid::types::principal::PrincipalError) -> Self {
61        MemoryError::DecodeError(DecodeError::from(err))
62    }
63}
64
65impl From<uuid::Error> for MemoryError {
66    fn from(err: uuid::Error) -> Self {
67        MemoryError::DecodeError(DecodeError::from(err))
68    }
69}
70
71/// An enum representing possible decoding errors.
72#[derive(Debug, Error, CandidType, Deserialize, Serialize)]
73pub enum DecodeError {
74    /// Error when the raw record header is invalid.
75    #[error("Bad raw record header")]
76    BadRawRecordHeader,
77    /// Principal error
78    #[error("Principal error: {0}")]
79    PrincipalError(String),
80    /// Error when failing to convert from slice.
81    #[error("Failed to convert from slice: {0}")]
82    TryFromSliceError(String),
83    /// Error when failing to convert from UTF-8 string.
84    #[error("Failed to convert from UTF-8 string: {0}")]
85    Utf8Error(String),
86    /// Error when the data is too short to decode.
87    #[error("Data too short to decode")]
88    TooShort,
89    /// UUID error
90    #[error("UUID error: {0}")]
91    UuidError(String),
92}
93
94impl From<uuid::Error> for DecodeError {
95    fn from(err: uuid::Error) -> Self {
96        DecodeError::UuidError(err.to_string())
97    }
98}
99
100impl From<std::string::FromUtf8Error> for DecodeError {
101    fn from(err: std::string::FromUtf8Error) -> Self {
102        DecodeError::Utf8Error(err.to_string())
103    }
104}
105
106impl From<TryFromSliceError> for DecodeError {
107    fn from(err: TryFromSliceError) -> Self {
108        DecodeError::TryFromSliceError(err.to_string())
109    }
110}
111
112impl From<candid::types::principal::PrincipalError> for DecodeError {
113    fn from(err: candid::types::principal::PrincipalError) -> Self {
114        DecodeError::PrincipalError(err.to_string())
115    }
116}
117
118#[cfg(test)]
119mod tests {
120
121    use super::*;
122
123    #[test]
124    fn test_memory_error_display() {
125        let error = MemoryError::DataTooLarge {
126            page_size: 1024,
127            requested: 2048,
128        };
129        assert_eq!(
130            format!("{}", error),
131            "Data too large for page (page size: 1024, requested: 2048)"
132        );
133    }
134
135    #[test]
136    fn test_decode_error_display() {
137        let error = DecodeError::BadRawRecordHeader;
138        assert_eq!(format!("{}", error), "Bad raw record header");
139    }
140}