Skip to main content

wasm_dbms_api/memory/
error.rs

1use std::array::TryFromSliceError;
2
3use serde::{Deserialize, Serialize};
4use thiserror::Error;
5
6use crate::memory::{Page, PageOffset};
7
8/// An enum representing possible memory-related errors.
9#[cfg_attr(feature = "candid", derive(candid::CandidType))]
10#[derive(Debug, Error, Deserialize, Serialize)]
11pub enum MemoryError {
12    /// Error when an autoincrement column has reached its maximum value.
13    #[error("Autoincrement overflow: {0} column has reached its maximum value")]
14    AutoincrementOverflow(String),
15    /// Error when a constraint prevents the requested operation.
16    #[error("Constraint violation: {0}")]
17    ConstraintViolation(String),
18    /// Error when the data to be written is too large for the page.
19    #[error("Data too large for page (page size: {page_size}, requested: {requested})")]
20    DataTooLarge { page_size: u64, requested: u64 },
21    /// Error when failing to decode data from bytes.
22    #[error("Failed to decode data from bytes: {0}")]
23    DecodeError(DecodeError),
24    /// Error when failing to allocate a new page.
25    #[error("Failed to allocate a new page")]
26    FailedToAllocatePage,
27    /// Error when the unclaimed-pages ledger has no room for another entry.
28    #[error("Unclaimed pages ledger is full ({capacity} entries)")]
29    UnclaimedPagesFull {
30        /// Maximum number of pages the ledger can hold.
31        capacity: u32,
32    },
33    /// Error when no index exists for the requested columns.
34    #[error("Index not found for columns: {0:?}")]
35    IndexNotFound(Vec<String>),
36    /// Error when registering a table whose name hash collides with an
37    /// already-registered table of a different name.
38    #[error(
39        "Name hash collision: table `{candidate}` hashes to the same value as already-registered table `{existing}`"
40    )]
41    NameCollision {
42        /// Name of the table being registered.
43        candidate: String,
44        /// Name of the already-registered table that produced the same hash.
45        existing: String,
46    },
47    /// Error when an index entry cannot be located.
48    #[error("Entry not found in index")]
49    EntryNotFound,
50    /// Error when a single key cannot fit into a node page.
51    #[error("Key too large: {size} bytes exceeds maximum {max} bytes")]
52    KeyTooLarge { size: u64, max: u64 },
53    #[error("Offset {offset} is not aligned to {alignment} bytes")]
54    OffsetNotAligned { offset: PageOffset, alignment: u16 },
55    /// Error when attempting to access stable memory out of bounds.
56    #[error("Stable memory access out of bounds")]
57    OutOfBounds,
58    /// Error when attempting to write out of the allocated page.
59    #[error(
60        "Tried to read or write out of the allocated page (page: {page}, offset: {offset}, data size: {data_size}, page size: {page_size})"
61    )]
62    SegmentationFault {
63        page: Page,
64        offset: PageOffset,
65        data_size: u64,
66        page_size: u64,
67    },
68    /// Error from the underlying memory provider.
69    #[error("Memory provider error: {0}")]
70    ProviderError(String),
71}
72
73impl From<TryFromSliceError> for MemoryError {
74    fn from(err: TryFromSliceError) -> Self {
75        MemoryError::DecodeError(DecodeError::from(err))
76    }
77}
78
79impl From<std::string::FromUtf8Error> for MemoryError {
80    fn from(err: std::string::FromUtf8Error) -> Self {
81        MemoryError::DecodeError(DecodeError::from(err))
82    }
83}
84
85impl From<uuid::Error> for MemoryError {
86    fn from(err: uuid::Error) -> Self {
87        MemoryError::DecodeError(DecodeError::from(err))
88    }
89}
90
91/// An enum representing possible decoding errors.
92#[cfg_attr(feature = "candid", derive(candid::CandidType))]
93#[derive(Debug, Error, Deserialize, Serialize)]
94pub enum DecodeError {
95    /// Error when the raw record header is invalid.
96    #[error("Bad raw record header")]
97    BadRawRecordHeader,
98    /// Error when JSON is invalid.
99    #[error("Invalid JSON: {0}")]
100    InvalidJson(String),
101    /// Identity decoding error.
102    #[error("Identity decode error: {0}")]
103    IdentityDecodeError(String),
104    /// Error when failing to convert from slice.
105    #[error("Failed to convert from slice: {0}")]
106    TryFromSliceError(String),
107    /// Error when failing to convert from UTF-8 string.
108    #[error("Failed to convert from UTF-8 string: {0}")]
109    Utf8Error(String),
110    /// Error when the data is too short to decode.
111    #[error("Data too short to decode")]
112    TooShort,
113    /// Error when an invalid discriminant byte is encountered.
114    #[error("Invalid discriminant: {0}")]
115    InvalidDiscriminant(u8),
116    /// UUID error
117    #[error("UUID error: {0}")]
118    UuidError(String),
119}
120
121impl From<uuid::Error> for DecodeError {
122    fn from(err: uuid::Error) -> Self {
123        DecodeError::UuidError(err.to_string())
124    }
125}
126
127impl From<std::string::FromUtf8Error> for DecodeError {
128    fn from(err: std::string::FromUtf8Error) -> Self {
129        DecodeError::Utf8Error(err.to_string())
130    }
131}
132
133impl From<TryFromSliceError> for DecodeError {
134    fn from(err: TryFromSliceError) -> Self {
135        DecodeError::TryFromSliceError(err.to_string())
136    }
137}
138
139#[cfg(feature = "candid")]
140impl From<candid::types::principal::PrincipalError> for DecodeError {
141    fn from(err: candid::types::principal::PrincipalError) -> Self {
142        DecodeError::IdentityDecodeError(err.to_string())
143    }
144}
145
146#[cfg(test)]
147mod tests {
148
149    use super::*;
150
151    #[test]
152    fn test_memory_error_display() {
153        let error = MemoryError::DataTooLarge {
154            page_size: 1024,
155            requested: 2048,
156        };
157        assert_eq!(
158            format!("{}", error),
159            "Data too large for page (page size: 1024, requested: 2048)"
160        );
161    }
162
163    #[test]
164    fn test_decode_error_display() {
165        let error = DecodeError::BadRawRecordHeader;
166        assert_eq!(format!("{}", error), "Bad raw record header");
167    }
168}