canic_core/
lib.rs

1//! Core Canic library used inside canisters.
2//!
3//! Most users should depend on the `canic` facade crate, which re-exports this crate
4//! under `canic::core` and exposes the common entrypoint macros:
5//! - `canic::build!` / `canic::build_root!` (in `build.rs`) to validate/embed `canic.toml`
6//! - `canic::start!` / `canic::start_root!` (in `lib.rs`) to wire lifecycle hooks and export endpoints
7//!
8//! ## Layering
9//!
10//! Canic is organized to keep endpoint code thin and policies centralized:
11//! - `access/` contains guard/auth/policy helpers for boundary enforcement.
12//! - `model/` owns storage (stable memory) and in-process registries/caches.
13//! - `ops/` implements workflows (provisioning, scaling, sharding, pool management).
14//! - `macros/` provides public macro entrypoints and endpoint bundles.
15//!
16//! The default flow is: endpoints → ops → model.
17pub mod access;
18
19// -----------------------------------------------------------------------------
20// Phase 0: path coherence re-exports (no behavior change)
21// -----------------------------------------------------------------------------
22
23pub use access::{auth, guard, policy};
24pub mod config;
25pub mod dispatch;
26pub mod dto;
27pub mod env;
28pub mod ids;
29pub mod log;
30pub mod macros;
31pub(crate) mod model;
32pub mod ops;
33pub mod perf;
34pub mod spec;
35
36pub use ::canic_cdk as cdk;
37pub use ::canic_memory as memory;
38pub use ::canic_memory::{eager_init, eager_static, ic_memory, ic_memory_range};
39pub use ::canic_types as types;
40pub use ::canic_utils as utils;
41
42/// Internal re-exports required for macro expansion.
43/// Not part of the public API.
44#[doc(hidden)]
45pub mod __reexports {
46    pub use ::ctor;
47    pub use ::defer;
48}
49
50pub use thiserror::Error as ThisError;
51
52use crate::cdk::{
53    call::{CallFailed, CandidDecodeFailed, Error as CallError},
54    candid::{CandidType, Error as CandidError},
55};
56use serde::Deserialize;
57
58///
59/// Crate Version
60///
61
62pub const CRATE_NAME: &str = env!("CARGO_PKG_NAME");
63pub const VERSION: &str = env!("CARGO_PKG_VERSION");
64
65///
66/// Error
67///
68/// top level error should handle all sub-errors, but not expose the child candid types
69///
70
71#[derive(CandidType, Debug, Deserialize, ThisError)]
72pub enum Error {
73    #[error("{0}")]
74    AccessError(String),
75
76    #[error("{0}")]
77    ConfigError(String),
78
79    #[error("{0}")]
80    CustomError(String),
81
82    #[error("{0}")]
83    ModelError(String),
84
85    #[error("{0}")]
86    OpsError(String),
87
88    #[error("{0}")]
89    SerializeError(String),
90
91    #[error("http request failed: {0}")]
92    HttpRequest(String),
93
94    #[error("http error status: {0}")]
95    HttpErrorCode(u32),
96
97    #[error("http decode failed: {0}")]
98    HttpDecode(String),
99
100    ///
101    /// Test Error
102    /// as we don't want to import dev-dependencies
103    ///
104
105    #[error("{0}")]
106    TestError(String),
107
108    ///
109    /// Common IC errors
110    ///
111    /// CallError          : should be automatic with ?
112    /// CallFailed         : use this for wrapping <T, String> return values
113    /// CandidError        : for decode_one errors etc.  automatic
114    /// CandidDecodeFailed : automatic for calls like ::candid<T>()
115    ///
116
117    #[error("call error: {0}")]
118    CallError(String),
119
120    #[error("call failed: {0}")]
121    CallFailed(String),
122
123    #[error("candid error: {0}")]
124    CandidError(String),
125
126    #[error("candid decode failed: {0}")]
127    CandidDecodeFailed(String),
128}
129
130macro_rules! from_to_string {
131    ($from:ty, $variant:ident) => {
132        impl From<$from> for Error {
133            fn from(e: $from) -> Self {
134                Error::$variant(e.to_string())
135            }
136        }
137    };
138}
139
140impl Error {
141    /// Build a custom error from a string without defining a new variant.
142    #[must_use]
143    pub fn custom<S: Into<String>>(s: S) -> Self {
144        Self::CustomError(s.into())
145    }
146
147    /// Build a test error to avoid extra dev-only dependencies.
148    #[must_use]
149    pub fn test<S: Into<String>>(s: S) -> Self {
150        Self::TestError(s.into())
151    }
152}
153
154from_to_string!(access::AccessError, AccessError);
155from_to_string!(config::ConfigError, ConfigError);
156from_to_string!(model::ModelError, ModelError);
157from_to_string!(ops::OpsError, OpsError);
158from_to_string!(serde_json::Error, HttpDecode);
159
160from_to_string!(CallError, CallError);
161from_to_string!(CallFailed, CallFailed);
162from_to_string!(CandidDecodeFailed, CandidDecodeFailed);
163from_to_string!(CandidError, CandidError);