canic_core/
lib.rs

1//! CANIC crate utilities for multi-canister apps on the Internet Computer.
2pub mod access;
3
4// -----------------------------------------------------------------------------
5// Phase 0: path coherence re-exports (no behavior change)
6// -----------------------------------------------------------------------------
7
8pub use access::{auth, guard, policy};
9pub mod config;
10pub mod dispatch;
11pub mod dto;
12pub mod env;
13pub mod ids;
14pub mod log;
15pub mod macros;
16pub(crate) mod model;
17pub mod ops;
18pub mod perf;
19pub mod spec;
20
21pub use ::canic_cdk as cdk;
22pub use ::canic_memory as memory;
23pub use ::canic_memory::{eager_init, eager_static, ic_memory, ic_memory_range};
24pub use ::canic_types as types;
25pub use ::canic_utils as utils;
26
27/// Internal re-exports required for macro expansion.
28/// Not part of the public API.
29#[doc(hidden)]
30pub mod __reexports {
31    pub use ::ctor;
32    pub use ::defer;
33}
34
35pub use thiserror::Error as ThisError;
36
37use crate::cdk::{
38    call::{CallFailed, CandidDecodeFailed, Error as CallError},
39    candid::{CandidType, Error as CandidError},
40};
41use serde::Deserialize;
42
43///
44/// Crate Version
45///
46
47pub const CRATE_NAME: &str = env!("CARGO_PKG_NAME");
48pub const VERSION: &str = env!("CARGO_PKG_VERSION");
49
50///
51/// Error
52///
53/// top level error should handle all sub-errors, but not expose the child candid types
54///
55
56#[derive(CandidType, Debug, Deserialize, ThisError)]
57pub enum Error {
58    #[error("{0}")]
59    AccessError(String),
60
61    #[error("{0}")]
62    ConfigError(String),
63
64    #[error("{0}")]
65    CustomError(String),
66
67    #[error("{0}")]
68    ModelError(String),
69
70    #[error("{0}")]
71    OpsError(String),
72
73    #[error("{0}")]
74    SerializeError(String),
75
76    #[error("http request failed: {0}")]
77    HttpRequest(String),
78
79    #[error("http error status: {0}")]
80    HttpErrorCode(u32),
81
82    #[error("http decode failed: {0}")]
83    HttpDecode(String),
84
85    ///
86    /// Test Error
87    /// as we don't want to import dev-dependencies
88    ///
89
90    #[error("{0}")]
91    TestError(String),
92
93    ///
94    /// Common IC errors
95    ///
96    /// CallError          : should be automatic with ?
97    /// CallFailed         : use this for wrapping <T, String> return values
98    /// CandidError        : for decode_one errors etc.  automatic
99    /// CandidDecodeFailed : automatic for calls like ::candid<T>()
100    ///
101
102    #[error("call error: {0}")]
103    CallError(String),
104
105    #[error("call failed: {0}")]
106    CallFailed(String),
107
108    #[error("candid error: {0}")]
109    CandidError(String),
110
111    #[error("candid decode failed: {0}")]
112    CandidDecodeFailed(String),
113}
114
115macro_rules! from_to_string {
116    ($from:ty, $variant:ident) => {
117        impl From<$from> for Error {
118            fn from(e: $from) -> Self {
119                Error::$variant(e.to_string())
120            }
121        }
122    };
123}
124
125impl Error {
126    /// Build a custom error from a string without defining a new variant.
127    #[must_use]
128    pub fn custom<S: Into<String>>(s: S) -> Self {
129        Self::CustomError(s.into())
130    }
131
132    /// Build a test error to avoid extra dev-only dependencies.
133    #[must_use]
134    pub fn test<S: Into<String>>(s: S) -> Self {
135        Self::TestError(s.into())
136    }
137}
138
139from_to_string!(access::AccessError, AccessError);
140from_to_string!(config::ConfigError, ConfigError);
141from_to_string!(model::ModelError, ModelError);
142from_to_string!(ops::OpsError, OpsError);
143from_to_string!(serde_json::Error, HttpDecode);
144
145from_to_string!(CallError, CallError);
146from_to_string!(CallFailed, CallFailed);
147from_to_string!(CandidDecodeFailed, CandidDecodeFailed);
148from_to_string!(CandidError, CandidError);