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