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}
48
49pub use thiserror::Error as ThisError;
50
51use crate::cdk::{
52    call::{CallFailed, CandidDecodeFailed, Error as CallError},
53    candid::{CandidType, Error as CandidError},
54};
55use serde::Deserialize;
56
57///
58/// Crate Version
59///
60
61pub const CRATE_NAME: &str = env!("CARGO_PKG_NAME");
62pub const VERSION: &str = env!("CARGO_PKG_VERSION");
63
64///
65/// Error
66///
67/// top level error should handle all sub-errors, but not expose the child candid types
68///
69
70#[derive(CandidType, Debug, Deserialize, ThisError)]
71pub enum Error {
72    #[error("{0}")]
73    AccessError(String),
74
75    #[error("{0}")]
76    ConfigError(String),
77
78    #[error("{0}")]
79    CustomError(String),
80
81    #[error("{0}")]
82    ModelError(String),
83
84    #[error("{0}")]
85    OpsError(String),
86
87    #[error("{0}")]
88    SerializeError(String),
89
90    #[error("http request failed: {0}")]
91    HttpRequest(String),
92
93    #[error("http error status: {0}")]
94    HttpErrorCode(u32),
95
96    #[error("http decode failed: {0}")]
97    HttpDecode(String),
98
99    ///
100    /// Test Error
101    /// as we don't want to import dev-dependencies
102    ///
103
104    #[error("{0}")]
105    TestError(String),
106
107    ///
108    /// Common IC errors
109    ///
110    /// CallError          : should be automatic with ?
111    /// CallFailed         : use this for wrapping <T, String> return values
112    /// CandidError        : for decode_one errors etc.  automatic
113    /// CandidDecodeFailed : automatic for calls like ::candid<T>()
114    ///
115
116    #[error("call error: {0}")]
117    CallError(String),
118
119    #[error("call failed: {0}")]
120    CallFailed(String),
121
122    #[error("candid error: {0}")]
123    CandidError(String),
124
125    #[error("candid decode failed: {0}")]
126    CandidDecodeFailed(String),
127}
128
129macro_rules! from_to_string {
130    ($from:ty, $variant:ident) => {
131        impl From<$from> for Error {
132            fn from(e: $from) -> Self {
133                Error::$variant(e.to_string())
134            }
135        }
136    };
137}
138
139impl Error {
140    /// Build a custom error from a string without defining a new variant.
141    #[must_use]
142    pub fn custom<S: Into<String>>(s: S) -> Self {
143        Self::CustomError(s.into())
144    }
145
146    /// Build a test error to avoid extra dev-only dependencies.
147    #[must_use]
148    pub fn test<S: Into<String>>(s: S) -> Self {
149        Self::TestError(s.into())
150    }
151}
152
153from_to_string!(access::AccessError, AccessError);
154from_to_string!(config::ConfigError, ConfigError);
155from_to_string!(model::ModelError, ModelError);
156from_to_string!(ops::OpsError, OpsError);
157from_to_string!(serde_json::Error, HttpDecode);
158
159from_to_string!(CallError, CallError);
160from_to_string!(CallFailed, CallFailed);
161from_to_string!(CandidDecodeFailed, CandidDecodeFailed);
162from_to_string!(CandidError, CandidError);