1use serde::{Deserialize, Serialize};
2use thiserror::Error;
3
4#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
6#[serde(rename_all = "snake_case")]
7pub enum ContextErrorCode {
8 InvalidValue,
10 BoundsExceeded,
12 DuplicateIdentity,
14 AmbiguousConflict,
16 BudgetExceeded,
18 ProviderFailure,
20}
21
22#[derive(Debug, Clone, PartialEq, Eq, Error)]
24#[error("{code:?}: {message}")]
25pub struct ContextError {
26 code: ContextErrorCode,
27 message: String,
28}
29
30impl ContextError {
31 #[must_use]
33 pub fn new(code: ContextErrorCode, message: impl Into<String>) -> Self {
34 let mut message = message.into();
35 if message.is_empty() {
36 "context operation failed".clone_into(&mut message);
37 }
38 message.retain(|character| character != '\0');
39 if message.len() > 4096 {
40 let boundary = message
41 .char_indices()
42 .map(|(index, _)| index)
43 .take_while(|index| *index <= 4096)
44 .last()
45 .unwrap_or(0);
46 message.truncate(boundary);
47 }
48 Self { code, message }
49 }
50
51 #[must_use]
53 pub const fn code(&self) -> ContextErrorCode {
54 self.code
55 }
56
57 #[must_use]
59 pub fn message(&self) -> &str {
60 &self.message
61 }
62}